Skip to content

Output Schema

Open the editor to try output types live.

Return a FrameResult object from your entry file. Every property is optional — return only what you need.

javascript
return {
  sprites: [...],
  particles: [...],
  lines: [...],
  vectors: [...],
  circles: [...],
  arcs: [...],
  bars: [...],
  text: { ... },
}

Rendering Order

Drawn back to front:

  1. sprites
  2. lines
  3. circles
  4. arcs
  5. bars
  6. vectors
  7. particles
  8. text (HUD overlay)

Later layers sit on top of earlier ones.


Sprites

Images from the built-in asset library. x / y are the center of the image. Draw a background image first, then sprites, so it sits behind everything.

javascript
return {
  sprites: [
    { asset: 'ship-0', x: w / 2, y: h / 2, w: 64, h: 64 },
    { asset: 'coin', x: 120, y: 200 },
  ],
}
PropertyTypeRequiredDefaultDescription
assetstringyesAsset id, e.g. 'ship-0', 'coin'
xnumberyesCenter X
ynumberyesCenter Y
wnumbernonatural widthDisplay width
hnumbernonatural heightDisplay height
rotationnumberno0Rotation in radians
flipXbooleannofalseMirror horizontally
flipYbooleannofalseMirror vertically
opacitynumberno10–1 transparency
srcobjectnowhole imageSource crop { sx, sy, sw, sh } for sprite sheets

Sprites whose image is still loading are skipped until ready, so there is no error frame.

GAME BUILDING

src crops let you pull one frame out of a sprite sheet. Use assets.frame(id, index, cols) to compute the crop, or assets.tiles(...) to lay out a whole grid. See Assets.


Particles

Filled circles with optional labels.

javascript
return {
  particles: [
    { x: 100, y: 200, r: 8, color: '#8B5CF6', label: 'ball' },
  ],
}
PropertyTypeRequiredDefaultDescription
xnumberyesCenter X
ynumberyesCenter Y
rnumberno6Radius in pixels
colorstringno#8B5CF6Fill color (CSS)
labelstringnoLabel to the right of the circle

TIP

Use particles for moving bodies — balls, planets, boids. Default purple reads well on the dark canvas.


Lines

Solid or dashed segments.

javascript
return {
  lines: [
    { x1: 0, y1: 0, x2: 200, y2: 150, color: '#F59E0B', width: 2, dashed: true },
  ],
}
PropertyTypeRequiredDefaultDescription
x1numberyesStart X
y1numberyesStart Y
x2numberyesEnd X
y2numberyesEnd Y
colorstringno#ffffffStroke color
widthnumberno2Line width in pixels
dashedbooleannofalseDash pattern 6 / gap 4

TIP

Store a trail in state.trail and map it to lines each frame. Cap length for performance.


Vectors

Arrows from an origin, with arrowheads.

javascript
return {
  vectors: [
    { x: 100, y: -50, ox: 200, oy: 200, color: '#22C55E', label: 'v' },
  ],
}
PropertyTypeRequiredDefaultDescription
xnumberyesHorizontal component from origin
ynumberyesVertical component from origin
oxnumberno0Origin X
oynumberno0Origin Y
colorstringno#22C55EArrow color
labelstringnoLabel near the arrowhead

Arrowhead size: min(12, length * 0.3) pixels.

MATH

x / y are components, not endpoints. Velocity (vx, vy) at (px, py){ x: vx, y: vy, ox: px, oy: py }. Scale (e.g. vx * 0.3) so arrows stay readable.


Circles

Outlines, optionally filled.

javascript
return {
  circles: [
    { cx: 200, cy: 200, r: 60, color: 'rgba(255,255,255,0.2)', fill: 'rgba(139,92,246,0.1)' },
  ],
}
PropertyTypeRequiredDefaultDescription
cxnumberyesCenter X
cynumberyesCenter Y
rnumberyesRadius
colorstringnorgba(255,255,255,0.2)Stroke
fillstringnoFill (omit for hollow)

TIP

Good for orbits, influence radii, and collision bounds. Semi-transparent fills keep particles visible underneath.


Arcs

Partial circles for angles.

javascript
return {
  arcs: [
    { cx: 200, cy: 200, r: 30, startAngle: 0, endAngle: 1.57, color: '#F59E0B', width: 2 },
  ],
}
PropertyTypeRequiredDefaultDescription
cxnumberyesCenter X
cynumberyesCenter Y
rnumberyesRadius
startAnglenumberyesStart radians (0 = right)
endAnglenumberyesEnd radians
colorstringno#F59E0BStroke
widthnumberno2Line width

MATH

Canvas angles: 0 right, π/2 down (Y increases downward), π left, 3π/2 up. Math textbooks often use Y-up — flip with -Math.sin when matching textbook diagrams.


Bars

Filled rectangles for energy diagrams, histograms, or gauges.

javascript
const KE = 0.5 * mass * state.v * state.v;
const PE = 0.5 * k * state.x * state.x;

return {
  bars: [
    { x: 30, y: 300 - KE * 0.01, w: 40, h: KE * 0.01, color: '#EF4444', label: 'KE' },
    { x: 90, y: 300 - PE * 0.01, w: 40, h: PE * 0.01, color: '#3B82F6', label: 'PE' },
  ],
}
PropertyTypeRequiredDefaultDescription
xnumberyesTop-left X
ynumberyesTop-left Y
wnumberyesWidth
hnumberyesHeight (grows downward)
colorstringno#8B5CF6Fill
labelstringnoText above the bar

TIP

Normalize heights: h: (energy / maxEnergy) * 150 so bars stay on-screen.


Text

HUD key-value panel in the top-right.

javascript
return {
  text: {
    time: time.toFixed(1) + 's',
    velocity: Math.sqrt(state.vx ** 2 + state.vy ** 2).toFixed(1),
    particles: state.particles.length,
  },
}
Keys / valuesTypeDescription
keysstringLabels (monospace)
valuesstring | numberShown after each label

Panel at (w - 210, 5), width 205px, ~18px per row. Entries appear in object insertion order (not sorted).

WARNING

The HUD covers the top-right ~210px. Keep important geometry out of that corner.


Returning Nothing

null, undefined, or no return clears the frame to grid + axes only:

javascript
if (!state.ready) return null;

Useful for conditional rendering or waiting on init.