docs(visual): specify the phase 4b component, procedural system, and behavior contract
Format Specification section 18 (PRD 77-84) closes slice 4b: visual components and their inputs scope, particle systems with a normative integrator and life ramps, the nine placement distributions, emitters with exact fractional-accumulator emission timing, repeaters and the copy-scoped repeat.* namespace, the seventeen-behavior vocabulary and its channel set, the six procedural fields with a normative coherent noise function, and trails, ribbons, and links. Seven diagnostic codes are added to the section 7 table. Section 17 is amended in four places the new section requires: the visuals.fields container, the component visual object type beside the closed fourteen primitives, the now-declared behaviors field, and the widened visual limit row. Revision 0.5 -> 0.6. Documentation only; no runtime, schema, fixture, or test file changed. npm test remains 102 passing. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019dTNHWyTdFobdevrKspoV6
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# Phase 4b evidence — Visual subsystem contract, part II (Format Specification section 18)
|
||||
|
||||
**Date:** September 6, 2026
|
||||
**Slice:** 4b — Contract II (documentation only; no runtime change)
|
||||
**Baseline:** `main` at `3e27a66` (Phase 4a, section 17)
|
||||
**Specification revision:** 0.5 → 0.6
|
||||
**PRD coverage:** 77-84
|
||||
|
||||
## What this slice fixes
|
||||
|
||||
Section 18 continues the Visual contract section 17 opened. It covers reusable visual components and
|
||||
their input scope, particle systems and the normative motion integrator, the nine placement
|
||||
distributions, emitters and exact emission timing, repeaters and the copy-scoped `repeat.*` namespace,
|
||||
the seventeen-behavior vocabulary and the channel set behaviors may write, the six procedural fields and
|
||||
the normative coherent-noise function behind them, and trails, ribbons, and links.
|
||||
|
||||
Section 19 (Phase 4c) remains the owner of visual automation, lifecycle and ownership, camera,
|
||||
post-processing, and the centralized ceilings. The forward references to 19.1, 19.2, and 19.5 are the
|
||||
only unresolved numeric references in section 18, and they close when 4c lands.
|
||||
|
||||
## Decisions taken, so 4e does not relitigate them
|
||||
|
||||
1. **`component` is a visual object type, not a fifteenth primitive.** Visual Primitive Set 0.1 stays
|
||||
closed at the fourteen geometry primitives section 17.9 fixed. Section 18.1 adds `component` beside
|
||||
that set, exactly as 15.11 added a `component` node beside the audio node set 14.3 opened, so a
|
||||
component instance can be placed inline in any `content` or `children` container instead of only
|
||||
being reachable through a repeater of count one.
|
||||
2. **Visual component parameters admit four types, audio's admit one.** `number`, `boolean`, `string`,
|
||||
and `color` — the shared scalar types of section 2. The audio contract (15.15) permits only `number`
|
||||
because an audio node field is always numeric; a visual field may be a color, a label, or a
|
||||
visibility flag. `min`, `max`, and `unit` remain number-only.
|
||||
3. **`inputs.*` and `repeat.*` are construct-scoped, not document namespaces.** Both follow the rule
|
||||
15.15 fixed for audio components: legal only inside their construct, `ERR_INVALID_REFERENCE`
|
||||
anywhere else, absent from the section 1.3 namespace list, and granting no section 8.1 capability.
|
||||
4. **A component's expansion path, not its ID, is its stable instance key** for section 9.3 stream
|
||||
derivation. Two instances of one component therefore sample independently, and reordering unrelated
|
||||
siblings does not perturb either — the same property 14.12 gives audio components.
|
||||
5. **Particle motion has a normative integrator.** Semi-implicit Euler, velocity before position, with
|
||||
drag as `(1 - drag)^dt` so it is tick-length independent. A renderer that integrates position first,
|
||||
or applies drag once per tick regardless of `dt`, produces visibly different motion at a different
|
||||
tick rate and does not conform. Traces 5 and 6 pin both halves.
|
||||
6. **Life ramps interpolate resolved endpoints; they do not re-sample.** `size`, `opacity`, and `color`
|
||||
may ramp over normalized age using the same four curves PRD 85 fixes for automation. `from` and `to`
|
||||
resolve once at particle creation, so 17.14 and 9.3 hold unchanged: rendering still consumes no
|
||||
procedural stream. This is what gives PRD 78 its `age` property without breaking reproducibility.
|
||||
7. **Emission timing is a fractional accumulator, not a per-tick rounding.** Cumulative count after `t`
|
||||
seconds at a constant rate is `floor(rate * t)` exactly, under any tick length, with no drift and no
|
||||
reset when automation changes the rate later.
|
||||
8. **Unbounded emission fails validation.** A system that declares emission but neither a per-item
|
||||
`lifetime` nor a total `limit` is `ERR_UNBOUNDED_EMISSION`. An initial `count` with no `lifetime`
|
||||
stays legal — a fixed starfield that never expires is the common case, not the dangerous one.
|
||||
9. **Pool exhaustion evicts oldest-first**, mirroring the voice eviction of 16.6, and is silent at the
|
||||
system level. The aggregate ceiling across systems and its diagnostic belong to 19.5.
|
||||
10. **Index-driven placement needs a known count.** `even` modes and the `grid` type place item `i` of
|
||||
`n`, so they are legal in a repeater and in a fixed `count` or `burst` population and are
|
||||
`ERR_INVALID_DISTRIBUTION` on continuous `rate` emission. Distribution sample-consumption order is
|
||||
normative (`x`, then `y`, then `z`; angle before radius) so fixtures place identically everywhere.
|
||||
11. **Coherent noise is specified, not left to the renderer.** Three-dimensional gradient noise on the
|
||||
integer lattice, twelve edge-midpoint gradients, a `256`-entry permutation shuffled from the field's
|
||||
own stream at instantiation, and the quintic fade `6u^5 - 15u^4 + 10u^3`. Reproducibility (9.3)
|
||||
promises identical decisions rather than identical pixels, but a field that drove motion differently
|
||||
on two conforming renderers would make a fixture untestable, so the function itself is pinned.
|
||||
`curl` is the default mode because it is divergence-free and will not pile items into a point.
|
||||
12. **Ribbons are a trail render mode, not a separate system type.** A ribbon is the same history buffer
|
||||
drawn with area instead of a stroke, so `trail.mode` is `line`, `ribbon`, or `points`. PRD 84 is
|
||||
satisfied without a fourth procedural system.
|
||||
13. **`links` is illegal on an emitter.** A `particles` system and a `repeater` have bounded, known
|
||||
populations; an emitter's changes continuously and its pair search would have to be rebuilt every
|
||||
tick at exactly the cost the ceiling exists to prevent. All three PRD 84 rules — `distance`,
|
||||
`nearest`, `index` — are specified, with `distance` the required 0.1 minimum.
|
||||
14. **Behaviors write internal channels; they do not extend section 8.1.** The `property` channel set of
|
||||
18.6 is a behavior's own permitted write set. External addressability of visual properties remains a
|
||||
section 19.1 decision, and a binding, `set`, or `override` naming anything introduced here is still
|
||||
`ERR_UNSUPPORTED_TARGET`.
|
||||
15. **The morph rule section 17.13 deferred is now fixed:** equal `type`, equal point count, and equal
|
||||
spline `mode`, with `ERR_MORPH_INCOMPATIBLE` on any mismatch. Resampling one shape onto another's
|
||||
point count would change the geometry the author wrote, so it fails validation instead.
|
||||
|
||||
## Amendments to section 17
|
||||
|
||||
Four, all consequences of this slice rather than corrections:
|
||||
|
||||
- **17.3** gains a `fields` row for the `visuals.fields` container. Without it the strict unknown-field
|
||||
policy would make every declared field `ERR_UNKNOWN_FIELD`.
|
||||
- **17.9** records that Visual Primitive Set 0.1 is closed at fourteen and that 18.1 adds the
|
||||
`component` object type beside it.
|
||||
- **17.10**'s `behaviors` row no longer reads "Rejected as `ERR_UNKNOWN_FIELD` until section 18 declares
|
||||
them"; it now carries the `0` to `8` bound.
|
||||
- **17.15**'s local `ERR_VISUAL_LIMIT_EXCEEDED` row names the procedural-system ceilings this section
|
||||
adds.
|
||||
|
||||
No decision recorded in section 17 was reversed.
|
||||
|
||||
## New diagnostic codes
|
||||
|
||||
Seven were added to the section 7 table, which remains the single authoritative list:
|
||||
`ERR_INVALID_DISTRIBUTION_TYPE`, `ERR_INVALID_DISTRIBUTION`, `ERR_INVALID_BEHAVIOR_TYPE`,
|
||||
`ERR_INVALID_BEHAVIOR_TARGET`, `ERR_INVALID_FIELD_TYPE`, `ERR_MORPH_INCOMPATIBLE`, and
|
||||
`ERR_UNBOUNDED_EMISSION`. Section 18.9 repeats them for locality, exactly as 15.18, 16.10, and 17.15 do.
|
||||
|
||||
`ERR_COMPONENT_RECURSION` is reused for visual component recursion and over-nesting rather than
|
||||
duplicated under a visual name, along with `ERR_VISUAL_LIMIT_EXCEEDED`, `ERR_INVALID_REFERENCE`,
|
||||
`ERR_INVALID_RANGE_ORDER`, `ERR_OUT_OF_BOUNDS`, `ERR_TYPE_MISMATCH`, `ERR_UNKNOWN_FIELD`,
|
||||
`ERR_SCHEMA_VALIDATION`, and `WARN_AUTOMATION_FALLBACK`.
|
||||
|
||||
## Authoring limits fixed in this slice
|
||||
|
||||
| Limit | Bound | Diagnostic |
|
||||
| --- | --- | --- |
|
||||
| Visual component nesting depth | 8 (matches audio, 15.14) | `ERR_COMPONENT_RECURSION` |
|
||||
| Particle `capacity` per system | 4096 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Emitter `capacity` per system | 512 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Repeater `count` | 1024 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| `burst` entries per system | 16 | `ERR_SCHEMA_VALIDATION` |
|
||||
| Behaviors per object | 8 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Declared fields per exhibit | 8 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Fields referenced per system or behavior | 4 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Noise `octaves` | 4 | `ERR_OUT_OF_BOUNDS` |
|
||||
| Grid `columns` / `rows` | 256 each | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Trail `length` | 128 samples | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Links per system per tick (`maxLinks`) | 1024 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Statically known population under a pairwise link rule | 256 | `ERR_VISUAL_LIMIT_EXCEEDED` |
|
||||
| Nearest-neighbour links per item (`count`) | 8 | `ERR_SCHEMA_VALIDATION` |
|
||||
|
||||
These are authoring bounds a document must satisfy at validation. The aggregate runtime ceilings —
|
||||
total active particles, total spawned systems, total links, total field evaluations, and the per-tick
|
||||
budget they share (PRD 89, 120) — remain slice 4c and are not set here. Slice 4h is what determines
|
||||
whether these bounds are the right ones.
|
||||
|
||||
## Verification performed
|
||||
|
||||
This slice changes documentation only. No runtime source, schema, fixture, or test file was touched.
|
||||
|
||||
- Every diagnostic code used in section 18 (19 distinct codes) resolves to a row in the section 7 table;
|
||||
zero unresolved, checked programmatically.
|
||||
- Every numeric cross-reference in section 18 resolves to an existing heading, except the intended
|
||||
forward references to 19.1, 19.2, and 19.5.
|
||||
- All code fences in section 18 are balanced and every table row is well formed.
|
||||
- `npm test` passes 102 tests with zero failures, confirming the existing suite is unaffected.
|
||||
- The section 11 contract register's Visuals row now reads **In progress (Rev 0.6 / Phase 4a-4b)** and
|
||||
names what remains for 4c.
|
||||
|
||||
## Test boundary
|
||||
|
||||
Traces 1-19 of section 18.10 are automated and belong to slice 4e, where the procedural systems exist to
|
||||
run them. Traces 20 and 21 — the PRD 130 visual challenge judged on a real display, and the early
|
||||
combined GC6 benchmark at `1920 x 1080` — are user-observed and close slice 4h. Trace 20 is the same gate
|
||||
as trace 15 of 17.16, restated for locality rather than added as a second gate.
|
||||
|
||||
## State at this checkpoint
|
||||
|
||||
Sections 17 and 18 are contract only. No visual runtime code exists: `src/runtime` has no renderer
|
||||
module, the JSON Schema has no visual definitions, `exhibits/` has no visual fixture, and nothing has
|
||||
been drawn from any build. Phase 3 also remains unaccepted while its own user-observed gates (traces
|
||||
15-17 of section 16.11) and the Phase 1 direct-file restart observation are open; no Phase 4 slice
|
||||
depends on them, and no Phase 4 slice can close them.
|
||||
|
||||
Whether sections 17-19 pass a multi-model review before slice 4d begins — the pass that found thirteen
|
||||
defects in sections 14-16, nine of which any single reviewer would have missed — remains an open
|
||||
decision, and section 18 has now roughly doubled the surface that review would cover.
|
||||
Reference in New Issue
Block a user