Skip to main content
reskate.viewmodel draws one rigged, animated model in front of the camera, over the game’s finished frame. It is what a first-person mod uses for arms and something held. Every function needs the viewmodel permission. Calling one without it raises an error. The model is drawn on your screen only. Other players see nothing of it.
The viewmodel has its own lens and its own depth, so it looks the same whatever the game camera’s field of view, and the world never cuts into it. It is drawn before your plugin’s overlay, so draw handlers draw on top of it. It is never drawn over the game’s own menu.

The model file

A viewmodel is a .rsvm file in your plugin’s package, with its pictures beside it. The ReSkate repository makes one from any rigged, animated model Blender can open (FBX, glTF or .blend) with contrib/viewmodel_export.py:
It writes <name>.rsvm and three pictures for each material: <material>_albedo.png (colour), <material>_normal.png (tangent-space normals) and <material>_surface.png (red roughness, green ambient occlusion, blue specular). Every action in the file becomes a clip, named as in Blender. Ship the pictures in the same folder as the .rsvm. ReSkate refuses a model with more than 128 bones, a file or picture larger than 64 MB, and a picture that is not a PNG or JPG. It scales a picture larger than 2048 pixels down as it reads it. Positions in this API are in the view: x to the right, y up, z forward, in metres from the eye. The FPS plugin in the ReSkate repository (contrib/plugins/fps) draws a pistol and arms this way.

Loading

One plugin has the viewmodel at a time. The first load takes it; another plugin’s load is refused until the holder unloads or stops. A plugin’s viewmodel is unloaded when the plugin stops.

reskate.viewmodel.load(path)

Starts reading a .rsvm file, and the pictures it names, in the background. It replaces any viewmodel your plugin had. Check info (below) for when it is ready.
string
required
A .rsvm file in your package, at most 200 characters, such as "viewmodel/pistol.rsvm".
boolean
true when reading has started.
string
Why not: "<plugin> has the viewmodel", or "unavailable here" on a dedicated server.
It raises an error for a path that is not a .rsvm file (a viewmodel is a .rsvm file (contrib/viewmodel_export.py makes one)), or that is not a file in the package.
Needs the viewmodel permission.

reskate.viewmodel.unload()

Forgets your viewmodel. Nothing is drawn until one is loaded again, and another plugin may take the viewmodel. Returns nothing; it does nothing when your plugin has none.
Needs the viewmodel permission.

reskate.viewmodel.info()

What your viewmodel holds.
table or nil
nil when your plugin has no viewmodel loaded.
Needs the viewmodel permission.

Showing

reskate.viewmodel.show(look)

Draws the viewmodel for the next 300 ms, so call it every tick you want it shown. Until the file is ready nothing is drawn, but the call still succeeds.
table
Each field is optional; a field left out takes its default.
boolean
true when it is shown.
string
Why not: "this plugin has no viewmodel loaded" or "the game's menu is open".
A number or vector part outside its range raises an error that names the field and its range.
Needs the viewmodel permission.

reskate.viewmodel.hide()

Stops drawing the viewmodel now, rather than letting the last show run out. The model stays loaded.
boolean
true when hidden.
string
"this plugin has no viewmodel loaded".
Needs the viewmodel permission.

Animating

reskate.viewmodel.play(clip, options)

Plays a clip from its start, faded in over what was playing.
string
required
A clip’s name, as info().clips lists it, at most 120 characters.
table
boolean
true when it plays.
string
Why not: "this plugin has no viewmodel loaded", "the viewmodel is still loading", "no viewmodel is loaded" (it failed) or "the viewmodel has no clip \"<clip>\"".
A clip that does not loop stops on its last frame.
Needs the viewmodel permission.

reskate.viewmodel.stop()

Stops the clip. The model is drawn unanimated until the next play. Returns nothing.
Needs the viewmodel permission.

reskate.viewmodel.state()

The clip playing now.
table or nil
nil when nothing plays, or your plugin has no viewmodel ready.
Needs the viewmodel permission.

reskate.viewmodel.bone(name)

Where a bone of the model is now, in the view, with the last show’s placement applied. Use it to start a muzzle flash, a tracer or a shell from the right place.
string
required
A bone’s name, as info().bones lists it, at most 120 characters.
table or nil
nil when there is no such bone, or your plugin has no viewmodel ready.
Needs the viewmodel permission.