The editor — how to work in the page

This is the help behind the ? key in the viewer. It is the workflow: what the panels are, how to start a new layout, add scenes, bring fixtures in, and pick or write patterns. The field-by-field reference is the authoring guide and FORMAT.md; the gentler tour is Getting started.

Open the editor at pixeldestrukt.github.io/voxeled/viewer/?static=1 (or viewer/ next to a running hub). Everything you make stays in this browser (IndexedDB) — nothing is uploaded; export a bundle to move it.

The page

panelopens withwhat it is
HUD (top-left)tap its title · Hscene name, counts, the view buttons, the crossfader. Folds to one line.
projectproject button · Pthe project: which one is open, the files in it, the layout text, bundles, a live hub.
builderbuilder button · Eplace things by hand: select an instance, move/rotate, duplicate, array, emitter, output patch, add instances, new fixture from a file.
helphelp button · ?this, condensed.
the viewdrag · scrollorbit and zoom. S simulator, B bloom, M model, N normals, R ropes, O orbit, V stand at a vantage, [ ] crossfade, A auto.
walkthe button · F · ?walk=1first person on this screen: WASD / arrows + mouse, or drag + a stick on a phone; gyro and a cardboard stereo split. The headset demo without a headset.
vr · arthe buttons (where the browser has WebXR) · Xwalk the piece at true scale in a headset; on a phone, stand it on your floor (tap where the ring lands). ?xrscale=0.1 for a tabletop model.

On a phone the HUD starts folded and the panels are sheets along the bottom.

A layout is the YAML in the project panel: fixtures (kinds of thing), instances (where they are), structures (the piece's own CAD), paths, inputs, controls, and the show (scenes). The page runs the same hub the Node server runs, so what you see is what a controller would get.

1. A new layout

  1. project → new — name it. You get a starter layout: one 8×32 panel and two scenes.
  2. Edit the layout text. apply runs it (an error shows under the buttons and names the field); 💾 save keeps it in this browser. Save often; save as… forks a copy, and an example opened from the list is read-only until you save as….
  3. Or start from an example in the project list (columns, ropes, site…) and save as….
  4. Or drop a .yaml on the page: it becomes the layout. Drop a *.voxeled.json bundle to open a whole project someone exported.

The smallest layout that lights up:

name: my-piece
fixtures:
  panel: { type: matrix, params: { cols: 32, rows: 8, pitchMM: 10, wiring: columns, start: top-left } }
instances:
  - { fixture: panel, name: panel-1, pos: [0, 1200, 0] }
show:
  scenes:
    - { name: chase, pattern: ribbonChase }

Units are millimetres, Y is up; pos places a fixture's origin, rotDeg: [x, y, z] turns it.

2. Scenes — the show

A scene is a pattern with parameters, under a name. The show cycles them (holdS seconds each, fadeS crossfade); the crossfader in the HUD scrubs between two by hand (A returns to auto), and a page in ?ui=bar mode shows them as a bar of buttons.

show:
  holdS: 6
  fadeS: 2.5
  scenes:
    - { name: rising, pattern: planeSweep, params: { speedMM: 400, spacingMM: 1200, widthMM: 250 } }
    - { name: helix,  pattern: helix,      params: { turns: 1, pitch: 3 } }
    - { name: comet,  pattern: comet,      params: { speed: 0.12, tail: 0.15 } }

Add a scene = add a line, apply. The crossfader's A/B labels follow the scene names, and the pattern bar (viewer/?…&ui=bar) lists them in order. To start a page on one: ?scene=helix.

Layers. A scene can be a stack — a generic pattern under, a specialised one only where it fits:

    - name: night
      layers:
        - { pattern: plasma }                                        # everywhere
        - { pattern: helix, on: { space: cylinder }, blend: add }    # only on tubes
        - { pattern: comet, on: { fixture: ropes }, blend: max, opacity: 0.8 }

on: is all, { fixture: … }, { instance: … } or { space: … }; blend: is over · add · max · multiply · screen. Every pattern says which space it reads (world, volume, fixture, strand, cylinder) and apply checks it against the fixtures: helix (a cylinder pattern) on a flat panel still runs, as a chase, but the layout carries a warning with the fix — put it on a layer with on:. GUIDE §3.5.

3. Fixtures — bringing LEDs in

A fixture is a kind of thing; instances place it (many times, if you like). Pick the route that matches what you have:

Primitives — type them. No files needed.

you havetypethe essentials
a panel, matrix, or strip laid in rowsmatrixcols, rows, pitchMM, `wiring: rows\columns, start corner, serpentine`
a strip, string or rope along a line or curveropepath (inline points [[x,y,z], …] or a named path), count or pitchMM; radiusMM + angleDeg around a tube; diffuserMM draws it as a lit tube
a flexible panel rolled into a tubetubecols around, rows along, panels, pitchMM
a video surface: an LED wall as an image, a projector, a monitorscreencols, rows (texels), widthMM; the same patterns light it; viewer/screen.html?instance=… is the fullscreen output (hub only)
one big LED / a lampdotsizeMM

From a file — the builder. builder → new fixture from a file: name it, choose the kind, give the file name and the scale (mm per unit; STL in metres = 1000), + create fixture & add one. Drop the file on the page first (or project → + add files…); a dropped file is found by its bare name, so file: ../models/frame.stl only needs frame.stl dropped in.

the filetypenotes
CAD with the LED chips modelled (STL/OBJ/GLB)meshone LED per chip body; the thin axis is the LED's normal. Check N; normalSign: -1 flips.
positions baked by Blender, Grasshopper, vox import, or export --barevxla .vxl.json — carries normals, strands, emitter
a glTF with points/normalsgltffile, scaleToMM (glTF is metres)
a Chromatik / LX model (.lxm, .lxf)—vox import model.lxm on the command line, then vxl

The same fixture is typed in the layout as fixtures: { name: { type, params: { file, scaleToMM } } }.

Place it. instances: lines (pos, rotDeg, or array: / ring: / along: to generate many), or the builder: click an instance, T move / R rotate with the gizmo (10 mm / 5° snaps) or type numbers, duplicate, delete, ▦ make array, + add another instance of any fixture.

Its look and its wire. The builder's emitter row (viewing angle, size, core, softness, gain, glow) is what the simulator draws; the output row (protocol · host · port · universe · channel · byte order) is the patch a hub sends. Tick apply to every … instance to set the fixture's default. The browser can't send UDP: to light real LEDs run the hub on a LAN computer (node examples/mobius-heart/run.mjs layout.yaml), then watch it here with ?ws=ws://<hub>:8080/bus.

Structures. The sculpture, frame or wall around the LEDs: structures: [{ file: frame.glb, scaleToMM: 1000, opacity: 0.35 }] on a fixture (rides with every instance) or at the top level. Translucent in dots mode, an occluder in the simulator (M cycles).

4. Patterns

A pattern is a function of each LED's real position and normal (and its place along its fixture or strand), not its index — so a wipe crosses the gap between two panels in real time and a spiral wraps a tube. Use them by name in show:; parameters in params:.

patternwhat it doesparams
ribbonChasea hue chase along each fixture's data orderloops, speed, sat
planeSweepplanes of light rising through everythingspeedMM, spacingMM, widthMM, hue
worldWipea plane wiping along an axis; space: world keeps the real gapsaxis, speedMM, spacingMM, widthMM, space, hue
helixa barber-pole stripe winding around a tube as it climbs (pitch: 0 = rings) — cylinderturns, pitch, speed, width, hue, hueAlong, dir
lanterna lamp carried through the room; sides facing it glow`path: orbit\eight, radiusMM, heightMM, speed, falloffMM, ambient`
swirlspiral arms over the floor about the piece's centrearms, spacingMM, speed, twist, wrap
dropsdrops falling down one side of each column — cylinderrate, speed, lengthS, spin
cometa comet bouncing down every strand with a tailspeed, tail, hue, hueStep, ambient
plasmalayered sine fields along each strandspeed, scale, hueDrift, sat
fireheat injected at LED 0 climbing each stringrate, cooling, seed
strandsone colour per strand (or per group) — the wiring at a glancegroup, hue, hueStep, sat
solidone colour everywherergb or hue, sat, value
normalRGBcolours each LED by its normal — the map made visible—
spotlight, projectoronly what a virtual camera sees; project a texture through itorbitDegPerSec, angleDeg, elevDeg, fovDeg
point, painta torch beam from a tracked wand / phone; a brush that leaves lightsee GUIDE §3.5
testCarda grid, border, centre cross and tinted quadrants on a screen — align a projectorcells, line, hue
(GPU)in the page the pure patterns also run as one GPU shader (?gpu=0 to turn it off); fire, paint, torch and visibility stay on the JS path—
sampleran image source on the pixels: map: uv (the fixture as the image), box (a plane in the world), projector (a beam) — GUIDE §3.8source, map, box, projector, filter, outside, gain

Your own. A pattern is code: (pixel, t, ctx) → [r, g, b] in 0..1, with pixel.p (mm), pixel.n, pixel.s / pixel.v (0→1 along / across its fixture), pixel.strand, pixel.inst, and ctx.scene. Add it to src/patterns.mjs and register it in PATTERNS; it is then a name any layout can use — in the Node hub, and in the page when you host your own copy of the viewer (scripts/vendor.mjs, STATIC.md). There is no loading of pattern files at run time yet.

Video. Declare sources in a video: block — { file: poster.png } (drop the file in), { file: clip.mp4 }, { url }, { camera: true }, { display: true } — and put a sampler on a scene or a layer. Stills and clips start on their own; the camera and a display capture start from the video sources row in the project panel (the browser asks once). A raw-frame stream is for the Node hub (ffmpeg → TCP). The screen example has a poster on its wall, as a plane the columns share, and projected from the back of the room.

5. Keep it, share it

Troubleshooting