|
|
|
@@ -1,8 +1,8 @@
|
|
|
|
|
# XZBT Format Specification 0.1
|
|
|
|
|
|
|
|
|
|
**XZBT format version:** 0.1
|
|
|
|
|
**Document revision:** 0.4
|
|
|
|
|
**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, and the remaining subsystem contracts are in progress
|
|
|
|
|
**Document revision:** 0.5
|
|
|
|
|
**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, with procedural systems and automation/lifecycle/effects to follow in sections 18-19), 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.
|
|
|
|
@@ -294,6 +294,11 @@ To ensure consistent error reporting between structural schema validation, seman
|
|
|
|
|
| `WARN_VOICE_LIMIT` | Runtime | A voice ceiling was reached; an instance was evicted or a request refused. |
|
|
|
|
|
| `WARN_AUDIO_NONFINITE` | Runtime | A non-finite sample reached the master chain and the containing block was muted. |
|
|
|
|
|
| `WARN_AUDIO_UNAVAILABLE` | Runtime | No audio device is available; the performance continues silently. |
|
|
|
|
|
| `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). |
|
|
|
|
|
| `WARN_VISUAL_APPROXIMATION` | Runtime | A declared appearance feature is unavailable on the active renderer and the documented fallback was used. |
|
|
|
|
|
|
|
|
|
|
## 8. Shared value resolution, bindings, and transitions
|
|
|
|
|
|
|
|
|
@@ -514,7 +519,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 | Subsystem contract (Phase 4) |
|
|
|
|
|
| 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.5 / Phase 4a):** 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. Procedural systems, behaviors, and fields remain Phase 4b (section 18); automation, lifecycle, camera, post-effects, and the centralized ceilings remain Phase 4c (section 19) |
|
|
|
|
|
| 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** |
|
|
|
|
@@ -1499,3 +1504,394 @@ User-observed, and **not** satisfiable by the above:
|
|
|
|
|
17. The PRD 129 audio acceptance challenge passes in full.
|
|
|
|
|
|
|
|
|
|
Traces 15 through 17 close Phase 3 slice 3c-4. Until they do, Phase 3 is not accepted no matter how many automated traces pass.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 17. Visual Subsystem Contract — Scene, Primitives, Transforms, and Appearance (Phase 4a)
|
|
|
|
|
|
|
|
|
|
This section opens the Visual contract required by section 11 (PRD 69-89). It covers the visual pipeline overview, canonical units, the `visuals` container and layer set, the scene model and coordinate spaces (PRD 70), 2.5D depth (PRD 71), the fourteen geometry primitives (PRD 72), common visual properties (PRD 73), the transform model (PRD 74), appearance (PRD 75), and paths and splines (PRD 76).
|
|
|
|
|
|
|
|
|
|
Visual components, particle systems, placement distributions, emitters, repeaters, behaviors, procedural fields, and trails/ribbons/links (PRD 77-84) are specified in section 18 (Phase 4b). 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).
|
|
|
|
|
|
|
|
|
|
### 17.1 Pipeline and scope
|
|
|
|
|
|
|
|
|
|
The visual pipeline is, in order: visual primitives (17.9-17.13) → reusable `components.visual.*` components (18.1) → procedural systems (18.2-18.8) → layers (17.5) → camera (19.3) → post effects (19.4) → display (PRD 69).
|
|
|
|
|
|
|
|
|
|
The schema is renderer-neutral: nothing in this section names a drawing API, and every construct is expressible by any renderer that can composite transformed, styled 2D geometry. XZBT 0.1 realizes it with Canvas 2D (PRD 69). Where a declared appearance feature is unavailable on the active renderer, this contract fixes the fallback and the runtime raises `WARN_VISUAL_APPROXIMATION`; it never silently omits the feature and never substitutes a materially different one.
|
|
|
|
|
|
|
|
|
|
XZBT never implements a primitive, field, or system named after a specific exhibit's subject. There is no `planet`, `tree`, `ship`, or `machine` primitive (PRD 72). Every construct in this contract is generic, and the fourteen PRD 130 challenge items must be reachable by composition alone.
|
|
|
|
|
|
|
|
|
|
### 17.2 Canonical units
|
|
|
|
|
|
|
|
|
|
| Quantity | Unit | Notes |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| position, size, length | scene units of the declared coordinate space (17.4) | Not CSS pixels unless `coordinateSpace` is `viewport`. |
|
|
|
|
|
| depth | scene units on the `z` axis | Increasing `z` is **farther from the camera** (17.6). |
|
|
|
|
|
| angle | degrees | `0` points along `+x`; positive angles turn toward `+y`. Applies to `rotation`, `skew`, `arc` bounds, and conic gradient angles. |
|
|
|
|
|
| scale | unitless multiplier | `1` is unscaled. Negative values mirror. |
|
|
|
|
|
| opacity and normalized controls | `0` to `1` | Polarity-free control ranges (`opacity`, glow `strength`, filter `amount`, `tension`). |
|
|
|
|
|
| color | `color` (section 2) | Alpha may be carried in `#rrggbbaa` and multiplies the applicable opacity. |
|
|
|
|
|
| stroke width, blur radius, glow radius, shadow offset | scene units | Measured before camera scaling (19.3), so a zoomed camera scales them with the geometry. |
|
|
|
|
|
| time | DurationSpec 0.1 | Section 6; a procedural `TimeSpec` is permitted wherever a field's contract says DurationSpec. |
|
|
|
|
|
| rate | occurrences per logical second | Section 9.1 logical time, never wall time or frame count. |
|
|
|
|
|
|
|
|
|
|
Angles are degrees throughout the visual contract. The audio contract's `phase` field (14.7) is already degrees; no visual field is authored in radians or turns.
|
|
|
|
|
|
|
|
|
|
### 17.3 The `visuals` block
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"visuals": {
|
|
|
|
|
"scene": { "coordinateSpace": "virtual", "width": 1600, "height": 900, "background": "#020308" },
|
|
|
|
|
"layers": { "far": { "parallax": 0.2 }, "near": {} },
|
|
|
|
|
"systems": {
|
|
|
|
|
"horizon": {
|
|
|
|
|
"type": "graphic",
|
|
|
|
|
"layer": "far",
|
|
|
|
|
"content": {
|
|
|
|
|
"band": { "type": "rectangle", "position": { "x": 0, "y": 620 }, "size": { "width": 1600, "height": 4 }, "style": { "fill": "#1d2b3a" } }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Notes |
|
|
|
|
|
| --- | --- | :---: | --- |
|
|
|
|
|
| `scene` | object | Yes when `visuals` is present | Scene model (17.4). |
|
|
|
|
|
| `layers` | object keyed by layer ID | No | Layer set (17.5). Absent means one implicit layer. |
|
|
|
|
|
| `systems` | object keyed by system ID | No (defaults to `{}`) | Visual system objects (17.7). An exhibit with no systems renders only `scene.background`. |
|
|
|
|
|
| `camera` | object | No | Camera (19.3). |
|
|
|
|
|
| `effects` | array | No (defaults to `[]`) | Post-effect chain (19.4). |
|
|
|
|
|
|
|
|
|
|
Per the strict unknown-field policy (section 1), any other property of `visuals` is `ERR_UNKNOWN_FIELD`. Layer and system keys follow the shared identifier rule (section 1.3); a key failing the regex is `ERR_INVALID_ID`.
|
|
|
|
|
|
|
|
|
|
### 17.4 Scene model (`visuals.scene`)
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `coordinateSpace` | enum | No | `virtual` | `normalized`, `viewport`, or `virtual` (PRD 70). |
|
|
|
|
|
| `width` | number | Conditional | — | Required if and only if `coordinateSpace` is `virtual`. `1` to `16384`. |
|
|
|
|
|
| `height` | number | Conditional | — | Required if and only if `coordinateSpace` is `virtual`. `1` to `16384`. |
|
|
|
|
|
| `fit` | enum | No | `contain` | `contain`, `cover`, or `stretch`. |
|
|
|
|
|
| `background` | `color` | No | `#000000` | Cleared to this color before every frame. |
|
|
|
|
|
| `depthFog` | object | No | — | Depth fog (17.6). |
|
|
|
|
|
|
|
|
|
|
`width` or `height` present while `coordinateSpace` is not `virtual` is `ERR_UNKNOWN_FIELD`; either absent while it is `virtual` is `ERR_SCHEMA_VALIDATION`.
|
|
|
|
|
|
|
|
|
|
The three coordinate spaces:
|
|
|
|
|
|
|
|
|
|
* **`normalized`** — the scene is the unit square. `x` and `y` run `0` to `1` from the top-left. The square is mapped into the display surface under `fit`.
|
|
|
|
|
* **`viewport`** — scene units are CSS pixels of the display surface, origin at its top-left. The scene has no intrinsic size, so `fit` is ignored and a `fit` other than `stretch` is `ERR_SCHEMA_VALIDATION`. Content is responsible for its own responsiveness; the runtime does not scale it.
|
|
|
|
|
* **`virtual`** — the scene is a fixed `width` x `height` design space with the origin at its top-left, mapped into the display surface under `fit`. This is the recommended space for reproducible composition, and the one the reference exhibits use.
|
|
|
|
|
|
|
|
|
|
`fit` resolves the scene rectangle against the display rectangle: `contain` scales uniformly until the scene fits entirely inside, letterboxing the remainder with `background`; `cover` scales uniformly until the scene covers the display, cropping the overflow; `stretch` scales each axis independently, changing the aspect ratio. Coordinates outside the scene rectangle are legal and are simply outside the visible area under `contain` and `stretch`.
|
|
|
|
|
|
|
|
|
|
Scene-to-device resolution — the device-pixel-ratio multiplier and its ceiling — is a runtime resource concern and is fixed in 19.5, not by the exhibit. An exhibit never declares a device resolution.
|
|
|
|
|
|
|
|
|
|
### 17.5 Layers (`visuals.layers`)
|
|
|
|
|
|
|
|
|
|
Layers are the compositing groups of PRD 69. Each `visuals.layers.<layer-id>` is:
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `opacity` | ValueSpec\<number\> | No | `1` | `0` to `1`. Applied to the composited layer, not per object. |
|
|
|
|
|
| `blend` | enum | No | `normal` | Safe blend set (17.12). |
|
|
|
|
|
| `visible` | ValueSpec\<boolean\> | No | `true` | An invisible layer is composited out entirely and its systems still advance. |
|
|
|
|
|
| `parallax` | number | No | `1` | Multiplier on camera translation for this layer (17.6, 19.3). `0` pins the layer to the display. |
|
|
|
|
|
|
|
|
|
|
Layers composite in document key order, back to front. A system's `layer` must name a declared layer or `ERR_INVALID_REFERENCE`. When `visuals.layers` is absent, one implicit layer with every default applies and a system's `layer` field is `ERR_INVALID_REFERENCE`.
|
|
|
|
|
|
|
|
|
|
More than `16` layers is `ERR_VISUAL_LIMIT_EXCEEDED`. A layer whose `opacity` or `blend` is not the default requires an offscreen compositing buffer; those buffers count against the pass budget of 19.5.
|
|
|
|
|
|
|
|
|
|
### 17.6 Visual depth
|
|
|
|
|
|
|
|
|
|
XZBT 0.1 supports 2.5D depth through an optional `z` on any visual object (PRD 71). It has no meshes, no lighting model, and no occlusion beyond draw order.
|
|
|
|
|
|
|
|
|
|
**Sign.** Increasing `z` is farther from the camera. `z` defaults to `0`.
|
|
|
|
|
|
|
|
|
|
**Depth sorting.** Within one layer, objects are drawn farthest first: sort by effective `z` descending, breaking ties by document key order. The sort is stable, so equal-`z` objects always draw in document order — the same document-order rule sections 14.4 and 9.3 already use for sampling.
|
|
|
|
|
|
|
|
|
|
**Perspective scaling.** Under the `perspective` camera projection (19.3), an object's transform is post-multiplied by the uniform factor `focalLength / (focalLength + z)` about the camera's projection center. `z <= -focalLength` places an object at or behind the eye; such an object is culled for that frame and raises no diagnostic. Under `orthographic`, `z` affects sorting, parallax, and fog but never scale.
|
|
|
|
|
|
|
|
|
|
**Parallax.** A layer's `parallax` multiplies the camera's translation before it is applied to that layer, giving the deep parallax field of PRD 130 item 1 without any subject-specific renderer.
|
|
|
|
|
|
|
|
|
|
**Depth fog.** `visuals.scene.depthFog` is optional:
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `color` | `color` | Yes | — | Color the object is blended toward. |
|
|
|
|
|
| `near` | number | No | `0` | `z` at which fogging begins. |
|
|
|
|
|
| `far` | number | Yes | — | `z` at which fogging reaches full `density`. `far` must exceed `near` or `ERR_INVALID_RANGE_ORDER`. |
|
|
|
|
|
| `density` | number | No | `1` | `0` to `1`. Maximum blend fraction. |
|
|
|
|
|
|
|
|
|
|
The fog fraction for an object is `density * clamp((z - near) / (far - near), 0, 1)`, and its resolved fill, stroke, glow, and shadow colors are blended toward `color` by that fraction before drawing. Fog applies per object, not per pixel, so it is exact and renderer-independent; it is not an approximation and raises no diagnostic.
|
|
|
|
|
|
|
|
|
|
### 17.7 Visual system objects (`visuals.systems.<id>`)
|
|
|
|
|
|
|
|
|
|
A **visual system** is the addressable unit of the visual subsystem and the resource whose namespace section 1.3 reserves as `visuals.systems.*`.
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `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. |
|
|
|
|
|
| *(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.
|
|
|
|
|
|
|
|
|
|
### 17.8 The `graphic` system
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"type": "graphic",
|
|
|
|
|
"content": {
|
|
|
|
|
"hull": { "type": "polygon", "points": [{ "x": 0, "y": 0 }, { "x": 90, "y": 0 }, { "x": 45, "y": 70 }] }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Notes |
|
|
|
|
|
| --- | --- | :---: | --- |
|
|
|
|
|
| `content` | object keyed by visual object ID | Yes | Visual objects (17.9). An empty `content` object is `ERR_SCHEMA_VALIDATION`. |
|
|
|
|
|
|
|
|
|
|
**Object identity.** Visual objects are addressed by their key in the containing `content` or `children` object, matching how the document keys `parameters`, `state`, `audio` nodes (14.3), buses, and systems. A visual object therefore carries **no** `id` field; supplying one is `ERR_UNKNOWN_FIELD`. Keys follow the shared identifier rule (section 1.3) and are unique within their container by construction. Two objects in different containers may share a key; a full object path is the system ID followed by each container key in turn.
|
|
|
|
|
|
|
|
|
|
Document key order within a container is draw order for equal `z` (17.6), so a renderer must preserve the source key order of `content` and `children` rather than reordering them.
|
|
|
|
|
|
|
|
|
|
### 17.9 Visual objects and Visual Primitive Set 0.1
|
|
|
|
|
|
|
|
|
|
Every value in a `content` or `children` container is a **visual object**: a `type` from Visual Primitive Set 0.1, its type-specific geometry fields, and the common properties of 17.10.
|
|
|
|
|
|
|
|
|
|
| `type` | Geometry fields | Notes |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| `point` | — | A zero-extent mark drawn as a filled dot of `style.pointSize` (17.12). The cheapest primitive; the starfield of PRD 130 item 1 is points under a repeater. |
|
|
|
|
|
| `line` | `to` (`{x, y, z?}`) | From the object's origin to `to`. Stroke only; `style.fill` on a `line` is `ERR_UNKNOWN_FIELD`. |
|
|
|
|
|
| `polyline` | `points` (array, `2` to `512`) | Open chain. Stroke only. |
|
|
|
|
|
| `polygon` | `points` (array, `3` to `512`) | Implicitly closed. Fill and stroke. |
|
|
|
|
|
| `rectangle` | `size` (`{width, height}`) | Axis-aligned in local space before `transform`. |
|
|
|
|
|
| `rounded-rectangle` | `size`, `radius` | `radius` is a number or `{topLeft, topRight, bottomRight, bottomLeft}`. Each radius clamps to half the shorter side. |
|
|
|
|
|
| `ellipse` | `radius` (number or `{x, y}`) | A single number is a circle. |
|
|
|
|
|
| `arc` | `radius`, `startAngle`, `endAngle`, `direction` | `direction` is `clockwise` (default) or `counter-clockwise`. Stroke only. A sweep whose magnitude exceeds `360` degrees is `ERR_OUT_OF_BOUNDS`. |
|
|
|
|
|
| `ring` | `radius`, `innerRadius`, `startAngle`, `endAngle`, `direction` | An annulus or annular sector. `innerRadius` must be less than `radius` or `ERR_INVALID_RANGE_ORDER`. Angles default to a full ring. Fill and stroke. |
|
|
|
|
|
| `path` | `commands` | 17.13. |
|
|
|
|
|
| `bezier` | `c1`, `c2`, `to` | One cubic segment from the object's origin. Stroke only. |
|
|
|
|
|
| `spline` | `points`, `mode`, `closed`, `tension` | 17.13. |
|
|
|
|
|
| `text` | `text`, `font`, `size`, `align`, `baseline`, `maxWidth` | 17.13. |
|
|
|
|
|
| `group` | `children` | A transform and style scope. Fills and strokes are not drawn for the group itself. |
|
|
|
|
|
|
|
|
|
|
A `type` outside this set is `ERR_INVALID_PRIMITIVE_TYPE`. Per the strict unknown-field policy, any property a primitive's contract does not declare — including a geometry field belonging to another primitive — is `ERR_UNKNOWN_FIELD`.
|
|
|
|
|
|
|
|
|
|
`points` entries are `{ "x": number, "y": number, "z"?: number }`. A point's `z` offsets the object's `z` for depth purposes but does not sort points independently; an object is sorted and drawn as one unit.
|
|
|
|
|
|
|
|
|
|
**Groups.** A `group` composes a transform (17.11), a style scope (17.12), and an optional clip or mask over its `children`. Group nesting deeper than `8` levels is `ERR_VISUAL_LIMIT_EXCEEDED`, matching the audio component nesting bound of 15.15. A `group` with an empty `children` object is `ERR_SCHEMA_VALIDATION`.
|
|
|
|
|
|
|
|
|
|
### 17.10 Common visual properties
|
|
|
|
|
|
|
|
|
|
Where applicable to the primitive (PRD 73):
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `position` | `{x, y}`, each ValueSpec\<number\> | No | `{0, 0}` | The object's origin in its parent's local space. |
|
|
|
|
|
| `z` | ValueSpec\<number\> | No | `0` | Depth coordinate (17.6). PRD 73 names this property "depth"; it is spelled `z` throughout this contract, matching PRD 71. |
|
|
|
|
|
| `size` | `{width, height}`, each ValueSpec\<number\> | Per primitive | — | Only where the primitive's row declares it. |
|
|
|
|
|
| `transform` | object | No | identity | Transform model (17.11). |
|
|
|
|
|
| `style` | object | No | inherited | Appearance (17.12). |
|
|
|
|
|
| `behaviors` | array | No (defaults to `[]`) | — | Behavior instances (18.6). Rejected as `ERR_UNKNOWN_FIELD` until section 18 declares them. |
|
|
|
|
|
| `visible` | ValueSpec\<boolean\> | No | `true` | A hidden object and its descendants are not drawn; their behaviors and automation still advance. |
|
|
|
|
|
| `lifetime` | DurationSpec | No | — | Logical duration after which the object is removed from its container. Absent means it lives as long as its system. |
|
|
|
|
|
| `layer` | — | — | — | Declared on the *system* (17.7), not on an object. `layer` on a visual object is `ERR_UNKNOWN_FIELD`. |
|
|
|
|
|
|
|
|
|
|
`layer` is deliberately a system-level property: layers are compositing groups, and allowing sibling objects within one transform hierarchy to composite into different layers would make the hierarchical transform of 17.11 meaningless.
|
|
|
|
|
|
|
|
|
|
### 17.11 Transform model
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"transform": {
|
|
|
|
|
"translate": { "x": 12, "y": 0, "z": -40 },
|
|
|
|
|
"rotation": 30,
|
|
|
|
|
"scale": { "x": 1.5, "y": 1.5 },
|
|
|
|
|
"skew": { "x": 0, "y": 0 },
|
|
|
|
|
"origin": { "x": 45, "y": 35 }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| Field | Type | Default | Notes |
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
| `translate` | `{x, y, z}`, each ValueSpec\<number\> | `{0, 0, 0}` | Added to `position` and `z`. |
|
|
|
|
|
| `rotation` | ValueSpec\<number\> | `0` | Degrees (17.2). |
|
|
|
|
|
| `scale` | `{x, y}`, each ValueSpec\<number\> | `{1, 1}` | Negative values mirror. `0` collapses the object; this is legal and draws nothing. |
|
|
|
|
|
| `skew` | `{x, y}`, each ValueSpec\<number\> | `{0, 0}` | Degrees. Each magnitude must be below `90` or `ERR_OUT_OF_BOUNDS`. |
|
|
|
|
|
| `origin` | `{x, y}`, each ValueSpec\<number\> | `{0, 0}` | Pivot for rotation, scale, and skew, in the object's own local space. |
|
|
|
|
|
|
|
|
|
|
**Composition order is normative.** An object's local matrix is, applied right to left to a local-space point:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
M_local = T(position + translate) x T(origin) x R(rotation) x K(skew) x S(scale) x T(-origin)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
so a point is scaled, then skewed, then rotated about `origin`, then translated. The `z` component of `translate` adds to the object's `z` and takes part in depth sorting and perspective (17.6); it is not part of `M_local`.
|
|
|
|
|
|
|
|
|
|
**Hierarchy.** For an object inside a `group`, the effective matrix is `M_parent x M_local`, and effective `z` is `z_parent + z_local`. Transforms therefore compose down the tree exactly as PRD 74 requires, and a group's `origin` pivots its whole subtree.
|
|
|
|
|
|
|
|
|
|
A renderer must not fold the order differently even where the result would coincide for a particular object; exhibits depend on the stated order wherever rotation and non-uniform scale are combined.
|
|
|
|
|
|
|
|
|
|
### 17.12 Appearance
|
|
|
|
|
|
|
|
|
|
`style` is an object whose fields are inherited by a `group`'s descendants unless the descendant redeclares them. Inheritance is per field, not per object.
|
|
|
|
|
|
|
|
|
|
| Field | Type | Default | Notes |
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
| `fill` | `color`, paint object, or `null` | `null` | `null` draws no fill. |
|
|
|
|
|
| `stroke` | `color`, paint object, or `null` | `null` | `null` draws no stroke. |
|
|
|
|
|
| `strokeWidth` | ValueSpec\<number\> | `1` | Scene units. `0` draws no stroke. |
|
|
|
|
|
| `strokeCap` | enum | `butt` | `butt`, `round`, `square`. |
|
|
|
|
|
| `strokeJoin` | enum | `miter` | `miter`, `round`, `bevel`. |
|
|
|
|
|
| `strokeDash` | array of numbers | — | Alternating on/off lengths in scene units, `1` to `8` entries. |
|
|
|
|
|
| `strokeDashOffset` | ValueSpec\<number\> | `0` | Scene units. |
|
|
|
|
|
| `pointSize` | ValueSpec\<number\> | `1` | Diameter of a `point`, in scene units. |
|
|
|
|
|
| `opacity` | ValueSpec\<number\> | `1` | `0` to `1`. Multiplies with any inherited group opacity and with layer opacity. |
|
|
|
|
|
| `blend` | enum | `normal` | Safe blend set below. |
|
|
|
|
|
| `glow` | object or `null` | `null` | `{ "color": color, "radius": number, "strength": number }`. `strength` is `0` to `1`. |
|
|
|
|
|
| `shadow` | object or `null` | `null` | `{ "color": color, "blurRadius": number, "offsetX": number, "offsetY": number }`. |
|
|
|
|
|
| `blur` | ValueSpec\<number\> | `0` | Object blur radius in scene units. |
|
|
|
|
|
| `filters` | array | `[]` | Ordered filter entries, `0` to `4`. |
|
|
|
|
|
| `clip` | object or `null` | `null` | Clip region; see below. |
|
|
|
|
|
| `mask` | string or `null` | `null` | `group` only; see below. |
|
|
|
|
|
|
|
|
|
|
**Safe blend set (PRD 75).** `normal`, `add`, `screen`, `multiply`, `overlay`, `lighten`, `darken`, `difference`. Any other token is `ERR_SCHEMA_VALIDATION`. This is the set every target renderer supports identically; no other blend mode is authorable in 0.1.
|
|
|
|
|
|
|
|
|
|
**Paint objects.** A `fill` or `stroke` may be a gradient instead of a flat `color`:
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Notes |
|
|
|
|
|
| --- | --- | :---: | --- |
|
|
|
|
|
| `type` | enum | Yes | `linear-gradient`, `radial-gradient`, `conic-gradient`. |
|
|
|
|
|
| `stops` | array | Yes | `2` to `16` entries of `{ "offset": number, "color": color }`. |
|
|
|
|
|
| `from`, `to` | `{x, y}` | `linear-gradient` only | Gradient axis in the object's local space. |
|
|
|
|
|
| `center`, `radius` | `{x, y}`, number | `radial-gradient` only | `innerRadius` optional, default `0`. |
|
|
|
|
|
| `center`, `angle` | `{x, y}`, number | `conic-gradient` only | `angle` is the start angle in degrees, default `0`. |
|
|
|
|
|
|
|
|
|
|
Stop `offset` values are `0` to `1` and must be strictly increasing; a non-increasing pair is `ERR_INVALID_RANGE_ORDER`, the same code section 14 uses for inverted bounds. More than `16` stops is `ERR_VISUAL_LIMIT_EXCEEDED`.
|
|
|
|
|
|
|
|
|
|
**Conic gradient fallback.** PRD 75 makes conic gradients conditional on renderer support. Where the active renderer has no conic gradient, the runtime substitutes a `linear-gradient` with the same stops along the axis from `center` at `angle` to the paint's bounding-box edge, and raises `WARN_VISUAL_APPROXIMATION` once per paint instance, not once per frame. This is the only appearance fallback in 0.1; every other field in this table is exact on every target renderer.
|
|
|
|
|
|
|
|
|
|
**Filters.** Each entry is `{ "type": enum, "amount": ValueSpec<number> }` with `type` in `brightness`, `contrast`, `saturate`, `hue-rotate`, `grayscale`, `sepia`, `invert`. `amount` is `0` to `4` for `brightness`, `contrast`, and `saturate`; `0` to `1` for `grayscale`, `sepia`, and `invert`; and degrees for `hue-rotate`. Filters apply in array order, after the object is drawn and before it composites into its layer. More than `4` entries is `ERR_VISUAL_LIMIT_EXCEEDED`.
|
|
|
|
|
|
|
|
|
|
**Clipping.** `clip` is `{ "shape": "rectangle" | "ellipse", "x": number, "y": number, "width": number, "height": number }`, expressed in the object's local space and intersected with any clip inherited from an ancestor. A clip on a non-`group` primitive clips only that primitive.
|
|
|
|
|
|
|
|
|
|
**Masking.** `mask` is legal only on a `group` and names one key in that group's own `children`. The named child is not drawn; its rendered alpha multiplies the alpha of the group's remaining children. A `mask` naming a missing key is `ERR_INVALID_REFERENCE`; a `mask` on a non-`group` object is `ERR_UNKNOWN_FIELD`.
|
|
|
|
|
|
|
|
|
|
**Cost.** A non-default `blend`, a `mask`, a `blur`, a `glow`, or any `filters` entry requires an offscreen buffer for the object or group. Those buffers count against the pass budget fixed in 19.5; this section declares the cost, and section 19 sets the ceiling.
|
|
|
|
|
|
|
|
|
|
**Stroke-only primitives.** `line`, `polyline`, `arc`, and `bezier` have no interior. A `fill` *declared* on one of them is `ERR_UNKNOWN_FIELD`; a `fill` *inherited* from an ancestor group is ignored for those primitives and still applies to their fillable siblings. Inheritance never turns into a validation error.
|
|
|
|
|
|
|
|
|
|
### 17.13 Paths, splines, and text
|
|
|
|
|
|
|
|
|
|
**Path (`path`).** `commands` is an ordered array of `1` to `512` command objects (PRD 76):
|
|
|
|
|
|
|
|
|
|
| `op` | Fields | Notes |
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
| `move` | `to` | Begins a subpath at `to`. |
|
|
|
|
|
| `line` | `to` | Straight segment. |
|
|
|
|
|
| `quadratic` | `c`, `to` | One quadratic segment with control point `c`. |
|
|
|
|
|
| `cubic` | `c1`, `c2`, `to` | One cubic segment. |
|
|
|
|
|
| `arc` | `radius`, `rotation`, `largeArc`, `sweep`, `to` | Endpoint-parameterized elliptical arc. `radius` is a number or `{x, y}`; `rotation` is degrees; `largeArc` and `sweep` are booleans defaulting to `false`. |
|
|
|
|
|
| `close` | — | Closes the current subpath back to its `move` point. |
|
|
|
|
|
|
|
|
|
|
A `path` also accepts `fillRule`, an enum of `nonzero` (default) or `evenodd`.
|
|
|
|
|
|
|
|
|
|
Path legality:
|
|
|
|
|
|
|
|
|
|
* A `commands` array whose first entry is not `move` is `ERR_INVALID_PATH`.
|
|
|
|
|
* A `close` with no open subpath, or two consecutive `close` commands, is `ERR_INVALID_PATH`.
|
|
|
|
|
* An `arc` with a zero or negative radius component is `ERR_OUT_OF_BOUNDS`. It is **not** silently degraded to a `line`: PRD 89 requires clearly excessive or degenerate values to fail validation rather than become something materially different.
|
|
|
|
|
* More than `512` commands is `ERR_VISUAL_LIMIT_EXCEEDED`.
|
|
|
|
|
|
|
|
|
|
**Spline (`spline`).**
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `points` | array of `{x, y, z?}` | Yes | — | `2` to `256` entries. |
|
|
|
|
|
| `mode` | enum | No | `catmull-rom` | `catmull-rom`, `bezier`, `linear` (PRD 76). |
|
|
|
|
|
| `closed` | boolean | No | `false` | Joins the last point back to the first. |
|
|
|
|
|
| `tension` | ValueSpec\<number\> | No | `0.5` | `0` to `1`. `catmull-rom` only; present under another mode is `ERR_UNKNOWN_FIELD`. |
|
|
|
|
|
| `fillRule` | enum | No | `nonzero` | Applies only when the spline is `closed` and has a fill. |
|
|
|
|
|
|
|
|
|
|
In `bezier` mode the points are read as `p0, c1, c2, p1, c1, c2, p2, ...`, so the entry count must satisfy `count = 3n + 1` for an integer `n >= 1`; any other count is `ERR_SCHEMA_VALIDATION`. In `linear` mode the spline is a polyline over its points, differing from `polyline` only in that its points are individually addressable. In `catmull-rom` mode the curve passes through every point; for an open spline the first and last points are duplicated as the phantom endpoints.
|
|
|
|
|
|
|
|
|
|
**Independently mutable points.** PRD 76 requires spline points to be independently mutable so that slow point wandering and morphing can build evolving organic geometry. This contract fixes what that means: a spline's point *count* is fixed at instantiation (17.14) and its point *indices* are stable for the object's lifetime, so index `i` always denotes the same point. Individual coordinates are addressable as `points[<index>].x`, `.y`, and `.z` by the behaviors of 18.6 and by the visual automation of 19.1. More than `256` points is `ERR_VISUAL_LIMIT_EXCEEDED`. Morphing between two splines requires equal point counts and equal `mode`; section 18.6 fixes that rule and its diagnostic.
|
|
|
|
|
|
|
|
|
|
**Text (`text`).**
|
|
|
|
|
|
|
|
|
|
| Field | Type | Required | Default | Notes |
|
|
|
|
|
| --- | --- | :---: | --- | --- |
|
|
|
|
|
| `text` | ValueSpec\<string\> | Yes | — | Max `256` characters after resolution. |
|
|
|
|
|
| `font` | enum | No | `sans-serif` | `sans-serif`, `serif`, `monospace` only. |
|
|
|
|
|
| `size` | ValueSpec\<number\> | No | `16` | Scene units, not CSS pixels. |
|
|
|
|
|
| `weight` | enum | No | `normal` | `normal`, `bold`. |
|
|
|
|
|
| `italic` | boolean | No | `false` | — |
|
|
|
|
|
| `align` | enum | No | `left` | `left`, `center`, `right`, relative to the object's origin. |
|
|
|
|
|
| `baseline` | enum | No | `alphabetic` | `top`, `middle`, `alphabetic`, `bottom`. |
|
|
|
|
|
| `letterSpacing` | ValueSpec\<number\> | No | `0` | Scene units. |
|
|
|
|
|
| `maxWidth` | ValueSpec\<number\> | No | — | When set, the rendered run is condensed horizontally to fit; it is never wrapped or truncated. |
|
|
|
|
|
|
|
|
|
|
`font` is restricted to the three generic CSS families because section 13.3 requires the standalone artifact to carry every asset it needs and make no external request. A named family would resolve differently on each viewer's machine and could not be embedded without shipping a font file; 0.1 does not ship one.
|
|
|
|
|
|
|
|
|
|
**Live numeric readouts are not in 0.1.** `text` resolves once at instantiation (17.14), so it renders authored strings and static labels, not values that change while the exhibit runs. The instrument and radar displays of PRD 130 item 7 and Exhibit D are built from generic geometry — `arc`, `ring`, `path`, and `polyline` driven by state through the mechanisms of section 19 — with `text` supplying fixed labels. This is a deliberate scope decision, not an oversight: a live readout needs a number-to-string formatting contract (precision, rounding, locale, unit suffixes) that PRD 72 does not specify and that would be the first subject-shaped construct in the visual set. Slice 4g revisits it if the Exhibit D visuals cannot be built without it.
|
|
|
|
|
|
|
|
|
|
### 17.14 Visual field resolution scope
|
|
|
|
|
|
|
|
|
|
Numeric, boolean, string, and color fields on visual objects are authored with ValueSpec 0.1 (section 4) and DurationSpec 0.1 (section 6) exactly where each field table says so. Every such field is resolved **once**, at its owning object's instantiation boundary, and is constant for that object's lifetime. Nested ValueSpecs within one system are sampled in depth-first, property-document order from the system instance's own stream, per section 9.3 — the same rule section 14.4 fixes for audio node fields.
|
|
|
|
|
|
|
|
|
|
The instantiation boundary is: activation, for a persistent system declared in `visuals.systems`; the spawn moment, for a spawned system (19.2); and the emission or repetition moment, for an object created by an emitter or repeater (18.4, 18.5).
|
|
|
|
|
|
|
|
|
|
**Rendering consumes no procedural stream.** Section 9.3 already fixes this. A frame is not a decision point, so no visual field is re-sampled per frame, and an exhibit's procedural decisions are identical across render rates and machines. Visual draws use the `visual` stream domain; the reproducibility scope of section 14.6 has no visual analogue, because no visual construct in 0.1 generates per-sample output outside the seeded streams.
|
|
|
|
|
|
|
|
|
|
Time variation therefore comes from exactly three mechanisms, all specified later in this contract:
|
|
|
|
|
|
|
|
|
|
1. **Behaviors** (18.6) — drift, orbit, wander, point-wander, morph, and the rest of the PRD 82 vocabulary, attached to an object and advanced on the logical clock.
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
### 17.15 New diagnostic codes
|
|
|
|
|
|
|
|
|
|
Added to the section 7 table, which remains the single authoritative list:
|
|
|
|
|
|
|
|
|
|
| Error Code | Stage | Cause |
|
|
|
|
|
| :--- | :--- | :--- |
|
|
|
|
|
| `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; section 19.5 adds the runtime ceilings). |
|
|
|
|
|
| `WARN_VISUAL_APPROXIMATION` | Runtime | A declared appearance feature is unavailable on the active renderer and this contract's documented fallback was used. |
|
|
|
|
|
|
|
|
|
|
### 17.16 Required traces before slice 4d implementation is accepted
|
|
|
|
|
|
|
|
|
|
Automated, and executable without a display measurement:
|
|
|
|
|
|
|
|
|
|
1. Each of the three coordinate spaces maps a known scene point to the expected display point under each `fit` mode, including the letterbox offsets of `contain` and the crop of `cover`; `width` or `height` outside `virtual` is `ERR_UNKNOWN_FIELD`, and either missing inside it is `ERR_SCHEMA_VALIDATION`.
|
|
|
|
|
2. Every primitive in Visual Primitive Set 0.1 instantiates from a minimal example, and an unknown `type` is `ERR_INVALID_PRIMITIVE_TYPE` while an unknown *property* on a known type is `ERR_UNKNOWN_FIELD`.
|
|
|
|
|
3. The transform composition order of 17.11 is verified by a case where rotation and non-uniform scale do not commute: a known local point maps to the documented device point, and reversing any two stages changes the result.
|
|
|
|
|
4. A nested `group` composes `M_parent x M_local` and `z_parent + z_local`; nesting `9` levels deep is `ERR_VISUAL_LIMIT_EXCEEDED` and `8` passes.
|
|
|
|
|
5. Depth sorting draws greater `z` first and preserves document key order for equal `z`; the sort is stable across repeated frames with unchanged input.
|
|
|
|
|
6. Perspective scaling matches `focalLength / (focalLength + z)` at three depths; an object at `z = -focalLength` is culled without a diagnostic; under `orthographic` the same object is unscaled.
|
|
|
|
|
7. Depth fog blends an object's colors by `density * clamp((z - near) / (far - near), 0, 1)` at `near`, midpoint, and beyond `far`; `far <= near` is `ERR_INVALID_RANGE_ORDER`.
|
|
|
|
|
8. Style inheritance is per field: a child redeclaring `fill` keeps its ancestor's `stroke`; a `fill` inherited by a `line` is ignored while a `fill` declared on a `line` is `ERR_UNKNOWN_FIELD`.
|
|
|
|
|
9. Gradient stops out of increasing order are `ERR_INVALID_RANGE_ORDER`; `17` stops, `5` filters, `9` layer nesting levels, `513` path commands, `257` spline points, and `513` polygon vertices are each `ERR_VISUAL_LIMIT_EXCEEDED`, and each limit's maximum legal value passes.
|
|
|
|
|
10. A renderer reporting no conic-gradient support falls back to the documented linear gradient and raises `WARN_VISUAL_APPROXIMATION` exactly once per paint instance across many frames, never once per frame.
|
|
|
|
|
11. Path legality: a first command other than `move` and an unopened `close` are `ERR_INVALID_PATH`; a zero-radius `arc` is `ERR_OUT_OF_BOUNDS` rather than a line; a `bezier`-mode spline whose point count is not `3n + 1` is `ERR_SCHEMA_VALIDATION`.
|
|
|
|
|
12. A `mask` naming a missing child is `ERR_INVALID_REFERENCE`; a `mask` on a non-`group` object is `ERR_UNKNOWN_FIELD`; the masked child is not itself drawn.
|
|
|
|
|
13. Visual ValueSpec fields resolve once: a `random` position sampled at instantiation holds its value across many frames, two runs of the same seed produce identical resolved values, and rendering `600` frames consumes no procedural stream.
|
|
|
|
|
14. A binding, `set`, or `override` addressing any visual property is `ERR_UNSUPPORTED_TARGET`, and the section 8.1 table is unchanged by this slice.
|
|
|
|
|
|
|
|
|
|
User-observed, and **not** satisfiable by the above:
|
|
|
|
|
|
|
|
|
|
15. The fourteen PRD 130 challenge items are reachable by composition of this primitive, transform, and appearance set with sections 18 and 19, judged visually on a real display, with no subject-specific renderer code.
|
|
|
|
|
16. The early combined GC6 benchmark of slice 4h, on recorded hardware at `1920 x 1080` with the environment details GC6 requires.
|
|
|
|
|
|
|
|
|
|
Traces 15 and 16 close Phase 4 slice 4h. Until they do, Phase 4 is not accepted no matter how many automated traces pass.
|
|
|
|
|