Scene spec format
Every scene on misconception.ai is drawn from a spec: one JSON object that says what is in the scene, how it looks, how it moves, and how its walkthrough goes. The agent writes it as you talk, and you can read and change it yourself in the Spec sidebar. This page describes all of it.
Editing a spec
- The sidebar shows the spec compactly: a field at its default value is left out. Anything on this page that has a default can be left out the same way.
- Apply checks the spec, saves it as a new version of the scene, and the scene updates. The agent works from the spec as it is, your changes included, so you can refer to things by their ids when you talk to it.
- Apply is forgiving. It repairs what it can, leaves out what it cannot use, and lists both under “Repaired while applying”. It stops only at JSON that does not parse, or a scene with no nodes and no paths.
- On a scene that is not yours, the spec is there to read and copy, not to apply.
A first scene
A sphere with a smaller one circling it, a link between them, and a walkthrough of two steps. The sections below explain each part. Drag a view to turn it; click it, and the wheel or a pinch zooms. On a touch screen, tap it first.
{
"title": "Earth and Moon",
"summary": "The Moon circles the Earth, held to it by gravity.",
"palette": {
"earth": {
"dark": "#4f8fe8",
"light": "#2f6fd0"
},
"moon": {
"dark": "#c9cfdc",
"light": "#6b7387"
},
"pull": {
"dark": "#8fa3c7",
"light": "#5d6f91"
}
},
"nodes": [
{
"id": "earth",
"shape": "sphere",
"position": [0, 0, 0],
"size": 4,
"color": "earth",
"label": "Earth",
"description": "Our planet, almost four times as wide as the Moon.",
"animations": [
{
"type": "spin",
"period": 10
}
]
},
{
"id": "moon",
"shape": "sphere",
"parent": "earth",
"position": [8, 0, 0],
"size": 1.1,
"color": "moon",
"label": "Moon",
"description": "It takes about 27 days to go once around the Earth.",
"animations": [
{
"type": "orbit",
"period": 20
}
]
}
],
"links": [
{
"from": "moon",
"to": "earth",
"arrow": "forward",
"color": "pull",
"label": "Gravity"
}
],
"steps": [
{
"title": "Earth and Moon",
"text": "The Moon goes around the Earth, held by its gravity.",
"focus": []
},
{
"title": "The Moon",
"text": "One trip around takes about 27 days. Here it takes 20 seconds.",
"focus": ["moon"]
}
]
}Conventions
- Space. Coordinates are right-handed, with Y up, in units of your choosing. A scene reads best at about 24 units across, centered on the origin. The camera frames whatever is there.
- Vectors are
[x, y, z].{"x": 1, "y": 2, "z": 3}works too, and so does one number for all three: asizeof2is[2, 2, 2]. - Rotations are Euler angles in degrees, applied about X, then Y, then Z.
- Ids are strings, unique among the nodes and paths. Short kebab-case ids, such as
left-wheel, are easiest to work with. - Options, such as a shape or a style, can be written in any case. One that is not on the list falls back to the default.
- Text is plain text: Markdown is shown as it is written.
The scene
The spec is an object with these fields. Only one node or path is needed for a scene to draw.
titletext · default"Untitled"- A short name for the scene.
summarytext · default none- One or two sentences that state its key idea.
paletteobject · default none- The scene’s colors, by name. See Palette.
nodeslist · default none- The things in the scene. See Nodes.
linkslist · default none- Lines that join two nodes. See Links.
pathslist · default none- Free-standing lines through points. See Paths.
jointslist · default none- What makes machines move. See Joints.
stepslist · default none- The guided walkthrough. See Steps.
Palette
A scene can be viewed on a dark background (#0d1324) or a light one (#ffffff), so each color is given for both. The palette holds them under names of your choosing, and every color in the scene, of nodes, links, paths and steps, is one of those names.
{
"palette": {
"steel": {
"dark": "#9fb3d1",
"light": "#4f6385"
},
"signal": {
"dark": "#ffb347",
"light": "#c86f00"
}
}
}darkis the color on the dark background,lighton the light one: the same hue, made to stand out from each. Clear, fairly bright colors work on dark; deeper ones on light.- Colors are
#rrggbbor#rgb. A color given for only one background is used on both. - Changing a palette color changes everything that uses it. Things of the same kind can share a name; something that must look different gets a name of its own.
- A node without a color, or with a name the palette does not have, gets one of the default colors (
blue,orange,green,yellow,purple,pink,cyan,lime), added to the palette under that name. Links and paths getline. Colors nothing uses are dropped. - Names are 1 to 40 characters, and a palette holds up to 200 colors.
Nodes
Each node is one shape, or one model from the library, placed in the scene.
idtext · required- Unique among the nodes and paths. A node without one, or with one already used, is left out.
shapeoption · defaultsphere- One of the shapes.
modelmodel id · default none- A model from the library, drawn in place of the shape. See Models.
position[x, y, z] · default[0, 0, 0]- Where its center is: relative to its parent if it has one, else in the scene.
size[x, y, z] or a number · default[1, 1, 1]- The size of its bounding box before it is rotated, from 0.01 to 100 each way. A sphere 2 across is
[2, 2, 2]; a tall cylinder is[1, 4, 1]; a thin orbit line is a torus such as[10, 0.04, 10]. rotation[x, y, z] · default[0, 0, 0]- Euler angles in degrees.
colorpalette name- One of the palette’s colors. Left out, the node gets a default one: see Palette.
styleoption · defaultsolid- One of the styles.
opacity0 to 1 · default1- At 0 the node is hidden, ready for a step to show it.
labeltext, up to 60 characters · default none- A caption of a few words. Captions show where there is room for them, larger nodes first; the rest appear as you zoom in or point at the node.
descriptiontext, up to 600 characters · default none- A sentence or two, shown when the node is selected.
parentnode id · default none- See Parents.
animationslist · default none- See Animations.
moveslist · default none- The node’s own sequence of moves. See Moves.
repeattrue or false · defaultfalse- Whether the moves play again when they end.
heightsrows of numbers · default flat- For a terrain only. See Terrain.
Shapes
Each shape fills its node’s size.
sphere- A ball; stretched into an ellipsoid when its size is not the same each way.
box- A rectangular block.
cylinder- Upright, along Y.
cone- Upright, along Y, its point at the top.
capsule- A cylinder with rounded ends, along Y.
torus- A tube bent into a ring, lying flat in the XZ plane around the Y axis. x and z are its outer diameter, y the thickness of the tube.
ring- A flat band in the XZ plane around the Y axis, its hole 60% of its width. x and z are its outer diameter; y does not matter.
tetrahedron- Four triangular faces.
octahedron- Eight triangular faces.
dodecahedron- Twelve pentagonal faces.
icosahedron- Twenty triangular faces.
terrain- Ground shaped by a heightmap: see Terrain.
label- Draws nothing. Use it for a floating caption, an invisible anchor for links, or an invisible parent that groups and tilts other nodes. Its size and color are ignored.
Show the spec
{
"title": "Shapes",
"palette": {
"first": {
"dark": "#5b9dff",
"light": "#2f6fd0"
},
"second": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"third": {
"dark": "#5ee0a0",
"light": "#0a9a62"
}
},
"nodes": [
{
"id": "sphere",
"shape": "sphere",
"position": [-6, 3.2, 0],
"size": 1.6,
"color": "first",
"label": "sphere"
},
{
"id": "box",
"shape": "box",
"position": [-2, 3.2, 0],
"size": 1.6,
"color": "first",
"label": "box"
},
{
"id": "cylinder",
"shape": "cylinder",
"position": [2, 3.2, 0],
"size": 1.6,
"color": "first",
"label": "cylinder"
},
{
"id": "cone",
"shape": "cone",
"position": [6, 3.2, 0],
"size": 1.6,
"color": "first",
"label": "cone"
},
{
"id": "capsule",
"shape": "capsule",
"position": [-6, 0, 0],
"size": [1, 1.8, 1],
"color": "second",
"label": "capsule"
},
{
"id": "torus",
"shape": "torus",
"position": [-2, 0, 0],
"size": [1.8, 0.45, 1.8],
"color": "second",
"label": "torus"
},
{
"id": "ring",
"shape": "ring",
"position": [2, 0, 0],
"size": [1.8, 1, 1.8],
"color": "second",
"label": "ring"
},
{
"id": "terrain",
"shape": "terrain",
"position": [6, 0, 0],
"size": [2, 1, 2],
"color": "second",
"label": "terrain",
"heights": [
[0.2, 0.6, 0.3],
[0.5, 1, 0.4],
[0.1, 0.5, 0.2]
]
},
{
"id": "tetrahedron",
"shape": "tetrahedron",
"position": [-6, -3.2, 0],
"size": 1.6,
"color": "third",
"label": "tetrahedron"
},
{
"id": "octahedron",
"shape": "octahedron",
"position": [-2, -3.2, 0],
"size": 1.6,
"color": "third",
"label": "octahedron"
},
{
"id": "dodecahedron",
"shape": "dodecahedron",
"position": [2, -3.2, 0],
"size": 1.6,
"color": "third",
"label": "dodecahedron"
},
{
"id": "icosahedron",
"shape": "icosahedron",
"position": [6, -3.2, 0],
"size": 1.6,
"color": "third",
"label": "icosahedron"
},
{
"id": "caption",
"shape": "label",
"position": [0, 5.6, 0],
"label": "label: a caption on its own"
}
]
}Styles
solid- An ordinary opaque surface.
glass- Translucent. For containers, shells, membranes and regions: anything with nodes inside it.
glow- Gives off light. For stars, energy, and parts that are active or highlighted.
wireframe- Only the edges of its faces.
Show the spec
{
"title": "Styles",
"palette": {
"solid": {
"dark": "#5b9dff",
"light": "#2f6fd0"
},
"glass": {
"dark": "#9fb3d1",
"light": "#5a6d8f"
},
"core": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"glow": {
"dark": "#ffd166",
"light": "#a87d00"
},
"wireframe": {
"dark": "#c58bff",
"light": "#8a4fd8"
}
},
"nodes": [
{
"id": "solid",
"shape": "sphere",
"position": [-6.75, 0, 0],
"size": 2,
"color": "solid",
"label": "solid"
},
{
"id": "glass",
"shape": "box",
"position": [-2.25, 0, 0],
"size": 2.2,
"color": "glass",
"style": "glass",
"label": "glass"
},
{
"id": "core",
"shape": "sphere",
"parent": "glass",
"position": [0, 0, 0],
"size": 0.9,
"color": "core"
},
{
"id": "glow",
"shape": "sphere",
"position": [2.25, 0, 0],
"size": 1.6,
"color": "glow",
"style": "glow",
"label": "glow"
},
{
"id": "wireframe",
"shape": "icosahedron",
"position": [6.75, 0, 0],
"size": 2.2,
"color": "wireframe",
"style": "wireframe",
"label": "wireframe"
}
]
}Parents
A node with a parent is part of it. Its position and rotation are relative to the parent’s, and it moves and turns with it; its size is its own. Build objects of several parts this way, or group nodes under an invisible label node to place and tilt them together. A parent that does not exist, or a node that would end up its own ancestor, is dropped.
Animations
Each item of animations is one of these types, at most one of each:
spin- The shape turns about axis, through its own center. Its children do not turn with it.
orbit- The node, with its children, circles its parent's center (the scene's origin if it has no parent) about axis, starting from where position puts it. Its distance from that center is the radius.
pulse- Its size swells and shrinks by ±amount, a fraction of its size.
bob- It floats up and down by ±amount units.
typeoption · required- One of the types above.
periodseconds · default 8 for spin, 12 for orbit, 2 for pulse, 3 for bob- How long one cycle takes, from 0.2 to 600 seconds. A negative period reverses a spin or an orbit.
axis[x, y, z] · default[0, 1, 0]- What a spin turns about, in the node’s own frame, or what an orbit circles about, in its parent’s.
amountnumber · default 0.12 for pulse, 0.3 for bob- For a pulse, the fraction of its size it swells by, up to 0.9; for a bob, how far it floats, in units, up to 20.
Show the spec
{
"title": "Animations",
"palette": {
"spin": {
"dark": "#5b9dff",
"light": "#2f6fd0"
},
"center": {
"dark": "#9fb3d1",
"light": "#5a6d8f"
},
"orbit": {
"dark": "#5ee0a0",
"light": "#0a9a62"
},
"pulse": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"bob": {
"dark": "#c58bff",
"light": "#8a4fd8"
}
},
"nodes": [
{
"id": "spin",
"shape": "box",
"position": [-7.5, 0, 0],
"size": 1.6,
"color": "spin",
"label": "spin",
"animations": [
{
"type": "spin",
"period": 4
}
]
},
{
"id": "center",
"shape": "sphere",
"position": [-2.5, 0, 0],
"size": 0.6,
"color": "center",
"label": "orbit"
},
{
"id": "track",
"shape": "torus",
"parent": "center",
"position": [0, 0, 0],
"size": [3, 0.03, 3],
"color": "center"
},
{
"id": "orbit",
"shape": "sphere",
"parent": "center",
"position": [1.5, 0, 0],
"size": 0.6,
"color": "orbit",
"animations": [
{
"type": "orbit",
"period": 4
}
]
},
{
"id": "pulse",
"shape": "sphere",
"position": [2.5, 0, 0],
"size": 1.6,
"color": "pulse",
"label": "pulse",
"animations": [
{
"type": "pulse",
"period": 1.5,
"amount": 0.15
}
]
},
{
"id": "bob",
"shape": "octahedron",
"position": [7.5, 0, 0],
"size": 1.5,
"color": "bob",
"label": "bob",
"animations": [
{
"type": "bob",
"period": 2.5,
"amount": 0.5
}
]
}
]
}Moves
Animations go on evenly and for ever. For motion that starts and stops, a node has moves: a list of what it does one after another, from where it is built as the scene’s clock starts. Something that falls, is thrown, bounces, swings and stops, opens, closes, strikes or fades. Each move is a target and how long it takes to get there from where the move before left the node; what it leaves out stays as it was. When the moves end, the node stays where they left it, unless repeat is true, in which case they play again from the start.
position[x, y, z] · default as it was- Where it goes, relative to its parent as in the node.
rotation[x, y, z] · default as it was- How it is turned at the end, in degrees. The angles run through as numbers, so 720 is two whole turns.
opacity0 to 1 · default as it was- How opaque it is at the end, as a share of what it is otherwise: 0 hides it. It reaches its children too.
overseconds · required- How long the move takes.
easeoption · defaultin-out- How it goes, one of the options below. Motion under gravity is
indownward andoutupward. waitseconds- Written on its own,
{ "wait": 1 }holds the node still for that long.
linear- Steadily, at one speed.
in- From rest, speeding up: falling, swinging down, setting off.
out- Slowing to rest: rising, swinging up, braking.
in-out- From rest to rest, as a hand would move it.
The pivot of a door on hinges that swings open, stays open a second and swings shut, over and over; the door is its child:
{
"id": "door-pivot",
"shape": "label",
"position": [-1, 0, 0],
"repeat": true,
"moves": [
{
"rotation": [0, 90, 0],
"over": 1,
"ease": "out"
},
{
"wait": 1
},
{
"rotation": [0, 0, 0],
"over": 1,
"ease": "in"
}
]
}Show the spec
{
"title": "A door on hinges",
"palette": {
"frame": {
"dark": "#9fb3d1",
"light": "#5a6d8f"
},
"door": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"knob": {
"dark": "#ffd166",
"light": "#a87d00"
}
},
"nodes": [
{
"id": "sill",
"shape": "box",
"position": [0, -2.2, 0],
"size": [3.2, 0.2, 1.6],
"color": "frame"
},
{
"id": "post-left",
"shape": "box",
"position": [-1.1, 0, 0],
"size": [0.2, 4.2, 0.2],
"color": "frame"
},
{
"id": "post-right",
"shape": "box",
"position": [1.1, 0, 0],
"size": [0.2, 4.2, 0.2],
"color": "frame"
},
{
"id": "lintel",
"shape": "box",
"position": [0, 2.2, 0],
"size": [2.4, 0.2, 0.2],
"color": "frame"
},
{
"id": "door-pivot",
"shape": "label",
"position": [-1, 0, 0],
"repeat": true,
"moves": [
{
"rotation": [0, 90, 0],
"over": 1,
"ease": "out"
},
{
"wait": 1
},
{
"rotation": [0, 0, 0],
"over": 1,
"ease": "in"
}
]
},
{
"id": "door",
"shape": "box",
"parent": "door-pivot",
"position": [1, 0, 0],
"size": [2, 4, 0.1],
"color": "door",
"label": "Door"
},
{
"id": "knob",
"shape": "sphere",
"parent": "door-pivot",
"position": [1.7, -0.1, 0.12],
"size": 0.16,
"color": "knob"
}
]
}- To turn about a point that is not the node’s center, as the door does about its hinge, give the moves to an invisible label node at that point and make the node its child.
- To move in two independent ways at once, such as a thrown ball flying steadily sideways while it rises and falls, nest: a parent with the one motion carrying a child with the other.
- Nodes that move together keep moves of the same total length, so they stay in step as they repeat. A repeating node should end where it was built, or it jumps back; Apply says so.
- A node with moves is not part of a machine, and a step may change only its color and opacity. Up to 60 moves a node.
Models
model names a ready-made model from the library in place of a shape: a car, a tree, a microchip. The model is fitted into the node’s size with its proportions kept, centered on its position, upright and facing +Z. Color, style, parents, links, and the orbit, pulse and bob animations work as for any node. Only models that turn as a whole, such as wheels and gears, can spin, and only about their axle. A model the library does not have is drawn as the node’s shape. Every model is shown, with its id, in the Model library.
Show the spec
{
"title": "Models",
"palette": {
"ground": {
"dark": "#6fbf5a",
"light": "#3f8f2a"
},
"house": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"tree": {
"dark": "#5ee0a0",
"light": "#0a9a62"
},
"windmill": {
"dark": "#9fb3d1",
"light": "#5a6d8f"
},
"car": {
"dark": "#5b9dff",
"light": "#2f6fd0"
},
"gear": {
"dark": "#ffd166",
"light": "#a87d00"
}
},
"nodes": [
{
"id": "ground",
"shape": "box",
"position": [0, -0.1, 0],
"size": [15, 0.2, 8],
"color": "ground"
},
{
"id": "house",
"model": "house",
"position": [-4.5, 1.5, -1],
"size": [2.27, 3, 2.12],
"color": "house",
"label": "house"
},
{
"id": "tree",
"model": "tree",
"position": [-1.2, 1.2, -2],
"size": [2.14, 2.4, 2.16],
"color": "tree",
"label": "tree"
},
{
"id": "windmill",
"model": "windmill",
"position": [2.6, 1.8, -1.6],
"size": [2.62, 3.6, 1.59],
"color": "windmill",
"label": "windmill"
},
{
"id": "car",
"model": "car",
"position": [1.5, 0.47, 2.2],
"size": [1.17, 0.93, 2.6],
"rotation": [0, 90, 0],
"color": "car",
"label": "car"
},
{
"id": "post",
"shape": "cylinder",
"position": [5.4, 0.7, 2],
"size": [0.25, 1.4, 0.25],
"color": "windmill"
},
{
"id": "gear",
"model": "gear",
"position": [5.4, 2.1, 2],
"size": [1.6, 1.6, 0.32],
"color": "gear",
"label": "gear",
"animations": [
{
"type": "spin",
"period": 6,
"axis": [0, 0, 1]
}
]
}
]
}Terrain
A node of shape terrain is a block of ground whose top is shaped by heights, a heightmap: for landscapes, landforms and geology. Its position and size are its box, and the height of the box is the relief, from the lowest the ground can be to the highest.
heightsis 2 to 10 rows of 2 to 10 numbers, all rows as long. Each number is from 0, the bottom of the box, to 1, its top.- Seen from above, the first row runs along the north edge (−z) and the last along the south edge (+z). In each row, the first number is at the west edge (−x) and the last at the east edge (+x). The samples are evenly spaced from edge to edge.
- The ground passes through every sample and curves smoothly between them, never rising above or dipping below its neighbours. Steep slopes show as bare rock, and the sides of the block as earth.
- Rows that are too short are extended with their last number; a grid larger than 10 by 10 is resampled; a terrain without heights is flat, filling its box.
{
"id": "hills",
"shape": "terrain",
"position": [0, 2, 0],
"size": [20, 4, 12],
"color": "grass",
"heights": [
[0.2, 0.6, 0.9, 0.5],
[0.1, 0.4, 0.7, 0.3],
[0, 0.2, 0.4, 0.1]
]
}Here the box runs from x −10 to 10, z −6 to 6 and y 0 to 4. Its highest sample, 0.9, is in the first row and third column: at x = −10 + 2 × 20 ⁄ 3 ≈ 3.3, z = −6, and y = 0 + 0.9 × 4 = 3.6. Something standing there has its bottom at that height, as the marker here does:
Show the spec
{
"title": "Terrain",
"palette": {
"grass": {
"dark": "#6fbf5a",
"light": "#3f8f2a"
},
"marker": {
"dark": "#ff8a5b",
"light": "#d0612f"
}
},
"nodes": [
{
"id": "hills",
"shape": "terrain",
"position": [0, 2, 0],
"size": [20, 4, 12],
"color": "grass",
"heights": [
[0.2, 0.6, 0.9, 0.5],
[0.1, 0.4, 0.7, 0.3],
[0, 0.2, 0.4, 0.1]
]
},
{
"id": "marker",
"shape": "cone",
"position": [3.33, 4.2, -6],
"size": [0.7, 1.2, 0.7],
"color": "marker",
"label": "Highest sample"
}
]
}Links
A link is a line from one node to another. It ends at their surfaces and follows them as they move. Links have no id: a link is known by its two ends.
fromnode id · required- Where it starts. A link to a node that does not exist is dropped.
tonode id · required- Where it ends.
arrowoption · defaultnonenone: a plain line.forward: an arrowhead at the to end, for direction, cause or flow.both: an arrowhead at each end.flowtrue or false · defaultfalse- Small arrows travelling from
fromtoto, for something that really moves: data, current, fluid. labeltext, up to 60 characters · default none- Shown while a step focuses on both ends, or when you point at one of them.
colorpalette name · defaultline- See Palette.
widthpixels, 1 to 8 · default2- How thick the line is.
curve−1 to 1 · default0- A sideways bend, as a fraction of the link’s length. Small values, such as 0.3, keep two links between the same area apart.
dashedtrue or false · defaultfalse- A dashed line.
Show the spec
{
"title": "Links",
"palette": {
"end": {
"dark": "#9fb3d1",
"light": "#5a6d8f"
},
"line": {
"dark": "#5b9dff",
"light": "#2f6fd0"
}
},
"nodes": [
{
"id": "plain-from",
"shape": "sphere",
"position": [-8, -1.8, 0],
"size": 0.7,
"color": "end"
},
{
"id": "plain-to",
"shape": "sphere",
"position": [-8, 1.8, 0],
"size": 0.7,
"color": "end",
"label": "plain"
},
{
"id": "forward-from",
"shape": "sphere",
"position": [-4, -1.8, 0],
"size": 0.7,
"color": "end"
},
{
"id": "forward-to",
"shape": "sphere",
"position": [-4, 1.8, 0],
"size": 0.7,
"color": "end",
"label": "forward"
},
{
"id": "both-from",
"shape": "sphere",
"position": [0, -1.8, 0],
"size": 0.7,
"color": "end"
},
{
"id": "both-to",
"shape": "sphere",
"position": [0, 1.8, 0],
"size": 0.7,
"color": "end",
"label": "both"
},
{
"id": "flow-from",
"shape": "sphere",
"position": [4, -1.8, 0],
"size": 0.7,
"color": "end"
},
{
"id": "flow-to",
"shape": "sphere",
"position": [4, 1.8, 0],
"size": 0.7,
"color": "end",
"label": "flow"
},
{
"id": "curve-from",
"shape": "sphere",
"position": [8, -1.8, 0],
"size": 0.7,
"color": "end"
},
{
"id": "curve-to",
"shape": "sphere",
"position": [8, 1.8, 0],
"size": 0.7,
"color": "end",
"label": "curve"
}
],
"links": [
{
"from": "plain-from",
"to": "plain-to",
"color": "line",
"width": 3
},
{
"from": "forward-from",
"to": "forward-to",
"color": "line",
"width": 3,
"arrow": "forward"
},
{
"from": "both-from",
"to": "both-to",
"color": "line",
"width": 3,
"arrow": "both"
},
{
"from": "flow-from",
"to": "flow-to",
"color": "line",
"width": 3,
"flow": true
},
{
"from": "curve-from",
"to": "curve-to",
"color": "line",
"width": 3,
"curve": 0.4
}
]
}Paths
A path is a line through points in the scene: a trajectory, a wave, a field line, an outline, the graph of a function. Its points are in the scene’s coordinates, not attached to any node. A curve looks smooth with 20 to 80 points.
pointslist of [x, y, z] · required- At least 2, up to 500.
idtext · defaultpath-0,path-1…- For steps to focus on it. One already used by a node or path is replaced.
smoothtrue or false · defaulttrue- A smooth curve through the points; false for straight segments.
closedtrue or false · defaultfalse- Joins the last point to the first.
flowtrue or false · defaultfalse- Small arrows travelling along it.
labeltext, up to 60 characters · default none- A caption.
colorpalette name · defaultline- See Palette.
widthpixels, 1 to 8 · default2- How thick the line is.
dashedtrue or false · defaultfalse- A dashed line.
Show the spec
{
"title": "Paths",
"palette": {
"helix": {
"dark": "#5b9dff",
"light": "#2f6fd0"
},
"wave": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"triangle": {
"dark": "#5ee0a0",
"light": "#0a9a62"
}
},
"nodes": [
{
"id": "helix-name",
"shape": "label",
"position": [-5, -2.8, 0],
"label": "smooth, flow"
},
{
"id": "wave-name",
"shape": "label",
"position": [2, -2.8, 0],
"label": "smooth"
},
{
"id": "triangle-name",
"shape": "label",
"position": [8, -2.8, 0],
"label": "straight, closed"
}
],
"paths": [
{
"id": "helix",
"color": "helix",
"width": 3,
"flow": true,
"points": [
[-3.6, -2, 0],
[-3.67, -1.93, 0.43],
[-3.87, -1.87, 0.82],
[-4.18, -1.8, 1.13],
[-4.57, -1.73, 1.33],
[-5, -1.67, 1.4],
[-5.43, -1.6, 1.33],
[-5.82, -1.53, 1.13],
[-6.13, -1.47, 0.82],
[-6.33, -1.4, 0.43],
[-6.4, -1.33, 0],
[-6.33, -1.27, -0.43],
[-6.13, -1.2, -0.82],
[-5.82, -1.13, -1.13],
[-5.43, -1.07, -1.33],
[-5, -1, -1.4],
[-4.57, -0.93, -1.33],
[-4.18, -0.87, -1.13],
[-3.87, -0.8, -0.82],
[-3.67, -0.73, -0.43],
[-3.6, -0.67, 0],
[-3.67, -0.6, 0.43],
[-3.87, -0.53, 0.82],
[-4.18, -0.47, 1.13],
[-4.57, -0.4, 1.33],
[-5, -0.33, 1.4],
[-5.43, -0.27, 1.33],
[-5.82, -0.2, 1.13],
[-6.13, -0.13, 0.82],
[-6.33, -0.07, 0.43],
[-6.4, 0, 0],
[-6.33, 0.07, -0.43],
[-6.13, 0.13, -0.82],
[-5.82, 0.2, -1.13],
[-5.43, 0.27, -1.33],
[-5, 0.33, -1.4],
[-4.57, 0.4, -1.33],
[-4.18, 0.47, -1.13],
[-3.87, 0.53, -0.82],
[-3.67, 0.6, -0.43],
[-3.6, 0.67, 0],
[-3.67, 0.73, 0.43],
[-3.87, 0.8, 0.82],
[-4.18, 0.87, 1.13],
[-4.57, 0.93, 1.33],
[-5, 1, 1.4],
[-5.43, 1.07, 1.33],
[-5.82, 1.13, 1.13],
[-6.13, 1.2, 0.82],
[-6.33, 1.27, 0.43],
[-6.4, 1.33, 0],
[-6.33, 1.4, -0.43],
[-6.13, 1.47, -0.82],
[-5.82, 1.53, -1.13],
[-5.43, 1.6, -1.33],
[-5, 1.67, -1.4],
[-4.57, 1.73, -1.33],
[-4.18, 1.8, -1.13],
[-3.87, 1.87, -0.82],
[-3.67, 1.93, -0.43],
[-3.6, 2, 0]
]
},
{
"id": "wave",
"color": "wave",
"width": 3,
"points": [
[-1, 0, 0],
[-0.85, 0.28, 0],
[-0.7, 0.54, 0],
[-0.55, 0.78, 0],
[-0.4, 0.97, 0],
[-0.25, 1.11, 0],
[-0.1, 1.19, 0],
[0.05, 1.2, 0],
[0.2, 1.14, 0],
[0.35, 1.02, 0],
[0.5, 0.85, 0],
[0.65, 0.63, 0],
[0.8, 0.37, 0],
[0.95, 0.09, 0],
[1.1, -0.19, 0],
[1.25, -0.46, 0],
[1.4, -0.71, 0],
[1.55, -0.91, 0],
[1.7, -1.07, 0],
[1.85, -1.17, 0],
[2, -1.2, 0],
[2.15, -1.17, 0],
[2.3, -1.07, 0],
[2.45, -0.91, 0],
[2.6, -0.71, 0],
[2.75, -0.46, 0],
[2.9, -0.19, 0],
[3.05, 0.09, 0],
[3.2, 0.37, 0],
[3.35, 0.63, 0],
[3.5, 0.85, 0],
[3.65, 1.02, 0],
[3.8, 1.14, 0],
[3.95, 1.2, 0],
[4.1, 1.19, 0],
[4.25, 1.11, 0],
[4.4, 0.97, 0],
[4.55, 0.78, 0],
[4.7, 0.54, 0],
[4.85, 0.28, 0],
[5, 0, 0]
]
},
{
"id": "triangle",
"color": "triangle",
"width": 3,
"smooth": false,
"closed": true,
"points": [
[6.5, -1.5, 0],
[9.5, -1.5, 0],
[8, 1.5, 0]
]
}
]
}Joints
Joints make machines move: a crank turning a piston through a rod, a beam rocking on its post, wheels joined by a coupling rod. Each part is a node, and each joint joins two of them at a point and says how one moves against the other. You place the parts where they are as the scene starts, and the viewer works out how each moves from there. There is no physics: no mass, no gravity.
typeoption · requiredhinge: b turns against a about axis, through the point at.slide: b moves against a along axis, without turning.anode id · required- The node
bis mounted on. bnode id · required- The node that moves.
at[x, y, z] · default for a slide, b’s position- The center of the pin or axle, in the scene’s coordinates, as the scene starts. It must lie on both nodes or their children. A hinge needs one.
axis[x, y, z] · required- In the scene’s coordinates: the hinge’s axle, or the direction the slide moves in.
periodseconds · default none- Makes a hinge a motor: b turns once against a every period, counterclockwise looking down the axis. A negative period reverses it.
The joints of a crank driving a piston, starting with the crank pointing straight up:
{
"joints": [
{
"type": "hinge",
"a": "block",
"b": "crank",
"at": [0, 0, 0],
"axis": [0, 0, 1],
"period": 2
},
{
"type": "hinge",
"a": "crank",
"b": "rod",
"at": [0, 1, 0],
"axis": [0, 0, 1]
},
{
"type": "hinge",
"a": "rod",
"b": "piston",
"at": [0, 4, 0],
"axis": [0, 0, 1]
},
{
"type": "slide",
"a": "block",
"b": "piston",
"axis": [0, 1, 0]
}
]
}The machine they move, whole:
Show the spec
{
"title": "Crank and piston",
"palette": {
"frame": {
"dark": "#9fb3d1",
"light": "#5a6d8f"
},
"crank": {
"dark": "#ff8a5b",
"light": "#d0612f"
},
"rod": {
"dark": "#5b9dff",
"light": "#2f6fd0"
},
"piston": {
"dark": "#ffd166",
"light": "#a87d00"
}
},
"nodes": [
{
"id": "block",
"shape": "label",
"position": [0, 0, 0]
},
{
"id": "base",
"shape": "box",
"parent": "block",
"position": [0, -1.6, 0],
"size": [3.2, 0.25, 1.8],
"color": "frame"
},
{
"id": "pedestal",
"shape": "box",
"parent": "block",
"position": [0, -0.85, -0.35],
"size": [0.6, 1.3, 0.5],
"color": "frame"
},
{
"id": "bearing",
"shape": "cylinder",
"parent": "block",
"position": [0, 0, -0.35],
"rotation": [90, 0, 0],
"size": [0.7, 0.5, 0.7],
"color": "frame"
},
{
"id": "cylinder",
"shape": "cylinder",
"parent": "block",
"position": [0, 3.3, 0],
"size": [1.5, 3.6, 1.5],
"color": "frame",
"style": "glass"
},
{
"id": "crank",
"shape": "box",
"position": [0, 0.5, 0.15],
"size": [0.35, 1.5, 0.15],
"color": "crank",
"label": "Crank"
},
{
"id": "rod",
"shape": "box",
"position": [0, 2.5, 0.35],
"size": [0.25, 3.3, 0.12],
"color": "rod",
"label": "Rod"
},
{
"id": "piston",
"shape": "cylinder",
"position": [0, 4, 0],
"size": [1.2, 1, 1.2],
"color": "piston",
"label": "Piston"
}
],
"joints": [
{
"type": "hinge",
"a": "block",
"b": "crank",
"at": [0, 0, 0],
"axis": [0, 0, 1],
"period": 2
},
{
"type": "hinge",
"a": "crank",
"b": "rod",
"at": [0, 1, 0],
"axis": [0, 0, 1]
},
{
"type": "hinge",
"a": "rod",
"b": "piston",
"at": [0, 4, 0],
"axis": [0, 0, 1]
},
{
"type": "slide",
"a": "block",
"b": "piston",
"axis": [0, 1, 0]
}
]
}- A machine has one motor, and every other joint follows it. Each part must be held so that the motor alone decides where it is: a part on a single hinge and nothing else swings freely.
- The distances between a part’s joints stay as you placed them: a rod is as long as the distance between its two pins. So place every part in a real position of the machine.
- A node that is the
bof a joint has no parent and no spin, orbit or bob: the joints move it. Apply takes them off and keeps the node where it was. Its children move with it, so build the details of a part as its children. - Apply also says when a machine cannot move as it should: a joint that misses its parts, nothing driving it, motors fighting each other, loose parts, jams, or a part that flips partway through its cycle.
- Gears meshing, chains, belts and cams cannot be joints. Show them with parts that turn at matching periods.
Steps
Steps are the guided walkthrough, like a narrated tour. The scene opens on the first one, so it is usually an introduction to the whole scene.
titletext, up to 80 characters · default none- A short heading.
texttext, up to 600 characters · default none- A sentence or three. A step with neither title nor text is dropped.
focuslist of ids · default[]- The nodes and paths the step is about. They are highlighted and framed while the rest dim; a node’s children are included, and so are links between focused nodes. Empty is the whole scene.
viewobject · default the camera keeps its direction- From where the camera shows the focus:
sideis one offront(the +z side),front-right,right(the +x side),back-right,back,back-left,leftandfront-left;heightislow,above(the usual three-quarter view) orhigh. The camera flies there and frames the focus. setobject · default no changes- What the step changes while it is on. See below.
motionobject · default normal time- How time runs while it is on. See below.
Changes
A step can change the scene while it is on, and the viewer eases from each step to the next. Each step keeps the scene as the step before it leaves it, plus its own changes: what a step changes stays so in the steps after it until a step sets it again, so a step says only what changes in it, and says when something ends.
nodes: items with a node’sidand any ofposition,rotation,size,colorandopacity. Position and rotation are relative to the parent, as in the node. A step’s opacity reaches the node’s children too, so a whole assembly fades with its parent.links: items withfrom,toandflow(true or false).paths: items withidandflow.- Nothing else changes: not a node’s shape, model, style, parent, label or animations, and nothing is added or removed. To have something turn into something else, build both and show one or the other with opacity. A part of a machine stays where its joints hold it, and a node with moves of its own where they put it: a step can change only the color and opacity of either.
Motion
speed0 to 4 · default1- 1 is normal speed, 0.25 slow motion, 0 holds everything still.
from, toseconds · default none- A stretch of the scene’s clock to replay over and over, both or neither. Equal, they hold the scene at that moment.
The clock starts at 0 with the scene as built, and everything that moves keeps time by it: joints, moves, animations and flows. A motor with a period of 2 makes half a turn in the first second; a ball whose first move takes 1 second lands as it ends.
A step that opens up a lamp to show current heating its filament, at half speed:
{
"title": "Inside the bulb",
"text": "Current flows through the thin filament, which heats up until it glows.",
"focus": ["filament"],
"view": {
"side": "front-right",
"height": "above"
},
"set": {
"nodes": [
{
"id": "bulb-glass",
"opacity": 0.1
},
{
"id": "filament",
"color": "filament-hot"
}
],
"links": [
{
"from": "battery",
"to": "filament",
"flow": true
}
]
},
"motion": {
"speed": 0.5
}
}Limits
A scene keeps up to:
- 300 nodes, 600 links and 200 joints;
- 60 paths of 500 points each;
- 20 steps; and
- 200 palette colors.
What goes beyond them is left out, and Apply says so. Texts are cut short at their lengths above; a scene’s title at 120 characters and its summary at 600.
Model library
A node’s model can name any of 910 ready-made objects, from a heart to a hammer to a hatchback. The Model library shows each of them, by category, with the id to name it by.
A full example
The lithium atom, one of the built-in scenes, as the Spec sidebar shows it:
Show the spec
{
"title": "Lithium atom",
"summary": "A dense nucleus of protons and neutrons, with electrons bound to it in shells. Lithium has three of each charged particle.",
"palette": {
"nucleus": {
"dark": "#ffd166",
"light": "#ab820a"
},
"proton": {
"dark": "#ff5d5d",
"light": "#f04f51"
},
"neutron": {
"dark": "#9aa7bd",
"light": "#7c889e"
},
"inner-shell": {
"dark": "#3d6bb3",
"light": "#3d6bb3"
},
"electron": {
"dark": "#5b9dff",
"light": "#4788e9"
},
"outer-shell": {
"dark": "#2f8f86",
"light": "#2b8c83"
},
"valence-electron": {
"dark": "#4dd8e6",
"light": "#1397a3"
},
"attraction": {
"dark": "#8fa3c7",
"light": "#6b7fa1"
}
},
"nodes": [
{
"id": "nucleus",
"shape": "sphere",
"position": [0, 0, 0],
"size": [2.4, 2.4, 2.4],
"color": "nucleus",
"style": "glass",
"label": "Nucleus",
"description": "Holds almost all of the atom’s mass in a tiny volume. The strong force binds its protons and neutrons together.",
"animations": [
{
"type": "pulse",
"period": 3,
"amount": 0.04
}
]
},
{
"id": "p1",
"shape": "sphere",
"parent": "nucleus",
"position": [0.42, 0.3, 0.2],
"size": [0.7, 0.7, 0.7],
"color": "proton",
"label": "Proton",
"description": "Positively charged. The number of protons (3) is what makes this lithium."
},
{
"id": "p2",
"shape": "sphere",
"parent": "nucleus",
"position": [-0.45, 0.22, -0.2],
"size": [0.7, 0.7, 0.7],
"color": "proton",
"description": "Positively charged. The number of protons (3) is what makes this lithium."
},
{
"id": "p3",
"shape": "sphere",
"parent": "nucleus",
"position": [0, -0.5, 0.3],
"size": [0.7, 0.7, 0.7],
"color": "proton",
"description": "Positively charged. The number of protons (3) is what makes this lithium."
},
{
"id": "n1",
"shape": "sphere",
"parent": "nucleus",
"position": [0, 0.05, -0.05],
"size": [0.7, 0.7, 0.7],
"color": "neutron",
"description": "No charge. Neutrons add mass and help hold the nucleus together."
},
{
"id": "n2",
"shape": "sphere",
"parent": "nucleus",
"position": [0.2, 0.4, -0.5],
"size": [0.7, 0.7, 0.7],
"color": "neutron",
"label": "Neutron",
"description": "No charge. Neutrons add mass and help hold the nucleus together."
},
{
"id": "n3",
"shape": "sphere",
"parent": "nucleus",
"position": [-0.3, -0.3, -0.45],
"size": [0.7, 0.7, 0.7],
"color": "neutron",
"description": "No charge. Neutrons add mass and help hold the nucleus together."
},
{
"id": "n4",
"shape": "sphere",
"parent": "nucleus",
"position": [0.45, -0.3, -0.25],
"size": [0.7, 0.7, 0.7],
"color": "neutron",
"description": "No charge. Neutrons add mass and help hold the nucleus together."
},
{
"id": "shell-1",
"shape": "label",
"position": [0, 0, 0],
"rotation": [0, 0, 18]
},
{
"id": "shell-1-path",
"shape": "torus",
"parent": "shell-1",
"position": [0, 0, 0],
"size": [7, 0.04, 7],
"color": "inner-shell"
},
{
"id": "e1",
"shape": "sphere",
"parent": "shell-1",
"position": [3.5, 0, 0],
"size": [0.4, 0.4, 0.4],
"color": "electron",
"style": "glow",
"label": "Electron",
"description": "One of two electrons that fill the innermost shell.",
"animations": [
{
"type": "orbit",
"period": 4
}
]
},
{
"id": "e2",
"shape": "sphere",
"parent": "shell-1",
"position": [-3.5, 0, 0],
"size": [0.4, 0.4, 0.4],
"color": "electron",
"style": "glow",
"description": "One of two electrons that fill the innermost shell.",
"animations": [
{
"type": "orbit",
"period": 4
}
]
},
{
"id": "shell-2",
"shape": "label",
"position": [0, 0, 0],
"rotation": [28, 0, -32]
},
{
"id": "shell-2-path",
"shape": "torus",
"parent": "shell-2",
"position": [0, 0, 0],
"size": [12, 0.04, 12],
"color": "outer-shell"
},
{
"id": "e3",
"shape": "sphere",
"parent": "shell-2",
"position": [6, 0, 0],
"size": [0.4, 0.4, 0.4],
"color": "valence-electron",
"style": "glow",
"label": "Valence electron",
"description": "Alone in the outer shell and weakly held, so lithium gives it up easily. That is why lithium is so reactive.",
"animations": [
{
"type": "orbit",
"period": 7
}
]
}
],
"links": [
{
"from": "nucleus",
"to": "e3",
"label": "electric attraction",
"color": "attraction",
"width": 1
}
],
"steps": [
{
"title": "Lithium atom",
"text": "An atom is a dense nucleus with electrons bound to it in shells. Lithium has three protons and three electrons.",
"focus": []
},
{
"title": "The nucleus",
"text": "Three protons (red) and four neutrons (grey) are packed into the center. The protons give it a charge of +3.",
"focus": ["nucleus"]
},
{
"title": "Inner shell",
"text": "The first shell can hold only two electrons. It is full, and these electrons are tightly bound.",
"focus": ["nucleus", "shell-1"]
},
{
"title": "Valence electron",
"text": "The third electron has to sit in a second, more distant shell. It is the one that takes part in chemistry.",
"focus": ["nucleus", "shell-2"]
}
]
}