q0idmation // draw, rig, animate, export .q0s log inregister

animation and host api

home · libraries · recipes

A host is the program that runs q0lang and applies what it asks for. The runtime itself never opens files or draws the stage.

availability

capabilityeditor: code analysiseditor: previewq0player v2q0shell
math, functions, conditions, loopsyes, with a small budgetyesyesyes
general script and frame codeanalyses one textyesyesone input text
frame jumps and stopsreported onlyyesyesreports it is unavailable
named instances, keyboard, time.dtno host valuesno host valuesyesno host values
object scripts (self.*)analyses one textnoyesno
rig commandsreported onlynot appliedyesreports it is unavailable
live physics, particles and lightsreported onlynot appliedyesreports it is unavailable
switching bundled scenesreported onlynot appliedyesreports it is unavailable
file commandsreported onlynot appliedignoredyes
mouse subscription tableyesyesyesyes
mouse events delivered to handlersnonoyesno

Analysing a single script cannot reproduce the shared variables that dependencies and earlier frames will have set. Test interactive projects in q0player. Everything here applies to vector v2 movies; old bitmap v1 movies and q0v videos do not run q0lang.

start-up order

q0player first creates the shared runtime. The embedded q0lang dependencies of the root project graph run in ascending node id order, then the general script of the entry q0rg, then the code of the first frame. External q0lang dependencies do not run: the player reports that they need a bundled export. If the start-up script already jumped somewhere, the destination's code is not run a second time.

During normal playback, the code of every frame the playhead enters runs. Scripts of one frame run in ascending layer id order, then in stored order. Shared state and defined functions carry over. Frame code of nested q0rgs does not run in the root runtime; a placed symbol with code of its own runs in an object script.

The editor preview runs the general script of the open q0rg and its frame code. Moving the editor's playhead by hand is editing and runs no frame code; seek in the player does run the destination frame's code.

q0.timeline

import q0.timeline
start = 3
gorun! start

gorun! target starts playback and jumps to target. gostop! target stops playback and jumps to target. A jump runs the destination's code and skips the frames in between. The command does not end the current script: the whole script runs first, then the host applies the collected actions in order.

Frame indices in code start at zero. A non-negative numeric target becomes a u16: the fraction is dropped and values that are too large saturate at 65535. The host clamps it to the last frame. Use finite whole numbers within the timeline.

A string target first resolves a named frame label within the active timeline. A numeric string like "12" falls back to frame index 12 when there is no label with that name. An unknown label gives a diagnostic and keeps the current frame; the playback mode requested by the command still applies. There is no automatic frame or label variable in the root runtime; inside an object script, frame holds that object's own frame.

An unconditional jump from a frame to itself runs the same code again. The editor and the player stop a chain of jumps after 64 transitions. To stop on a frame without looping, use a flag variable, or put the command in the general script.

q0.input and q0.time

nametypevalue in q0player
input.leftboolA or the left arrow is held
input.rightboolD or the right arrow is held
input.jumpboolW, the up arrow or Space is held
input.jump_pressedbooljump went from released to pressed; cleared after the frame's scripts run
time.dtnumberthe fixed step in seconds, 1 / fps

import q0.input switches on a game clock that runs independently of the animation's pause button. While a frame is held, its code keeps running at the movie's fps, even in a one-frame project, so controls and movement keep updating with the timeline stopped. Without the import, a paused animation runs no new ticks. On touch screens q0player shows on-screen left, right and jump buttons.

The host refreshes these values before every script. Assigning input.left or time.dt changes neither the keyboard nor the clock, and the next refresh overwrites it. The api offers no other keys, no typed text, no timers and no system time.

q0.scene: size and instances

nameaccessvalue
stage.width, stage.heightreadthe stage size in stage units
name.x, name.yread and writemoves the named instance
name.left, name.right, name.top, name.bottomreadthe instance's bounds on the stage
name.width, name.heightreadthe width and height of those bounds
name.frame, name.playingread and writethe own timeline of a named instance that has an object script

Replace name with an instance name given in the project, such as player. The library creates no character by itself. The instance must belong to the current entry q0rg; an unknown name stays an ordinary symbolic identifier.

import q0.scene
player.x = player.x + 10

The example needs an instance called player in q0player. Writes to x/y apply after the script ends, as a temporary runtime transform; the project itself never changes. Both values must be finite numbers. Writing width, height or the bounds does not scale the instance: those are measured again.

Within one script, writing player.x does not update player.right; the geometry is measured between runs. Compute limits from the starting bounds plus your own offset, as in the movement recipe.

object scripts

Every placed copy of a symbol (q0rg) that has code of its own, a general script or frame code, gets its own runtime in q0player. Each copy keeps separate variables, its own timeline position and its own handlers, so ten coins can each count their own score. The object's name is its instance name, or Symbol#id when it has none.

  • The symbol's general script runs once when the copy appears on stage.
  • Its frame code runs whenever the copy's own frame changes. With q0.object, q0.input or q0.mouse imported, it runs every tick instead.
  • gorun! and gostop! inside an object script drive that copy's own timeline.
  • Mouse events reach the copy under the pointer, see events.
nameaccessvalue
self.x, self.yread and writeposition within the parent timeline; writing moves the copy
self.frame / framereadthe copy's current frame
self.playingread and writewhether the copy's timeline plays
self.name, self.idreadinstance name and instance id
self.left, self.right, self.top, self.bottom, self.width, self.heightreadthe copy's bounds
self.hoveredreadthe pointer is over the copy
self.mouse_x, self.mouse_yreadthe pointer in the copy's own coordinates

Named instances inside the symbol are reachable as name.x and so on, relative to the copy. q0player runs at most 4096 active objects, and each object run has its own budget of 100,000 instructions.

import q0.object
import q0.mouse

pb func on_click target {
  self.playing = not self.playing
}

listen mouse.click on_click

q0.scene: switching scenes

import q0.scene
q0scene.switch! "room_2"

The alias must match the alias of a bundled movie in the root project's graph. An unknown alias gives a diagnostic. This never loads an arbitrary path or opens an outside file.

The player replaces the current scene and starts at frame zero. It drops temporary moves, rig changes, live physics and particles, and refreshes the sound. The shared runtime keeps its variables, functions and imports. Then the new scene's general script and its first frame's code run. The q0lang dependencies of the child scene's graph do not run again, so keep shared logic in the root graph.

q0.rig

commanddoes
q0rig.position! control, x, ya temporary position for a control
q0rig.value! control, valuea temporary numeric value for a control
q0rig.reset! controlremoves that control's temporary position and value
q0rig.pose! pose, weightblends in a saved pose with a weight clamped to 0…1
q0rig.pose_reset! poseremoves that pose's temporary weight

Names are strings; position and value take numbers. The pose weight must be finite. The commands act on the entry q0rg's rig. A control must be open to the runtime through its "visible in simple" setting; a hidden or missing control gives a diagnostic. Poses are looked up by name and need no such setting.

import q0.rig
q0rig.position! "look", 40, 25
q0rig.value! "arm blend", 0.75
q0rig.pose! "wave", 0.6

This example assumes a project with those controls and that pose. The commands store temporary values; what they do depends on the rig's bindings. reset does not delete the authored control, and pose_reset does not delete the saved pose. Temporary settings survive frame jumps; switching scenes drops them.

q0.physics

The physics world of the main timeline, when "Live in q0player" is on in the physics editor. Without that switch, physics is only baked into keys and does not travel with the movie.

commanddoes
q0physics.start!runs the world from the current frame, or resumes it after a pause
q0physics.pause!holds the world; bodies stay where they are
q0physics.reset!removes the world and hands the bodies back to the timeline
q0physics.push! body, x, yadds to a body's velocity, in px/s
q0physics.velocity! body, x, ysets a body's velocity, in px/s
q0physics.spin! body, degreessets the spin, in degrees per second, clockwise
q0physics.teleport! body, x, yputs a body down at a stage point
q0physics.gravity! x, ynew gravity for the world, in px/s²; y points down
q0physics.cut! linkcuts a rope or chain in its middle, or undoes a spring, hinge or weld

A body is named by its instance name, set with the "Script name" field in the physics window; a link by the name it has in the window's Links list. The world steps once per movie frame, even with the timeline paused. Animated bodies keep following the timeline, bodies tied on with links swing and bounce along, and liquids, ropes, chains and springs are drawn over the stage. Any command other than start! also builds the world but does not start it. Switching scenes drops the world.

import q0.physics
q0physics.start!
q0physics.push! "ball", 300, -600
q0physics.cut! "rope1"

q0.particles

The emitters of the particle editor that have "Live" on. An emitter releases nothing until a command tells it to.

commanddoes
q0particles.start! emitterstarts emitting, beginning with the emitter's burst
q0particles.stop! emitterstops emitting; particles in flight live out their lives
q0particles.burst! emitter, countreleases count particles at once
q0particles.move! emitter, x, ymoves the emitter to a stage point
q0particles.clear! emitterstops it and removes all its particles

Particles are drawn over the stage. Glowing (additive) emitters add their light to what is behind them. Particles that are library items are drawn at full opacity during playback; the built-in shapes fade with their colour. An emitter that follows an object in the particle editor follows it in the player too, wherever the timeline, live physics or a script has put it.

import q0.particles
q0particles.move! "sparks", player.x, player.y
q0particles.burst! "sparks", 40

q0.light

The lights of the light editor. Lights need no switch to travel: every movie with lights is lit while it plays, and these commands change them on the fly. A light is named by the name given in the light editor.

commanddoes
q0light.on! lightswitches a light on
q0light.off! lightswitches a light off
q0light.move! light, x, yputs a light at a stage point; it stops following its object
q0light.color! light, red, green, bluea new colour, each channel 0 to 255
q0light.brightness! light, value1 shows colours as drawn, 2 doubles them, 0 is off
q0light.size! light, radiushow far it reaches, in pixels
q0light.darkness! valuehow dark unlit places are, 0 (day) to 1 (pitch dark)

Lights shine on the main timeline's layers up to its light layer; layers above it stay as drawn. A command that changes a light's position, colour, brightness or size takes it over from its keyframes for the rest of the scene. Switching scenes drops every change.

import q0.light
import q0.mouse

pb func lights_out target {
  q0light.off! "lamp"
  q0light.darkness! 0.95
}

listen mouse.click lights_out

Sources: q0player/src/lib.rs, q0player/src/objects.rs, q0player/src/live.rs, q0s-format/src/lighting.rs, q0player/src/ui/app.rs, q0editor/src/app.rs, q0s-format/src/q0lang/runtime.rs, q0physics/src/lib.rs.

q0.window

The player's own window, on desktop systems. Sizes and places are in screen points; window.* and screen.* are refreshed before every script.

namevalue
window.x, window.ywhere the window's outer corner is on the desktop
window.width, window.heightthe size of the window's inside
window.fullscreenwhether it is fullscreen
window.uiwhether the menu bar and status show around the movie
screen.width, screen.heightthe size of the screen the window is on

Writing window.x, window.y, window.width or window.height moves or sizes the window, like the commands:

commanddoes
q0window.fullscreen! onfullscreen with only the movie, as F9 does; false comes back
q0window.ui! onshows or hides the menu bar and status line
q0window.hotkeys! onwhether F9 and F4 still work; Ctrl+O and Ctrl+R always do
q0window.move! x, yputs the window there
q0window.size! width, heightsizes its inside
q0window.center!centres it on its screen
q0window.title! textthe title in the title bar
q0window.decorations! on (q0window.titlebar! on)desktop system frame and title-bar buttons; false hides them, true restores them
q0window.icon! "app_icon"desktop window/taskbar icon from a library bitmap name or numeric asset id
q0window.icon! nullrestores q0player's own window icon
q0window.top! onkeeps it above other windows
q0window.minimize!minimizes it
q0window.perf!copies the performance log, as F4 does
q0window.quit!closes the player

on takes true or false, 1 or 0, or "on" or "off". A fullscreen window neither moves nor sizes. Opening a movie again puts the menu bar and the keys back.

import q0.window
import q0.math

# shake the window when something hits
pb func shake amount {
  window.x = window.x + amount
}
q0window.title! "BONE ZONE"
q0window.size! 640, 480
q0window.center!

Sources: player, layers and window, what layers draw, object scripts, live physics, particles and lights, lighting, player keys, editor preview, runtime commands, simulation.

Window icons are bundled bitmap assets, not filesystem paths. Import a PNG into the movie library and pass its library name or asset id. Closing the movie or opening another one restores the normal player icon and system frame. These commands affect the desktop window; they do not change the executable's file icon, and have no effect in the browser or Android host.