|
|
|
@@ -1,8 +1,8 @@
|
|
|
|
|
# XZBT Format Specification 0.1
|
|
|
|
|
|
|
|
|
|
**XZBT format version:** 0.1
|
|
|
|
|
**Document revision:** 0.6
|
|
|
|
|
**Status:** Normative specification for shared contracts (document, types, ValueSpec, ConditionSpec, resolution, bindings, and transitions); the Audio subsystem contract is complete (Phase 3a sources/control sources, Phase 3b processing/routing/components/buses, Phase 3c automation/lifecycle/protection); master-protection values remain provisional pending GC6 measurement; the Visual subsystem contract is open (Phase 4a scene/primitives/transforms/appearance in section 17 and Phase 4b components/procedural systems/behaviors/fields in section 18, with automation, lifecycle, camera, post-effects, and the centralized ceilings to follow in section 19), and the remaining subsystem contracts are in progress
|
|
|
|
|
**Document revision:** 0.7
|
|
|
|
|
**Status:** Normative specification for shared contracts (document, types, ValueSpec, ConditionSpec, resolution, bindings, and transitions); the Audio subsystem contract is complete (Phase 3a sources/control sources, Phase 3b processing/routing/components/buses, Phase 3c automation/lifecycle/protection); master-protection values remain provisional pending GC6 measurement; the Visual subsystem contract is complete (Phase 4a scene/primitives/transforms/appearance in section 17, Phase 4b components/procedural systems/behaviors/fields in section 18, and Phase 4c automation/lifecycle/camera/post-effects/ceilings in section 19); the aggregate visual ceilings of 19.5 remain provisional pending the slice 4h GC6 measurement, and the remaining subsystem contracts are in progress
|
|
|
|
|
**Related resources:** [PRD](../XZBT_0-1_MVP_Product_Requirements_Document.md), [decisions](XZBT_0-1_Gap_Closure_Decisions.md), [verification](XZBT_0-1_Verification_Gates.md)
|
|
|
|
|
|
|
|
|
|
This document defines normative syntax and runtime semantics for XZBT 0.1 exhibits. An exhibit is a UTF-8 JSON document that configures generic procedural visual, audio, cadence, and orchestration primitives. It does not contain executable JavaScript.
|
|
|
|
@@ -55,7 +55,7 @@ Metadata provides provenance and UI presentation details. It never executes or m
|
|
|
|
|
```text
|
|
|
|
|
<namespace>.<resource_id>[.<property>]
|
|
|
|
|
```
|
|
|
|
|
Valid canonical namespace prefixes: `parameters.*`, `state.*`, `signals.*`, `modulators.*`, `audio.buses.*`, `visuals.systems.*`. Dots are strictly forbidden within identifier names themselves.
|
|
|
|
|
Valid canonical namespace prefixes: `parameters.*`, `state.*`, `signals.*`, `modulators.*`, `audio.buses.*`, `visuals.systems.*`, `visuals.layers.*`, `visuals.camera.*`, `visuals.effects.*`. Dots are strictly forbidden within identifier names themselves. An ordered container is indexed rather than keyed: `visuals.effects[<index>].<property>` and `points[<index>].x` (17.13) are the two such forms in 0.1.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
@@ -288,7 +288,7 @@ To ensure consistent error reporting between structural schema validation, seman
|
|
|
|
|
| `ERR_NO_AUDIBLE_PATH` | Semantic | A sound's expanded audio graph has no chain of audio routes from a non-control source to `output`. |
|
|
|
|
|
| `ERR_COMPONENT_RECURSION` | Semantic | An audio component instantiates itself transitively, or component nesting exceeds 8 levels. |
|
|
|
|
|
| `WARN_AUDIO_RATE_CLAMP` | Runtime | A frequency field was clamped to the device's `audioMaxFrequency` at node instantiation. |
|
|
|
|
|
| `ERR_AUTOMATION_CONFLICT` | Semantic | More than one automation track directly controls one property in a recipe instance. |
|
|
|
|
|
| `ERR_AUTOMATION_CONFLICT` | Semantic | More than one writer directly controls one property: two automation tracks on one recipe instance or one visual scope, or a visual behavior and an automation track on one object channel. |
|
|
|
|
|
| `ERR_INDETERMINATE_ONESHOT` | Semantic | A `oneshot` recipe has no computable finite ending; its audible path begins at an unbounded source. |
|
|
|
|
|
| `WARN_AUTOMATION_FALLBACK` | Runtime | An `exponential` automation segment had a zero or sign-crossing endpoint and fell back to linear interpolation. |
|
|
|
|
|
| `WARN_VOICE_LIMIT` | Runtime | A voice ceiling was reached; an instance was evicted or a request refused. |
|
|
|
|
@@ -297,7 +297,7 @@ To ensure consistent error reporting between structural schema validation, seman
|
|
|
|
|
| `ERR_INVALID_SYSTEM_TYPE` | Semantic | A `visuals.systems.<id>` `type` is not a member of the Visual System Set 0.1. |
|
|
|
|
|
| `ERR_INVALID_PRIMITIVE_TYPE` | Semantic | A visual object `type` is not a member of Visual Primitive Set 0.1. |
|
|
|
|
|
| `ERR_INVALID_PATH` | Semantic | A path command sequence is structurally valid but illegal: it does not begin with `move`, or it closes a subpath that is not open. |
|
|
|
|
|
| `ERR_VISUAL_LIMIT_EXCEEDED` | Semantic / Runtime | A visual authoring or runtime ceiling is exceeded (layers, group nesting, vertices, path commands, spline points, gradient stops, filters, particle capacity, emitter capacity, repeater count, behaviors per object, declared or referenced fields, trail length, link count). |
|
|
|
|
|
| `ERR_VISUAL_LIMIT_EXCEEDED` | Semantic / Runtime | A visual authoring or runtime ceiling is exceeded (layers, group nesting, vertices, path commands, spline points, gradient stops, filters, particle capacity, emitter capacity, repeater count, behaviors per object, declared or referenced fields, trail length, link count, automation tracks and points, post-effect entries). |
|
|
|
|
|
| `WARN_VISUAL_APPROXIMATION` | Runtime | A declared appearance feature is unavailable on the active renderer and the documented fallback was used. |
|
|
|
|
|
| `ERR_INVALID_DISTRIBUTION_TYPE` | Semantic | A placement distribution `type` is not a member of the placement distribution set of 18.3. |
|
|
|
|
|
| `ERR_INVALID_DISTRIBUTION` | Semantic | A placement distribution is structurally valid but illegal in its context, such as an index-driven placement on a continuous-rate emission. |
|
|
|
|
@@ -306,6 +306,8 @@ To ensure consistent error reporting between structural schema validation, seman
|
|
|
|
|
| `ERR_INVALID_FIELD_TYPE` | Semantic | A `visuals.fields.<id>` `type` is not a member of the procedural field set of 18.7. |
|
|
|
|
|
| `ERR_MORPH_INCOMPATIBLE` | Semantic | A `morph` behavior's source and target differ in `type`, point count, or spline `mode`. |
|
|
|
|
|
| `ERR_UNBOUNDED_EMISSION` | Semantic | A particle system or emitter declares emission but neither a per-item `lifetime` nor a total `limit`, so it can create items without bound. |
|
|
|
|
|
| `ERR_INVALID_EFFECT_TYPE` | Semantic | A `visuals.effects` entry `type` is not a member of the post-effect vocabulary of 19.4. |
|
|
|
|
|
| `WARN_VISUAL_CEILING` | Runtime | An aggregate runtime ceiling of 19.5 was reached: work was shed or a spawn refused, and the exhibit continues. |
|
|
|
|
|
|
|
|
|
|
## 8. Shared value resolution, bindings, and transitions
|
|
|
|
|
|
|
|
|
@@ -324,8 +326,12 @@ Stages that the target does not expose are absent, not identity hooks available
|
|
|
|
|
| `parameters.<id>` | Declared primitive; stored user value | Yes | No | Yes | No | Declared `min`/`max`; integer targets round to the nearest integer after interpolation and before clamping |
|
|
|
|
|
| `state.<id>` | Declared primitive; current state value | Yes | No | Yes | No | Declared `min`/`max` |
|
|
|
|
|
| `audio.buses.<id>.gain` | Number; bus `gain` ValueSpec | Yes | Yes | Yes | Yes | `[0, 4]` in 0.1 before master output protection |
|
|
|
|
|
| `visuals.camera.<field>` | Number; camera `x`, `y`, `zoom`, `rotation`, `focalLength` | Yes | Yes | Yes | Yes | The per-field range of 19.3 |
|
|
|
|
|
| `visuals.layers.<id>.opacity` | Number; layer `opacity` | Yes | Yes | Yes | No | `[0, 1]` |
|
|
|
|
|
| `visuals.systems.<id>.visible` | Boolean; system `visible` | Yes | No | Yes | No | — |
|
|
|
|
|
| `visuals.effects[<index>].<param>` | Number; the post-effect parameter | Yes | Yes | Yes | No | The parameter's range in 19.4 |
|
|
|
|
|
|
|
|
|
|
`signals.*` and `modulators.*` are read-only sources and never binding or action targets. `instances.*` is a runtime action-addressing namespace, not a ValueSpec or binding namespace. Sound inputs are sampled at sound invocation and cannot be ordinary binding targets. Visual properties, audio recipe-instance properties, and any target family absent from this table remain unsupported until their subsystem contract adds an explicit capability row. Merely being numeric does not grant automation, override, or modulation support.
|
|
|
|
|
`signals.*` and `modulators.*` are read-only sources and never binding or action targets. `instances.*` is a runtime action-addressing namespace, not a ValueSpec or binding namespace. Sound inputs are sampled at sound invocation and cannot be ordinary binding targets. The four visual rows are the whole visual surface: section 19.1 adds them and adds nothing else, so per-object geometry, transform, and style properties, procedural-system fields, behavior fields, field strengths, and emitter rates are not binding, `set`, or `override` targets in 0.1. Audio recipe-instance properties and any target family absent from this table remain unsupported until their subsystem contract adds an explicit capability row. Merely being numeric does not grant automation, override, or modulation support.
|
|
|
|
|
|
|
|
|
|
Parameters store user configuration separately from exhibit defaults. State stores simulation values separately from parameters. State is not an implicit layer above user configuration. References read the value resolved for the current logical tick. Parameter controls read and edit stored user values and show an override indicator whenever any live override exists for the parameter, including a masked or releasing override.
|
|
|
|
|
|
|
|
|
@@ -526,7 +532,7 @@ Complete shared contracts before implementing dependent subsystems. Use PRD sect
|
|
|
|
|
| Actions and transitions | 22-30 | Shared `set`/`override` fields and defaults, override target matrix, interrupted transitions, instance IDs; subsystem action matrices remain with their subsystems | **Shared contract complete (Rev 0.3 / GC3)** |
|
|
|
|
|
| Audio | 34-60 | Complete recipe/component shapes, node defaults, automation timing, clamp implementation, one-shot endings and tails, unlock behavior, master protection contract | **Complete (Rev 0.4 / Phase 3a-3c):** units, graph objects, all sixteen node types, routing, modulation, graph legality, authoring limits, components, sounds/recipes, buses, automation tracks and precedence, lifecycle states and release, determinable one-shot endings, voice ceilings, unlock and pause behavior, and the master-protection contract shape. Master-protection *values* (peak ceiling, tolerance, release behavior) are provisional pending GC6 measurement |
|
|
|
|
|
| Cadence | 61-68 | Exact selection/cooldown/overlap fields, clocks, pool collisions, pending audio, manual sampling isolation and continuous-sample termination | Subsystem contract (Phase 5) |
|
|
|
|
|
| Visuals | 69-89 | Primitive/system/behavior fields, angle and motion units, transform order, depth projection, field behavior, morph compatibility, effect approximation and limits | **In progress (Rev 0.6 / Phase 4a-4b):** section 17 fixes the pipeline, canonical units and the angle convention, the `visuals` container, layers, the scene model and coordinate/fit modes, depth sign and sorting, the fourteen primitives, common properties, transform composition order, appearance and the safe blend set, paths and splines, and the once-at-instantiation resolution boundary. Section 18 fixes visual components and their `inputs` scope, particle systems and their normative integrator, the nine placement distributions, emitters and exact emission timing, repeaters and the `repeat.*` scope, the seventeen-behavior vocabulary and its channel set, the six procedural fields and their normative coherent-noise function, and trails, ribbons, and links. Automation, lifecycle, camera, post-effects, and the centralized ceilings remain Phase 4c (section 19) |
|
|
|
|
|
| Visuals | 69-89 | Primitive/system/behavior fields, angle and motion units, transform order, depth projection, field behavior, morph compatibility, effect approximation and limits | **Complete (Rev 0.7 / Phase 4a-4c):** section 17 fixes the pipeline, canonical units and the angle convention, the `visuals` container, layers, the scene model and coordinate/fit modes, depth sign and sorting, the fourteen primitives, common properties, transform composition order, appearance and the safe blend set, paths and splines, and the once-at-instantiation resolution boundary. Section 18 fixes visual components and their `inputs` scope, particle systems and their normative integrator, the nine placement distributions, emitters and exact emission timing, repeaters and the `repeat.*` scope, the seventeen-behavior vocabulary and its channel set, the six procedural fields and their normative coherent-noise function, and trails, ribbons, and links. Section 19 fixes visual automation and its two declaration scopes and loop modes, the four visual rows it adds to the section 8.1 table and nothing beyond them, the persistent and spawned system lifecycle and its ownership, the camera matrix and both projection modes, the seven post-effects and the boundary of permitted approximation, and the centralized runtime ceilings for the whole engine. Aggregate ceiling *values* are provisional pending the slice 4h GC6 measurement |
|
|
|
|
|
| Events/scenarios | 90-102 | Shared ownership, hooks/failure ordering, condition rearming, deferred ordering/expiry, dispatch limits; full trigger/timeline shapes remain for Phase 6 | **Shared lifecycle contract complete (Rev 0.3 / GC5)** |
|
|
|
|
|
| Generated UI | 103-107 | Widget compatibility, button actions, parameter validation and override display, group/control ordering | Subsystem contract (Phase 7) |
|
|
|
|
|
| Runtime/library | 108-112, 117-127 | Clock/audio synchronization, stalls, seed/stream derivation complete in GC4; import equality, update compatibility, transactions, failure recovery, persistence schema remain | **Shared clock/PRNG contract complete (Rev 0.3 / GC4); subsystem remainder Phase 1/8** |
|
|
|
|
@@ -1644,10 +1650,12 @@ A **visual system** is the addressable unit of the visual subsystem and the reso
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `type` | string enum | Yes | — | `graphic` in this section. Section 18 adds `particles`, `emitter`, and `repeater`. Any other value is `ERR_INVALID_SYSTEM_TYPE`. |
|
|
|
|
|
| `layer` | string | No | implicit layer | A declared layer ID (17.5). |
|
|
|
|
|
| `visible` | ValueSpec\<boolean\> | No | `true` | A hidden system is not drawn; its behaviors and automation still advance. |
|
|
|
|
|
| `visible` | ValueSpec\<boolean\> | No | `true` | A hidden system is not drawn; its behaviors and automation still advance. It is an external target by the section 8.1 rows 19.1 adds. |
|
|
|
|
|
| `lifecycle` | string enum | No | `persistent` | `persistent` or `spawned` (19.2). A `spawned` system is a template: declared and validated at import, instantiated only by a `spawn` action. |
|
|
|
|
|
| `automation` | array | No | `[]` | System-scoped automation tracks (19.1), with `at` measured from this system's instantiation boundary. |
|
|
|
|
|
| *(type-specific fields)* | — | Per type | — | 17.8 for `graphic`; 18.2-18.5 for the others. |
|
|
|
|
|
|
|
|
|
|
Lifecycle fields (`lifetime`, `ownership`, `inputs`, `cancelWithScenario`) belong to spawned systems and are specified in 19.2. A `graphic` system declared in `visuals.systems` is persistent.
|
|
|
|
|
Lifecycle fields (`lifetime`, `release`, `ownership`, `inputs`, `cancelWithScenario`) are legal only when `lifecycle` is `spawned` and are specified in 19.2; on a `persistent` system each is `ERR_UNKNOWN_FIELD`. A system declared in `visuals.systems` without a `lifecycle` field is persistent.
|
|
|
|
|
|
|
|
|
|
### 17.8 The `graphic` system
|
|
|
|
|
|
|
|
|
@@ -1866,7 +1874,9 @@ Time variation therefore comes from exactly three mechanisms, all specified late
|
|
|
|
|
2. **Visual automation** (19.1) — declared tracks over numeric properties, with the `step`, `linear`, `exponential`, and `smooth` curves and the `repeat` and `ping-pong` loop modes of PRD 85.
|
|
|
|
|
3. **External control** — bindings, overrides, and modulation, for exactly those visual properties that section 19.1 adds to the section 8.1 target-capability table.
|
|
|
|
|
|
|
|
|
|
Until section 19.1 lands, no visual property is in that table. A `BindingSpec`, `set` action, or `override` action addressing a visual property — for example `visuals.systems.horizon.content.band.style.opacity` — is `ERR_UNSUPPORTED_TARGET`. Section 1.3 reserves `visuals.systems.*` as a *reference path* namespace; reserving a namespace does not grant a capability, and as section 8.1 states, merely being numeric does not grant automation, override, or modulation support.
|
|
|
|
|
Mechanisms 1 and 2 are internal writers declared inside the visual subsystem; mechanism 3 comes from outside it. Adding the first two never widens the third (16.2).
|
|
|
|
|
|
|
|
|
|
Section 19.1 adds exactly four visual rows to that table, all system-level: `visuals.camera.<field>`, `visuals.layers.<id>.opacity`, `visuals.systems.<id>.visible`, and `visuals.effects[<index>].<param>`. No per-object property is among them. A `BindingSpec`, `set` action, or `override` action addressing one — for example `visuals.systems.horizon.content.band.style.opacity` — is `ERR_UNSUPPORTED_TARGET`, and remains so in 0.1. Section 1.3 reserves `visuals.systems.*` as a *reference path* namespace; reserving a namespace does not grant a capability, and as section 8.1 states, merely being numeric does not grant automation, override, or modulation support.
|
|
|
|
|
|
|
|
|
|
### 17.15 New diagnostic codes
|
|
|
|
|
|
|
|
|
@@ -1912,7 +1922,7 @@ Traces 15 and 16 close Phase 4 slice 4h. Until they do, Phase 4 is not accepted
|
|
|
|
|
|
|
|
|
|
This section continues the Visual contract opened in section 17. It covers reusable visual components (PRD 77), particle systems (PRD 78), placement distributions (PRD 79), emitters (PRD 80), repeaters (PRD 81), the behavior vocabulary (PRD 82), procedural fields (PRD 83), and trails, ribbons, and links (PRD 84).
|
|
|
|
|
|
|
|
|
|
Section 17 remains the owner of the scene, the primitive set, the transform model, and appearance; every construct here composes those and adds none of its own geometry. Visual automation (PRD 85), visual lifecycle and ownership (PRD 86), camera and projection (PRD 87), post-processing (PRD 88), and visual safety limits together with the centralized runtime ceilings (PRD 89, 119-120) are specified in section 19 (Phase 4c). The forward references to 19.1, 19.2, and 19.5 in this section are the only unresolved numeric references it contains.
|
|
|
|
|
Section 17 remains the owner of the scene, the primitive set, the transform model, and appearance; every construct here composes those and adds none of its own geometry. Visual automation (PRD 85), visual lifecycle and ownership (PRD 86), camera and projection (PRD 87), post-processing (PRD 88), and visual safety limits together with the centralized runtime ceilings (PRD 89, 119-120) are specified in section 19 (Phase 4c), which resolves every reference to 19.1, 19.2, and 19.5 made here.
|
|
|
|
|
|
|
|
|
|
The subject-neutrality rule of 17.1 governs this section unchanged. No component, distribution, behavior, or field is named after an exhibit's subject: there is no `snow`, `rain`, `flock`, or `traffic` construct. The fourteen PRD 130 challenge items must be reachable by composing this generic vocabulary.
|
|
|
|
|
|
|
|
|
@@ -2331,3 +2341,324 @@ User-observed, and **not** satisfiable by the above:
|
|
|
|
|
21. The early combined GC6 benchmark of slice 4h, which is what fixes whether the ceilings named throughout this section are the right ones.
|
|
|
|
|
|
|
|
|
|
Traces 1-19 belong to slice 4e, where the procedural systems exist to run them. Traces 20 and 21 close slice 4h. Phase 4 is not accepted until both do, no matter how many automated traces pass.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 19. Visual Subsystem Contract — Automation, Lifecycle, Camera, Effects, and Ceilings (Phase 4c)
|
|
|
|
|
|
|
|
|
|
This section closes the Visual contract sections 17 and 18 opened. It covers visual automation and its loop modes (PRD 85), the visual lifecycle and ownership of persistent and spawned systems (PRD 86), the camera and its projection modes (PRD 87), the post-effect chain (PRD 88), and visual safety limits together with the centralized runtime ceilings of the whole engine (PRD 89, 119-120).
|
|
|
|
|
|
|
|
|
|
Sections 17 and 18 define what an exhibit may *declare*. This section defines what the runtime *does* with it over time and what it refuses to do, which is the same division sections 14-15 and 16 use for audio. Every forward reference to 19.1, 19.2, and 19.5 left open by sections 17 and 18 resolves here; after this section the visual contract contains no unresolved forward reference.
|
|
|
|
|
|
|
|
|
|
**Implementation status.** No visual runtime code exists. Sections 17, 18, and 19 are contract only: the JSON Schema has no visual definitions, `src/runtime` has no renderer module, and nothing has been drawn from any build. Slice 4d begins the renderer; 4f implements this section. The ceilings of 19.5 are provisional in the same sense the master-protection values of 16.7 are provisional — their *shape* is normative now, their *values* are confirmed by the slice 4h GC6 measurement.
|
|
|
|
|
|
|
|
|
|
### 19.1 Visual automation
|
|
|
|
|
|
|
|
|
|
A visual automation track drives one numeric visual property along an authored curve on the logical clock (PRD 85). Tracks reuse the audio automation shape of 16.1 field for field, so an author who has written one has written the other; this subsection states only what differs.
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"visuals": {
|
|
|
|
|
"camera": { "x": 800, "y": 450, "zoom": 1 },
|
|
|
|
|
"automation": [
|
|
|
|
|
{
|
|
|
|
|
"target": "camera.zoom",
|
|
|
|
|
"mode": "absolute",
|
|
|
|
|
"interpolation": "smooth",
|
|
|
|
|
"loop": { "mode": "ping-pong", "count": "infinite" },
|
|
|
|
|
"points": [
|
|
|
|
|
{ "at": "0ms", "value": 1 },
|
|
|
|
|
{ "at": "24s", "value": 1.35 }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `target` | string | Yes | — | A property path in the automatable registry below, relative to the array's scope. |
|
|
|
|
|
| `mode` | enum | No | `absolute` | `absolute`, `offset`, or `scale`, with the contributions 16.1 fixes. |
|
|
|
|
|
| `interpolation` | enum | No | `linear` | `step`, `linear`, `exponential`, or `smooth`, with the curves 16.1 fixes, including the `exponential` fallback to linear and its `WARN_AUTOMATION_FALLBACK`. |
|
|
|
|
|
| `loop` | object | No | — | Absent means the track holds its last point's value forever, exactly as an audio track does. |
|
|
|
|
|
| `points` | array | Yes | — | `2` to `256` breakpoints of `{ "at": <duration literal>, "value": ValueSpec<number> }`, strictly increasing in `at`. |
|
|
|
|
|
|
|
|
|
|
**Two declaration scopes, each with its own time origin.** An `automation` array may appear in exactly two places:
|
|
|
|
|
|
|
|
|
|
| Scope | Time origin for `at` | Targets |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| `visuals.automation` | Exhibit activation | `scene.*`, `layers.<id>.*`, `camera.*`, and `effects[<index>].*` properties in the registry below. |
|
|
|
|
|
| `visuals.systems.<id>.automation` | That system's instantiation boundary (17.14) — activation for a persistent system, the spawn moment for a spawned one | Properties of that system, addressed relative to the system. |
|
|
|
|
|
|
|
|
|
|
The second scope is what makes automation work on a spawned system: a track written against spawn-relative time behaves identically however late the spawn happens, which is the same property 16.1 gives an audio track measured from its sound instance's start. A track in one scope naming a target in the other is `ERR_INVALID_REFERENCE`; automation never reaches across scope, and no track may address another system.
|
|
|
|
|
|
|
|
|
|
`at` is a duration literal only, never a procedural `TimeSpec`, for the reason 16.1 gives: the strictly-increasing ordering rule must stay decidable at import. Point *values* remain full ValueSpecs and resolve once, at the owning scope's instantiation boundary, sampled in depth-first document order after that scope's other fields.
|
|
|
|
|
|
|
|
|
|
**Loop modes** (PRD 85). `loop` is `{ "mode": "repeat" | "ping-pong", "count": <integer >= 1> | "infinite" }`, `count` defaulting to `infinite`. The loop period is the `at` of the last point. `repeat` restarts from the first point, so a track whose first and last values differ steps discontinuously at the wrap; that is the author's choice, not a defect. `ping-pong` plays the curve forward then backward, and one `count` unit is one *complete* forward-and-back cycle, so that a finite count always ends where it began. Before the first point the track holds the first point's value under either mode. After a finite `count` is exhausted the track holds the value it ended on and stops advancing. An `infinite` loop is what PRD 85 means by loop count being infinite for persistent visual behavior; it is legal only on a persistent scope, and an `infinite` loop on a spawned system with a finite `lifetime` (19.2) is legal and simply ends with the system.
|
|
|
|
|
|
|
|
|
|
**The automatable registry.** A track may address these properties and no others. A `target` outside this registry is `ERR_UNSUPPORTED_TARGET`; a `target` naming an undeclared layer, system, object, or effect index is `ERR_INVALID_REFERENCE`.
|
|
|
|
|
|
|
|
|
|
| Scope | Automatable properties |
|
|
|
|
|
| --- | --- |
|
|
|
|
|
| `scene` | `depthFog.near`, `depthFog.far`, `depthFog.density` |
|
|
|
|
|
| `layers.<id>` | `opacity`, `parallax` |
|
|
|
|
|
| `camera` | `x`, `y`, `zoom`, `rotation`, `focalLength` |
|
|
|
|
|
| `effects[<index>]` | Every numeric parameter of the effect's own table in 19.4 |
|
|
|
|
|
| A system | `visible` is **not** automatable (it is boolean); for a `graphic` system, any numeric `transform`, `style`, or geometry property of an object in its `content` tree, addressed by container keys; for `particles` and `emitter`, `rate`, `position.x`, `position.y`, `acceleration.x`, `acceleration.y`, `acceleration.z`, and `drag`; for `repeater`, the numeric fields of its `step` block |
|
|
|
|
|
|
|
|
|
|
Non-numeric properties are outside the registry by construction: PRD 85 says automation targets numeric properties, and a curve between two colors or two booleans is a different mechanism (a life ramp, 18.2) with a different contract.
|
|
|
|
|
|
|
|
|
|
**Exclusivity, and composition against behaviors.** Only one track may directly control one property of one instance; two tracks on one expanded target are `ERR_AUTOMATION_CONFLICT`, the same rule and the same code as 16.1. A behavior (18.6) that writes a channel an automation track also targets on the same object is `ERR_AUTOMATION_CONFLICT` as well: a behavior accumulates or multiplies onto a channel while an automation `mode` displaces the base, and two writers with different composition rules on one scalar have no defined answer. This is the resolution 18.6 defers here.
|
|
|
|
|
|
|
|
|
|
Where they do *not* collide, the order is fixed: the shared pipeline of 8.1 resolves the property, and the object's behaviors then compose over that resolved value in array order, per 18.6. Behaviors are the object's own internal motion; the pipeline's output is the base they displace.
|
|
|
|
|
|
|
|
|
|
**The visual rows of the section 8.1 target-capability table.** This slice adds exactly four target families to the shared registry. They are all *system-level*: camera, layer, system visibility, and effect parameters.
|
|
|
|
|
|
|
|
|
|
| Target family | Type and base | Binding target | Automation | Override | Additive modulation | Safety clamp |
|
|
|
|
|
| --- | --- | :---: | :---: | :---: | :---: | --- |
|
|
|
|
|
| `visuals.camera.<field>` | Number; camera `x`, `y`, `zoom`, `rotation`, `focalLength` (19.3) | Yes | Yes | Yes | Yes | The per-field range of 19.3 |
|
|
|
|
|
| `visuals.layers.<id>.opacity` | Number; layer `opacity` (17.5) | Yes | Yes | Yes | No | `[0, 1]` |
|
|
|
|
|
| `visuals.systems.<id>.visible` | Boolean; system `visible` (17.7) | Yes | No | Yes | No | — |
|
|
|
|
|
| `visuals.effects[<index>].<param>` | Number; the effect's own parameter (19.4) | Yes | Yes | Yes | No | The parameter's range in 19.4 |
|
|
|
|
|
|
|
|
|
|
Nothing else. Per-object geometry, transform, and style properties are **not** externally addressable in 0.1; nor are procedural-system fields, behavior fields, field strengths, emitter rates, or particle parameters. A `BindingSpec`, `set` action, or `override` action addressing one of them remains `ERR_UNSUPPORTED_TARGET`, exactly as 17.14 and trace 19 of 18.10 state, and those two statements survive this slice unchanged.
|
|
|
|
|
|
|
|
|
|
The reason is the one 16.2 gives for audio. Automation is declared *inside* the subsystem that owns the property, so adding it never widens the subsystem's external surface; binding, `set`, and `override` come from outside, and every target they can reach is plumbing that slices 4d through 4f must carry, that the override stack must mask and release correctly, and that a future revision cannot withdraw. A camera, a layer's opacity, a system's visibility, and an effect's amount are the four handles an exhibit needs to make its visuals respond to state — Exhibit D's instrument displays are built from state-driven *geometry inside a system*, which automation and behaviors reach without any external capability. The narrower surface is therefore not a limitation on what 0.1 can express; it is the smallest surface that expresses it, and a later revision can widen it compatibly, while nothing can narrow it.
|
|
|
|
|
|
|
|
|
|
Boolean targets take no automation and no modulation stage: those stages are absent, not identity hooks (8.1). `visuals.layers.<id>.visible` is deliberately **not** in the table; a layer is hidden by animating its `opacity` to `0`, which is continuous and needs no second mechanism.
|
|
|
|
|
|
|
|
|
|
**Limits.** At most `128` automation tracks and `2048` total automation points per exhibit, counted across both scopes and across every live spawned instance. Exceeding either is `ERR_VISUAL_LIMIT_EXCEEDED`. These are the "animation records" of PRD 89 and are restated in the centralized table of 19.5.
|
|
|
|
|
|
|
|
|
|
### 19.2 Visual lifecycle and ownership
|
|
|
|
|
|
|
|
|
|
A visual system is either **persistent** or **spawned** (PRD 86). The discriminator is explicit:
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `lifecycle` | enum | No | `persistent` | `persistent` or `spawned`. Added to the 17.7 system field table by this section. |
|
|
|
|
|
| `lifetime` | DurationSpec | No | — | `spawned` only. Logical duration from instantiation to the start of release. Absent means the instance runs until removed or its owner terminates. |
|
|
|
|
|
| `release` | DurationSpec | No | `0ms` | `spawned` only. `0ms` to `10s`. |
|
|
|
|
|
| `ownership` | enum | No | inherited | `spawned` only. `persistent` transfers the instance to the performance root (10.1). Any other value is `ERR_SCHEMA_VALIDATION`. |
|
|
|
|
|
| `inputs` | object | No | `{}` | `spawned` only. Declared parameters, with the shape, types, and construct scope 18.1 fixes for visual components. |
|
|
|
|
|
| `cancelWithScenario` | boolean | No | `true` | `spawned` only. `false` requires `ownership: "persistent"`, or `ERR_UNSUPPORTED_TARGET`. |
|
|
|
|
|
|
|
|
|
|
A lifecycle field on a `persistent` system is `ERR_UNKNOWN_FIELD`, per the strict unknown-field policy. This resolves the deferral 17.7 records.
|
|
|
|
|
|
|
|
|
|
**A spawned system is a template, not a drawn system.** A `visuals.systems.<id>` with `lifecycle: "spawned"` is declared, validated, and counted against the authoring limits at import, and is **not** instantiated or drawn at activation. It is instantiated only by a `spawn` action naming it, once per action, with the supplied values bound to its `inputs`. Its instantiation boundary (17.14) is the spawn moment; every ValueSpec in it, and every point value of its own `automation` array, resolves there. Two spawns of one template therefore sample independently and reproducibly, from the stream child key `<system-id>#<spawn-ordinal>` (9.3), with the ordinal monotonic per template from `0`.
|
|
|
|
|
|
|
|
|
|
The `spawn` and `remove` **action shapes** belong to the Action Model and are not fixed here, exactly as section 16 fixes the sound-instance lifecycle without redefining the `sound` action. This subsection fixes the *resource* contract that those actions operate on. A spawned instance is addressed through the `instances.*` runtime namespace section 1.3 reserves; per 8.1 that namespace is an action-addressing namespace and never a ValueSpec, binding, or automation target.
|
|
|
|
|
|
|
|
|
|
**States.** A visual system instance occupies exactly one state:
|
|
|
|
|
|
|
|
|
|
| State | Meaning | Drawn |
|
|
|
|
|
| --- | --- | :---: |
|
|
|
|
|
| `CREATED` | Template expanded, values resolved, objects constructed, not yet in a layer. | No |
|
|
|
|
|
| `ACTIVE` | In its layer and advancing on the logical clock. | Yes |
|
|
|
|
|
| `RELEASING` | Release ramp running; no new items are created; existing items still advance. | Yes, fading |
|
|
|
|
|
| `FINISHED` | Release complete; contributes nothing to the frame; resources not yet reclaimed. | No |
|
|
|
|
|
| `DISPOSED` | Objects, particles, emitted items, trail history, automation tracks, behavior state, field references, and subscriptions released. Terminal. | No |
|
|
|
|
|
| `FAILED` | Construction raised; resources reclaimed as for `DISPOSED`. Terminal. | No |
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
CREATED -> ACTIVE | FINISHED | FAILED
|
|
|
|
|
ACTIVE -> RELEASING | FINISHED | FAILED
|
|
|
|
|
RELEASING -> FINISHED | FAILED
|
|
|
|
|
FINISHED -> DISPOSED
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
There is no `SCHEDULED` state. The audio machine has one because a voice is committed to the audio clock before it sounds (16.3); a visual system has no second clock to commit to, so a spawn either constructs and becomes `ACTIVE` on the next logical tick or it fails. State names are runtime bookkeeping and are not exposed to exhibits.
|
|
|
|
|
|
|
|
|
|
**Release is a composited fade, and its default is immediate.** Entering `RELEASING` ramps the instance's composited opacity linearly from `1` to `0` over `release`, then enters `FINISHED`. The default is `0ms` — immediate removal — where the audio default is `50ms`, and the difference is deliberate: an audio release exists to prevent a click, which is a defect, while a visual pop is merely abrupt and is sometimes exactly what an author wants. An author who wants a fade declares one. A release of `0ms` still passes through `RELEASING` for one tick, so a single teardown path handles every removal, which is the property 16.4 is protecting.
|
|
|
|
|
|
|
|
|
|
Release is unconditional and runs on `lifetime` expiry, on an explicit `remove`, on owner termination, on exhibit deactivation, and on failure. Per 10.2, cleanup uses the shorter of the authored release and `5s`, and the cleanup owner's five-second deadline still applies, after which remaining instances are force-disposed with `WARN_CLEANUP_FORCED`.
|
|
|
|
|
|
|
|
|
|
**Ownership** follows 10.1 without amendment. A spawned instance inherits the dispatch context of the action that created it — a scenario instance, or the performance root — unless it declares `ownership: "persistent"` and the action requests it. A scenario-owned instance is released during that scenario's cleanup; `cancelWithScenario: false` on a persistent-owned instance is what lets a visual outlive the scenario that started it, which is the case PRD 86 names. A persistent system declared in `visuals.systems` is owned by the performance root, is created at activation, and is released only at deactivation.
|
|
|
|
|
|
|
|
|
|
**A persistent system's `visible` is not its lifecycle.** A hidden system still advances its behaviors, automation, particles, and emissions, and still counts against every ceiling in 19.5 (17.7). Hiding is a compositing decision; removal is a lifecycle decision. An exhibit that wants the work to stop must remove the system, not hide it.
|
|
|
|
|
|
|
|
|
|
**Ceiling.** At most `64` spawned instances live at once across every template, counted from `CREATED` until `DISPOSED`. A spawn that would exceed it is refused — not evicted — and raises `WARN_VISUAL_CEILING` once, naming the template and the ceiling. Refusal rather than eviction is the opposite of the voice policy of 16.6, and for a reason: an evicted voice fades out in milliseconds and is forgiven, whereas a visual system evicted mid-scene disappears in front of the viewer. A refused spawn is not a scenario failure.
|
|
|
|
|
|
|
|
|
|
### 19.3 Camera and projection
|
|
|
|
|
|
|
|
|
|
`visuals.camera` is optional; absent, every field takes its default and the camera is an identity view of the scene (PRD 87).
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Range | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- | --- |
|
|
|
|
|
| `x` | ValueSpec\<number\> | No | Scene center | — | Camera center in scene units. |
|
|
|
|
|
| `y` | ValueSpec\<number\> | No | Scene center | — | Camera center in scene units. |
|
|
|
|
|
| `zoom` | ValueSpec\<number\> | No | `1` | `0.01` to `100` | Uniform scale about the projection center. |
|
|
|
|
|
| `rotation` | ValueSpec\<number\> | No | `0` | — | Degrees, positive toward `+y` (17.2). |
|
|
|
|
|
| `projection` | enum | No | `orthographic` | — | `orthographic` or `perspective`. Any other token is `ERR_SCHEMA_VALIDATION`. |
|
|
|
|
|
| `focalLength` | ValueSpec\<number\> | No | `1000` | above `0` | Scene units. `ERR_OUT_OF_BOUNDS` at or below `0`. |
|
|
|
|
|
|
|
|
|
|
The scene center is `(width / 2, height / 2)` for `virtual`, `(0.5, 0.5)` for `normalized`, and the display center for `viewport` (17.4). A camera default that is not the scene center would make an exhibit that never mentions the camera look different from one that declares its defaults, which is the kind of surprise a contract exists to prevent.
|
|
|
|
|
|
|
|
|
|
**The projection center** is the center of the display rectangle after `fit` resolution (17.4). Every camera operation and the perspective factor of 17.6 act about that one point.
|
|
|
|
|
|
|
|
|
|
**The camera matrix is normative.** For a layer with parallax `p` (17.5), the view matrix applied to that layer's composited content is, in composition order:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
V = T(c) x S(zoom) x R(-rotation) x T(-c) x T(-p x (x - c_x), -p x (y - c_y))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
where `c` is the projection center. Parallax multiplies the camera *translation* only, never its zoom or rotation, so a distant layer drifts more slowly than a near one without also being scaled or tilted differently — which is what makes the deep parallax field of PRD 130 item 1 hold together. A layer with `parallax: 0` is pinned to the display and is the mechanism for a fixed overlay.
|
|
|
|
|
|
|
|
|
|
Under `perspective`, each object additionally receives the uniform factor `focalLength / (focalLength + z)` about the projection center, exactly as 17.6 states, applied after `V`. Under `orthographic`, `z` still drives sorting, parallax, and fog but never scale. Culling of objects at `z <= -focalLength` is unchanged from 17.6 and raises no diagnostic.
|
|
|
|
|
|
|
|
|
|
**`projection` is not automatable and not externally addressable.** Switching projection mid-run has no continuous meaning: there is no value between `orthographic` and `perspective`, so an interpolating mechanism cannot express the change and a stepping one would snap the whole scene. `x`, `y`, `zoom`, `rotation`, and `focalLength` are automatable and are in the 8.1 table by 19.1; `projection` is authored once. This is the direct reading of PRD 87, which says camera *properties* may be automated or bound to state and modulators, in a document whose other enums are likewise fixed at authoring.
|
|
|
|
|
|
|
|
|
|
**Camera and appearance units.** Stroke widths, blur radii, glow radii, and shadow offsets are measured in scene units before camera scaling (17.2), so zooming in thickens a stroke exactly as it enlarges the geometry it outlines. This is the behavior a design space implies and it is stated here because it is the question a renderer author asks first.
|
|
|
|
|
|
|
|
|
|
### 19.4 Post-processing (`visuals.effects`)
|
|
|
|
|
|
|
|
|
|
`visuals.effects` is an ordered array of post-effect entries applied to the composited frame after every layer has been composited and before display (PRD 88). It defaults to `[]`; an exhibit with no effects pays for none.
|
|
|
|
|
|
|
|
|
|
Every entry is `{ "type": <enum>, "enabled": ValueSpec<boolean>, ...parameters }`. `enabled` defaults to `true`; a disabled effect is skipped entirely and costs nothing that frame. A `type` outside the seven below is `ERR_INVALID_EFFECT_TYPE`, and any parameter a type's own table does not declare is `ERR_UNKNOWN_FIELD`.
|
|
|
|
|
|
|
|
|
|
| `type` | Parameters | Range | Default | Effect |
|
|
|
|
|
| --- | --- | --- | --- | --- |
|
|
|
|
|
| `vignette` | `amount` | `0` to `1` | `0.5` | Darkening toward the frame edge. |
|
|
|
|
|
| | `radius` | `0` to `1` | `0.75` | Fraction of the half-diagonal at which darkening begins. |
|
|
|
|
|
| | `softness` | `0` to `1` | `0.5` | Edge softness of that transition. |
|
|
|
|
|
| | `color` | `color` | `#000000` | Color blended toward. |
|
|
|
|
|
| `scanlines` | `amount` | `0` to `1` | `0.3` | Blend strength of the line pattern. |
|
|
|
|
|
| | `spacing` | `1` to `64` | `3` | Line period in device pixels. |
|
|
|
|
|
| | `thickness` | `0` to `1` | `0.5` | Fraction of the period the dark band occupies. |
|
|
|
|
|
| | `speed` | — | `0` | Periods per logical second of vertical scroll. |
|
|
|
|
|
| `grain` | `amount` | `0` to `1` | `0.15` | Blend strength of the noise. |
|
|
|
|
|
| | `scale` | `0.25` to `16` | `1` | Grain cell size in device pixels. |
|
|
|
|
|
| | `speed` | `0` to `60` | `24` | Regenerations per logical second. `0` freezes one pattern. |
|
|
|
|
|
| `color-adjust` | `brightness`, `contrast`, `saturation` | `0` to `4` | `1` | The 17.12 filter semantics, applied to the frame. |
|
|
|
|
|
| | `hueRotate` | — | `0` | Degrees. |
|
|
|
|
|
| `blur` | `radius` | `0` to `32` | `4` | Scene units, scaled by camera `zoom`. |
|
|
|
|
|
| `bloom` | `threshold` | `0` to `1` | `0.7` | Luminance above which a pixel contributes. |
|
|
|
|
|
| | `intensity` | `0` to `2` | `0.6` | Strength of the added bloom. |
|
|
|
|
|
| | `radius` | `0` to `32` | `8` | Scene units. |
|
|
|
|
|
| `fade` | `color` | `color` | `#000000` | Full-surface blend, the transition primitive. |
|
|
|
|
|
| | `amount` | `0` to `1` | `0` | Blend fraction. |
|
|
|
|
|
|
|
|
|
|
Every numeric parameter above is a ValueSpec\<number\>, is automatable by 19.1, and is an 8.1 binding and override target by the table in that subsection. `color` parameters and `type` are authored once. A parameter outside its range is `ERR_OUT_OF_BOUNDS` when it is a literal at import and clamped with no diagnostic when it resolves out of range at instantiation, which is the staging rule 14.5 fixes for audio and the same rule applies here.
|
|
|
|
|
|
|
|
|
|
**Order is array order**, and it is normative because these operations do not commute: `bloom` before `color-adjust` blooms the authored colors, and after it blooms the adjusted ones. `fade` last is the usual transition placement. The runtime does not reorder the chain for efficiency.
|
|
|
|
|
|
|
|
|
|
**Cost and passes.** `blur` and `bloom` each require a full-frame readback and count as **two** passes; `bloom` needs a bright-pass and a blend. `vignette`, `scanlines`, `grain`, `color-adjust`, and `fade` are single-pass pointwise operations over the frame and count as **one**. At most `4` effect entries are authorable (`ERR_VISUAL_LIMIT_EXCEEDED`), which is why the post-effect pass ceiling of 19.5 is `8`: four entries of two passes each. The offscreen compositing buffers of 17.5 and 17.12 have their own separate ceiling in the same table; the two budgets are counted separately because one is per object and the other is per frame.
|
|
|
|
|
|
|
|
|
|
**Approximation.** PRD 88 permits a runtime to approximate an effect differently depending on renderer capability, and 0.1 fixes the boundary of that permission:
|
|
|
|
|
|
|
|
|
|
* `blur` and `bloom` may be computed at a reduced resolution and upsampled, and their radius may be realized by a separable two-pass approximation. A runtime that does either raises `WARN_VISUAL_APPROXIMATION` once per effect instance, never once per frame, and the frame remains within one visually equivalent step of the exact result.
|
|
|
|
|
* `grain` is **exempt from reproducibility and consumes no procedural stream.** Its per-pixel noise is generated from a frame counter and pixel coordinate, not from a seeded stream (9.3), so two runs of one seed are not guaranteed pixel-identical while the grain is enabled. This is the only place in the visual contract where that is true, and it is stated rather than discovered: section 9.3 promises identical *decisions*, grain drives no decision, and pulling per-pixel samples from the exhibit's stream would make the stream position depend on resolution and frame rate — which would break every other reproducibility guarantee to protect one that nobody needs.
|
|
|
|
|
* An effect a renderer cannot perform at all is skipped for the frame and raises `WARN_VISUAL_APPROXIMATION` once per effect instance. It is never silently replaced with a different effect.
|
|
|
|
|
|
|
|
|
|
No post-effect is subject-specific, and none may be used to smuggle geometry into the frame: the chain reads the composited frame and writes the composited frame, and it has no access to scene objects, systems, or state beyond its own declared parameters.
|
|
|
|
|
|
|
|
|
|
### 19.5 Visual safety limits and the centralized runtime ceilings
|
|
|
|
|
|
|
|
|
|
PRD 120 requires that resource ceilings be centralized rather than scattered through individual subsystems. This subsection is that center. Every ceiling the engine enforces appears here, whether it was first stated in section 14, 15, 16, 17, or 18; a subsystem section states a limit for locality, and this table is where a runtime reads it and where a change is made.
|
|
|
|
|
|
|
|
|
|
**Two kinds of limit, and they behave differently.** PRD 89 requires that clearly excessive values normally fail validation rather than be silently transformed into something materially different. That gives the dividing line:
|
|
|
|
|
|
|
|
|
|
| Kind | Checked | On breach | Diagnostic |
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
| **Authoring bound** — a value in the document | Import (structural or semantic) | The exhibit is rejected | `ERR_VISUAL_LIMIT_EXCEEDED`, `ERR_NODE_LIMIT_EXCEEDED`, `ERR_OUT_OF_BOUNDS`, or `ERR_SCHEMA_VALIDATION`, as each limit's own section states |
|
|
|
|
|
| **Runtime ceiling** — an aggregate the document does not name | Every logical tick or frame | Work is shed by a documented rule; the exhibit keeps running | `WARN_VISUAL_CEILING`, raised once per ceiling per second, never once per shed item |
|
|
|
|
|
|
|
|
|
|
An authoring bound fails loudly because the author wrote a number and should learn it is wrong. A runtime ceiling sheds quietly because the exhibit is legal and the machine is merely small, and PRD 119 requires the runtime to remain usable when performance degrades. Neither is ever silently transformed into something materially different, which is the behavior PRD 89 forbids.
|
|
|
|
|
|
|
|
|
|
**Aggregate runtime ceilings.**
|
|
|
|
|
|
|
|
|
|
| Ceiling | Value | Shedding rule when reached |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| Live particles, all systems | `8192` | Evict the oldest particle in the system holding the most, then retry (18.2 is oldest-first within a system) |
|
|
|
|
|
| Live emitted items, all emitters | `2048` | Evict the oldest item in the emitter holding the most (18.4) |
|
|
|
|
|
| Live spawned system instances | `64` | Refuse the spawn (19.2). Never evict a live system |
|
|
|
|
|
| Link segments drawn per tick | `4096` | Drop the tail of the ascending pair order of 18.8, deterministically |
|
|
|
|
|
| Trail history samples retained | `32768` | Truncate the oldest samples of the longest histories first |
|
|
|
|
|
| Field evaluations per logical tick | `32768` | Evaluate fields for the nearest items first and treat the remainder as zero force for that tick |
|
|
|
|
|
| Offscreen compositing buffers per frame | `16` | Draw the excess objects without their non-default `blend`, `mask`, `blur`, `glow`, or `filters`, farthest-`z` first, and raise `WARN_VISUAL_APPROXIMATION` |
|
|
|
|
|
| Post-effect passes per frame | `8` | Skip the trailing effects of the chain (19.4) |
|
|
|
|
|
| Device-pixel-ratio multiplier | `min(devicePixelRatio, 2)` | Clamp |
|
|
|
|
|
| Backing store | `4096 x 4096` device pixels | Lower the multiplier until it fits, to a floor of `1` |
|
|
|
|
|
| Automation records, all scopes | `128` tracks / `2048` points | Authoring bound (19.1), not a shed |
|
|
|
|
|
| Logical ticks of shed before the runtime reports degradation | `120` consecutive | Raise `WARN_VISUAL_CEILING` naming the sustained ceiling |
|
|
|
|
|
|
|
|
|
|
**Ceilings from the other subsystems, restated for centralization.**
|
|
|
|
|
|
|
|
|
|
| Ceiling | Value | Fixed in |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| One-shot voices | `64` | 16.6 |
|
|
|
|
|
| Continuous sounds | `16` | 16.6 |
|
|
|
|
|
| Expanded audio nodes and routes per sound | Per section 15.14 | 15.14 |
|
|
|
|
|
| Audio component nesting | `8` | 15.15 |
|
|
|
|
|
| Resonator modes | Per section 14 | 15.10 |
|
|
|
|
|
| Audio automation tracks / points per sound | `64` / `256` | 16.1 |
|
|
|
|
|
| Ordinary dispatch units per logical tick | `1024` | 10.5 |
|
|
|
|
|
| Nested event depth | `16` | 10.5 |
|
|
|
|
|
| Termination-hook actions per owner | `256` | 10.5 |
|
|
|
|
|
| Layers | `16` | 17.5 |
|
|
|
|
|
| Group nesting | `8` | 17.9 |
|
|
|
|
|
| Polyline / polygon vertices | `512` | 17.9 |
|
|
|
|
|
| Spline points | `256` | 17.13 |
|
|
|
|
|
| Gradient stops | `16` | 17.12 |
|
|
|
|
|
| Filters per object | `4` | 17.12 |
|
|
|
|
|
| Visual component nesting | `8` | 18.1 |
|
|
|
|
|
| Particle `capacity` per system | `4096` | 18.2 |
|
|
|
|
|
| Emitter `capacity` per system | `512` | 18.4 |
|
|
|
|
|
| Repeater `count` | `1024` | 18.5 |
|
|
|
|
|
| Behaviors per object | `8` | 17.10, 18.6 |
|
|
|
|
|
| Declared fields / referenced per system | `8` / `4` | 18.7 |
|
|
|
|
|
| Trail `length` | `128` | 18.8 |
|
|
|
|
|
| `maxLinks` per system | `1024` | 18.8 |
|
|
|
|
|
| Post-effect entries | `4` | 19.4 |
|
|
|
|
|
| Blur and bloom radius | `32` scene units | 19.4 |
|
|
|
|
|
| Spawned instances | `64` | 19.2 |
|
|
|
|
|
|
|
|
|
|
Scenario instances and timeline expansions are the two entries of PRD 120's list that no contract has yet fixed; they are set with the scenario contract in Phase 6 and belong in this table when they are. Naming the gap here is what keeps the table the single center rather than a snapshot.
|
|
|
|
|
|
|
|
|
|
**Lowering, never raising.** A runtime may lower any ceiling in either table on a weaker device, exactly as 16.6 permits for voices. A document can never raise one: there is no field, parameter, or capability by which an exhibit requests a larger budget, and a document that could would be able to defeat the protection PRD 89 exists to provide.
|
|
|
|
|
|
|
|
|
|
**Frame-time governance** (PRD 119). The runtime monitors frame interval and sheds work in the order of the aggregate table above — particles first, then emitted items, then links, then trail history, then compositing buffers, then post-effect passes — before it lowers the device-pixel-ratio multiplier, and it never sheds an authored persistent object or a declared system. The order is normative so that a degraded frame is the same degraded frame everywhere. The *thresholds* that trigger governance are provisional and are derived from the slice 4h GC6 measurement, in the same relationship 16.7 has with the audio protection values: the shape is normative now, the numbers are confirmed by measurement. Until 4h runs, every value in the aggregate table is a considered estimate and nothing more, and no evidence record may describe them as measured.
|
|
|
|
|
|
|
|
|
|
### 19.6 New diagnostic codes
|
|
|
|
|
|
|
|
|
|
Added to the section 7 table, which remains the single authoritative list:
|
|
|
|
|
|
|
|
|
|
| Error Code | Stage | Cause |
|
|
|
|
|
| :--- | :--- | :--- |
|
|
|
|
|
| `ERR_INVALID_EFFECT_TYPE` | Semantic | A `visuals.effects` entry `type` is not one of the seven of 19.4. |
|
|
|
|
|
| `WARN_VISUAL_CEILING` | Runtime | An aggregate runtime ceiling of 19.5 was reached and work was shed or a spawn refused. |
|
|
|
|
|
|
|
|
|
|
Two, and no more. Every other diagnostic this section needs already exists and is reused rather than duplicated under a visual-specific name, on the principle 17.15 and 18.9 state: `ERR_AUTOMATION_CONFLICT`, `WARN_AUTOMATION_FALLBACK`, `ERR_UNSUPPORTED_TARGET`, `ERR_INVALID_REFERENCE`, `ERR_VISUAL_LIMIT_EXCEEDED`, `ERR_NODE_LIMIT_EXCEEDED`, `ERR_OUT_OF_BOUNDS`, `ERR_UNKNOWN_FIELD`, `ERR_SCHEMA_VALIDATION`, `WARN_VISUAL_APPROXIMATION`, and `WARN_CLEANUP_FORCED`.
|
|
|
|
|
|
|
|
|
|
`ERR_AUTOMATION_CONFLICT`'s section 7 cause text is widened by this slice from "in a recipe instance" to cover a visual scope and the behavior collision of 19.1. Widening the one code is correct where minting a second would not be: the condition is identical in both subsystems — two writers, one scalar, no defined answer — and an author who has learned what the code means in audio has learned what it means in visuals.
|
|
|
|
|
|
|
|
|
|
### 19.7 Required traces before slice 4f implementation is accepted
|
|
|
|
|
|
|
|
|
|
Automated, and executable without a display measurement:
|
|
|
|
|
|
|
|
|
|
1. Each automation `mode` and each interpolation curve produces its documented value at segment start, midpoint, and end on a visual target, matching the audio results of trace 1 of 16.11 exactly, since the curves are shared.
|
|
|
|
|
2. `loop.mode` `repeat` restarts from the first point at the loop period and `ping-pong` reverses; a finite `count` of `n` ends on the first point under `ping-pong` and on the last under `repeat`; `infinite` never stops; a track with no `loop` holds its last value forever.
|
|
|
|
|
3. A `visuals.automation` track's `at` is measured from activation and a `visuals.systems.<id>.automation` track's from that system's instantiation boundary: two spawns of one template `4s` apart produce identical curves offset by `4s`.
|
|
|
|
|
4. A track naming a target in the other scope, another system, an undeclared layer, or an out-of-range effect index is `ERR_INVALID_REFERENCE`; a target outside the 19.1 registry — a `color`, a `visible`, a field `strength`, a behavior parameter — is `ERR_UNSUPPORTED_TARGET`.
|
|
|
|
|
5. Two tracks on one expanded visual target are `ERR_AUTOMATION_CONFLICT`; a behavior writing a channel a track targets on the same object is `ERR_AUTOMATION_CONFLICT`; the same behavior on an object with no track on that channel passes and composes by the 18.6 rule.
|
|
|
|
|
6. `129` tracks or `2049` total points across both scopes and live spawned instances is `ERR_VISUAL_LIMIT_EXCEEDED`; `128` and `2048` pass.
|
|
|
|
|
7. Each of the four new section 8.1 rows takes binding, override, and — where the row permits — automation and modulation, through the shared pipeline, with masking and release behaving as 8.3 and 8.4 require; a `set` or `override` on any per-object, particle, emitter, behavior, or field property is `ERR_UNSUPPORTED_TARGET`, and trace 19 of 18.10 still passes unchanged.
|
|
|
|
|
8. A lifecycle field on a `persistent` system is `ERR_UNKNOWN_FIELD`; `cancelWithScenario: false` without `ownership: "persistent"` is `ERR_UNSUPPORTED_TARGET`; a `spawned` template is not drawn at activation and draws only after a spawn.
|
|
|
|
|
9. Every permitted state transition of 19.2 is exercised and every forbidden one rejected; a `release` of `0ms` still passes through `RELEASING` for one tick; a second `remove` on a `DISPOSED` instance is a no-op.
|
|
|
|
|
10. Two spawns of one template resolve independently from `<system-id>#<spawn-ordinal>`, and one seed reproduces both exactly across two runs and across two frame rates.
|
|
|
|
|
11. A scenario-owned spawned instance is released at scenario cleanup; a `persistent`-owned instance with `cancelWithScenario: false` survives it; a cleanup that exceeds the 10.2 deadline force-disposes with `WARN_CLEANUP_FORCED`.
|
|
|
|
|
12. A `65`th live spawned instance is refused with a single `WARN_VISUAL_CEILING`, no live instance is evicted, and the refusal is not a scenario failure.
|
|
|
|
|
13. The camera matrix of 19.3 places a known object at documented display coordinates for each of zoom, rotation, translation, and their composition; a layer at `parallax: 0.2` translates by one fifth of the camera translation and is neither scaled nor rotated differently; `parallax: 0` is pinned.
|
|
|
|
|
14. Under `perspective`, an object at `z` renders at the documented factor about the projection center and an object at `z <= -focalLength` is culled with no diagnostic; under `orthographic` the same object's scale is unchanged while its sorting, parallax, and fog are not.
|
|
|
|
|
15. Each of the seven effects produces its documented change on a known frame; array order is honored (`bloom` before and after `color-adjust` differ); a disabled effect costs no pass; a `type` outside the seven is `ERR_INVALID_EFFECT_TYPE`; a fifth entry is `ERR_VISUAL_LIMIT_EXCEEDED`.
|
|
|
|
|
16. `grain` consumes no procedural stream: with grain enabled, two runs of one seed produce identical decision traces, and disabling grain does not shift any later procedural sample.
|
|
|
|
|
17. A `blur` or `bloom` computed at reduced resolution raises `WARN_VISUAL_APPROXIMATION` once per effect instance and not once per frame; an unavailable effect is skipped, not substituted.
|
|
|
|
|
18. Each aggregate ceiling of 19.5 sheds by its documented rule under a synthetic overload: the shed is deterministic, the exhibit keeps running, `WARN_VISUAL_CEILING` is raised at most once per ceiling per second, and no authored persistent object or declared system is shed.
|
|
|
|
|
19. No document can raise a ceiling: every field, parameter, and action that names a count is checked to clamp or reject, never to widen.
|
|
|
|
|
|
|
|
|
|
User-observed, and **not** satisfiable by the above:
|
|
|
|
|
|
|
|
|
|
20. The PRD 130 visual acceptance challenge passes in full, judged on a real display. This is trace 15 of 17.16 and trace 20 of 18.10, restated for locality; it is one gate, not three.
|
|
|
|
|
21. The early combined GC6 benchmark of slice 4h at `1920 x 1080` runs its 30-second warm-up and 120-second window on recorded hardware, and its results either confirm the aggregate ceilings of 19.5 or replace them.
|
|
|
|
|
|
|
|
|
|
Traces 1-19 belong to slice 4f. Traces 20 and 21 close slice 4h. Phase 4 is not accepted until both do, no matter how many automated traces pass, and the ceilings of 19.5 are not measured until trace 21 says so.
|
|
|
|
|