The first visual code that draws. Sections 17.4 through 17.14 are implemented
against Format Specification revision 0.8, and the standalone artifact now has a
stage canvas that renders a declared scene.
The renderer is split so that the automated traces of 17.16 can run without a
display, which is what those traces require. visual-engine.js resolves an
exhibit's objects once at their instantiation boundary, composes the
scene-to-device chain, sorts by depth, applies fog and the compositing order,
and emits a **frame plan** in device pixels; visual-canvas2d.js turns a plan
into drawing calls. A plan carries the numeric oracles the traces ask for - a
known scene point at a known display point, a perspective factor, a fog
fraction, a sort order - where a canvas carries only pixels.
visual-math.js implements the affine matrices, the normative local transform of
17.11, the directed arc sweep of 17.9 with its bound checked before
normalization, and section 2 color parsing with the fog and ramp arithmetic of
17.6 and 18.2. Colors outside the four documented forms are ERR_TYPE_MISMATCH:
exact components are what make per-object fog renderer-independent.
visual-geometry.js reduces all fourteen primitives to subpaths of lines and
cubic Beziers, so an affine map carries geometry exactly rather than
approximately. It implements the local extents and anchors of 17.9 - a
rectangle anchored top-left, circular primitives centered - the uniform cardinal
form of catmull-rom with its open-duplication and closed-wrap index rules, the
straight closing segment of a closed bezier spline, and endpoint-parameterized
elliptical arcs.
The composition chain of 19.3 is implemented as written: the fit matrix carries
the contain and cover centering offsets, the camera center is mapped into CSS
coordinates before the translation is formed, perspective acts about the
projection center, and the device-pixel multiplier is applied exactly once and
drops below 1 on a display larger than 4096. Scalars with no axis - stroke
widths, radii, dash lengths - take the single uniform factor g, so a nonuniform
stretch never distorts a stroke.
Depth follows 17.6: effective depth accumulates z and translate.z up the tree,
sortable units order farthest-first with the documented tie-break, a point's own
z projects that point without making it a sortable unit, and an object at or
behind the eye is culled with no diagnostic. Compositing follows 17.12: opacity
multiplies down the tree while layer opacity applies once at the layer, and the
sixteen buffer allocations per frame are granted nearest-first so refusals fall
on the far content, each diagnosed under the 19.5 cadence rather than omitted
silently.
visual-validation.js gains the object tree: the fifteen object types and their
declared fields, no `id` and no `layer` on an object, a declared fill on a
stroke-only primitive, a mask only on a group and only naming its own child,
path legality, spline modes and point counts, gradient stop order, and every
authoring limit of 19.5 that applies to a drawn object.
While implementing V10 I corrected the buffer-accounting rule I had written into
17.12: counting buffers as concurrently live made 19.5's farthest-first shedding
nearly unreachable, since group nesting is already capped at 8. The rule is now
16 allocations per frame, which is the per-frame reading "pass budget" has
carried since 17.5 first used it. The arc-sweep prose is likewise corrected to
normalize the signed delta, so 350 -> 10 clockwise is the 20-degree sweep the
text always claimed rather than 340 the long way round.
test/phase4-renderer.test.mjs adds 22 tests covering traces 1 through 13 of
17.16 plus buffer shedding and the backend's call order. npm test goes from 131
to 153 passing. Traces 15 and 16 remain user-observed, and no procedural system,
automation track, or post-effect executes yet - 4e and 4f own those.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0162Jb1J36judZNT8fHabGVt
Stage 0 of the five-stage plan in reviews/02-application-code-triage.md: the
shared pre-renderer alignment that has to land before slice 4d writes renderer
code, so the runtime foundation and Format Specification revision 0.8 cannot
drift while three slices are built on top of them. Nothing here draws.
The JSON Schema's `visuals` definition was a Phase 0 stub of `camera`,
`systems`, and `passes`. It is replaced by the real container - scene, layers,
systems, fields, camera, effects, and the exhibit-scope `automation` array that
17.3 previously rejected while 19.1 authorized. Fourteen new definitions cover
visual objects, paints, styles, transforms, behaviors, distributions, trails,
links, automation tracks, the spawn container, and visual components, and
`components.visual` is no longer an unconstrained object. Structural exclusions
carry the contract's own prohibitions: no `id` on a visual object, no `links` on
an emitter, no `trail` on a render object, and none of the four spawn-only
lifecycle names at a system's top level.
src/runtime/visual-contract.js is new and plays the role audio-contract.js
plays for sections 14-16: the primitive, system, behavior, field, distribution,
blend, filter, and post-effect vocabularies; the post-effect parameter tables
with their ranges and pass costs; the centralized ceiling table of 19.5 split
into authoring bounds and runtime ceilings; and matchVisualTarget, which
resolves a path against the four section 8.1 visual target families and
distinguishes a dangling reference from a target that exposes no capability.
src/runtime/visual-validation.js is new and validates the shared surface: the
visuals container, the scene model including the conditional viewport `fit`
rule, layers including the rule that a present layer map makes a system's
`layer` required, the common system fields and the `spawn` container,
procedural fields including the conditional noise `direction`, the post-effect
chain, and visual automation with its two declaration scopes, its automatable
registry, its loop modes, and its authoring bound. Type-specific system fields
are carried through unvalidated and are tightened by 4d, 4e, and 4f.
The resolution engine now exposes the four visual families. `target()` returns a
capability record with a per-family stage table, replacing the hardcoded
`namespace === 'buses'` test for the automation and modulation stages, so a
boolean system `visible` correctly has neither. Visual bases sample once from
the `visual` stream domain at the exhibit-scope instantiation boundary, fall
back to their documented defaults - including the scene center for an
unauthored camera position - and clamp through the shared 8.1 safety stage, so
a `focalLength` that resolves below 1 becomes 1 rather than dividing by zero.
`requireAudioStage` becomes `requireStage(path, stage)` with the old name kept
as its automation wrapper.
The validator's binding-target check is no longer a regex over two families. It
reports ERR_INVALID_REFERENCE for an undeclared layer, system, or effect index
and ERR_UNSUPPORTED_TARGET for everything outside the four rows - per-object
properties, field strengths, emitter rates - which is the distinction trace 14
of 17.16 and trace 4 of 19.7 both check.
exhibits/minimal-visual.xzbt is a new fixture exercising the aligned surface:
two layers, a graphic system with system-scope automation, a repeater over a
component, a particle system reading a declared field, a spawned emitter with
its spawn container, two post-effects, and three bindings reaching three of the
four target families.
test/phase4-visual-contract.test.mjs adds 29 tests. `npm test` goes from 102 to
131 passing with zero failures; no existing test changed.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0162Jb1J36judZNT8fHabGVt
Review Phase 3a before building on it, then implement Phase 3b.
The Phase 3a draft had four blocking defects: nodes were described as a
keyed map while every documented example carried an inline `id` field,
so under the strict unknown-field policy each minimal example would have
failed its own acceptance trace; no section said where a node lives; the
`audioMaxFrequency` ceiling was declared a semantic-stage error while
depending on a live AudioContext sample rate; and the sample-hold PRNG
child key that section 9.3 requires was undocumented. Close all four,
plus nine further gaps in noise seeding, spectral definitions, impulse
decay math, Nyquist handling, missing-field codes, LFO phase origin, the
units table, node-type staging, and a duplicated diagnostics table.
Add Format Specification section 15 for Phase 3b: nine processing and
routing node contracts, the component instance node, audio routing and
modulation with an explicit modulatable-property registry, twelve graph
legality rules, authoring limits, components with a component-scoped
`inputs.*` namespace, sound definitions and recipes, and buses.
Implement the subsystem in three modules. audio-contract.js holds the
declarative node, limit, and modulation tables every consumer reads.
audio-graph.js validates, expands components, and checks legality
without ever opening an AudioContext. audio-engine.js resolves node
fields once from the seeded stream, clamps frequencies to the live
device ceiling, realizes the graph through Web Audio, and owns the
runtime AudioSubsystem. Extend the schema, delegate the standalone
validator's audio checks to the shared module rather than carrying a
second implementation, and add a generic audio fixture.
Phase 3 is not accepted. Automation precedence, the lifecycle state
machine, unlock behavior, voice ceilings, and master protection are
Phase 3c. No sound has been heard from any build, so the audio
acceptance challenge, peak and finite-sample capture, and listening
observations remain open.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011FWPdCqKaaDnP9NC3JAwh6
- Record user evidence for directory fallback to complete GC1 (10/10 checks passed)
- Expand Format Specification 0.1 to Revision 0.2 with normative shared contracts
- Author JSON Schema Draft-07 at schema/xzbt-0.1.schema.json
- Implement zero-dependency semantic validator at tools/validate-exhibit.mjs
- Create 12-case conformance fixture suite and automated test runner (12/12 passing)
- Update implementation status, verification gates, and gap closure decisions
- Add devlog entry covering stall recovery and Phase 0 current state