Docs / Building Blocks

Building Blocks

Every object on the board that is not one of the built-in shapes is composed from building blocks: a small, closed set of approved primitives, modifiers, behaviours and components held in one registry. A clock, a compass, a speedometer, a thermometer and a steering wheel are all the same circles, arcs, lines, text and rotations, arranged differently. Nothing draws outside the registry, and no object carries code.

Building an object? The recipe is on Object Definition, and every block with its properties, defaults and ranges is on Block Reference. This page is the why and the how.

The five layers

A block is a named, registered building unit with a declared input schema. There are four kinds, and objects made of them are the fifth.

LayerWhat it isExamples
PrimitivesThe things that actually draw. Each one is a pure function from resolved values to one SVG tag.circle, rect, ellipse, line, polyline, polygon, arc, ring, path, text, image, group
ModifiersTransforms and paint applied to a node and everything under it.translate, rotate, scale, mirror, opacity, visibility, stroke, fill, z-order, repeat
BehavioursWhat the reader can do to a node, and what that writes.clickable, drag-angle, drag-rotate, drag-circle-point, press-and-slide, drag-axis-tick, keep-time, follow-pointer, remember, track-pointer, tooltip
BindingsWhere a value comes from, declared rather than computed.constant, parameter, variable, expression, formula, token, format, choose, concat, direction, memory, termUnit, termName, model
ComponentsReady-made assemblies that compose the layers above, from a tick ring to a whole clock. An object is itself a component, so one can be reused inside another.dial-face, tick-ring, label-ring, pointer-hand, key-cap, seven-segment-display, plot-grid, plot-axes, plot-crosshair, memory-list, memory-trace, clock, compass, speedometer, circular-gauge, rotating-vector, orbit-system, steering-wheel, thermometer, calculator, mouse-tracker, ruler, protractor, trigonometric-circle

How a drawing is made

The spine is the same for every object on the board. The shape holds the values, the compiler turns the definition into render nodes, and the renderer writes the SVG once.

StepWhat happens
1. The shapeA ComponentShape on the board holds the object's parameter values in its own properties — which is why an object gets undo/redo, copy/paste, collaboration and saving with nothing written for the purpose.
2. The compilerBlockCompiler evaluates the definition's locals, drops the children whose when is false, expands repeat, resolves every binding and walks down to primitives.
3. The rendererBlockRenderer builds every tag itself and escapes every value. No markup from a definition ever reaches the page.
4. The interactionA behaviour writes exactly one command — a property of the shape, or a model variable through the calculator — and the next compilation reads it back. That is why a whole drag is a single undo entry and why no object has a redraw path of its own.

Values that change on their own — a model variable, the iteration on screen, the object's own size — arrive as bindings, so a definition never subscribes to anything or schedules a redraw. Bind a property to a variable and the object follows the simulation.

There is no eval anywhere on this path, and no JavaScript in a definition. Formulas are Modellus LaTeX, parsed by the same parser the expression shapes use. A block type the registry does not hold is refused by the compiler and by the validator alike.

An object is one JSON document

A new object is a single JSON document: no JavaScript, no markup, no file to wire up. It declares what the reader can edit (parameters), what it works out for itself (locals) and what it draws (root).

{
    "schemaVersion": "1.0.0",
    "type": "my-object",
    "category": "component",
    "displayName": "My object",
    "description": "One sentence, written for the person choosing it from the palette.",
    "icon": "fa-light fa-circle-notch",
    "tags": ["object"],
    "parameters": [ … ],
    "locals":     [ … ],
    "root":       { "id": "my-object", "type": "group", "children": [ … ] }
}

The same document is what the editor bundles, what the community catalogue publishes, what the assistant invents and what a model carries with it. Nothing about the object depends on which way it arrived. The full recipe, field by field, is on Object Definition.

Where an object comes from

SourceHow it gets thereWho sees it
BundledA JSON file the editor ships withEveryone, offline included
Community cataloguePublished under Assets → Objects, fetched when placedAnyone whose palette reads the catalogue
Invented on a boardThe assistant's save_custom_component, or Copy definition from an object's settings menuThe model that uses it
Carried by a modelThe model file's own objects sectionWhoever opens that model, anywhere

An object the editor does not ship with travels inside the model that uses it, so a board can invent one and a colleague can open the file and see it. A document naming a type the editor already ships is refused, deliberately: a model cannot freeze a bundled object at an old version.

Three ways to build one

WayWhat you do
Start from an object that existsPlace one from the Objects palette, set it up, then Copy definition in its settings menu and edit the JSON.
Write the documentFollow Object Definition and paste the result into the object editor in the catalogue, or bundle it with the editor.
Ask the assistantDescribe the object. The assistant composes it through the block tools, validates it and inserts it — and what it produces is an ordinary object, fully editable.

Drawing rather than writing is the fourth way in for the parts that are illustration: an SVG file can be converted into primitive nodes and pasted into the document, wired by the ids in the drawing. It is converted, not embedded — nothing new reaches the renderer.

The look is not the object's to invent

An object drawn from blocks has to look like the board it stands on, and the board already has a look: the font it writes in, the grey its axes are drawn in, the length of a tick, the dash of a crosshair, the plate a value is read on. Those numbers are the design tokens, and the chart, the ruler and the referential read the same ones — so an object drawing against a scale is the same grey as a chart beside it.

Two rules follow, and together they mean no definition ever names a font or an axis colour:

Because the tokens are one table, a preset restyles every object at once. Five ship with the editor: standard, minimal, scientific, classroom and high-contrast, and every value in each is listed on Block Reference.

What an object can do

CapabilityHow
Read the modelA variable binding, or an expression over model variables. The object redraws with the simulation.
Scale with its boxThe reserved parameters $width and $height, read through a local, so geometry is worked out from the size the reader dragged.
Be driven by handdrag-angle, drag-rotate, drag-circle-point, press-and-slide, clickable and drag-axis-tick write a model variable — or the object's own parameter when the row holds a plain number instead of a term.
Refuse to be drivenNothing switches interaction on or off: a row naming a term the model works out for itself is read-only, and says so with the cursor a locked handle uses.
RememberA memory parameter holds rows of { text, x, y }, filled by remember, track-pointer or a key, and read back by memory-list or memory-trace. It lives in the shape, so the file carries it and undo restores it.
Replay a recordingA memory declaring termParameters makes row n iteration n of those terms, so the board's player replays it and everything bound to them moves along.
Follow the pointerfollow-pointer reports where the cursor is into parameters the definition names, without writing anything down — no edit, no undo entry, no changed file — and stops while the player runs.
Count real timekeep-time runs a clock of its own, so it goes on counting while the model stands still, and the whole run is one undo entry.

What is checked before an object is drawn

A definition passes two gates. Registration reads the document; validation reads the tree it compiles to. An object cannot be published from the catalogue, inserted by the assistant or saved as a component until both are clean.

GateRefuses
RegistrationAn unsupported schemaVersion, a type outside ^[a-z][a-z0-9-]{2,48}$ or already shipped, a category other than component, a missing root, a parameter or local without an id, a local colliding with a parameter or an earlier local, and any formula reading a name the document does not declare.
ValidationUnknown block types, bindings on properties that do not accept them, variables that do not exist (with the nearest name suggested), expressions that do not parse, the runtime limits, and a visual pass: nothing drawn, everything invisible, zero-size interactive targets, nodes far outside the box.

The runtime limits are 2 000 nodes, 16 levels of nesting, 8 levels of component nesting, a repeat count of 720, 512 characters per expression and 2 000 memory rows. Image sources are limited to https:, data:image/ and relative paths; path data must match the SVG path grammar.

Where to go next