@glissade/scene 0.59.0-pre.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/describe.js CHANGED
@@ -23,7 +23,7 @@ import { easings, listValueTypes } from "@glissade/core";
23
23
  * never pulled onto the base embed path — a scene that never calls `describe()`
24
24
  * pays zero bytes for it.
25
25
  */
26
- const RAW_VERSION = "0.59.0-pre.0";
26
+ const RAW_VERSION = "0.59.0";
27
27
  const PACKAGE_VERSION = RAW_VERSION.includes("GLISSADE_".concat("VERSION")) ? "0.0.0-dev" : RAW_VERSION;
28
28
  /**
29
29
  * Parse the documented positional-arg count from a helper `usage` string — the
@@ -568,7 +568,7 @@ const HELPERS = [
568
568
  name: "createPlayer",
569
569
  summary: "Build the transport object (play / pause / seek / rate / loop / marker + cue callbacks) directly — what mount() returns as mounted.player.",
570
570
  import: "@glissade/player",
571
- usage: "createPlayer({ playhead: createPlayhead(), duration: 2 }, { loop?: boolean }): Player — player.play() → { finished }, player.pause(), player.seek(u), player.rate = 2, player.onMarker(name, cb), player.onCue(kind, cb)"
571
+ usage: "createPlayer({ playhead: createPlayhead(), duration: 2 }, { loop?: boolean }): Player — player.play() → { finished }, player.pause(), player.seek(t: seconds), player.rate = 2, player.onMarker(name, cb), player.onCue(kind, cb)"
572
572
  },
573
573
  {
574
574
  name: "mount",
@@ -152,21 +152,31 @@ declare function validateSceneFonts(scene: Scene, doc: Timeline, loadBytes: Font
152
152
  declare const DIAGNOSTIC_SCHEMA_VERSION: 1;
153
153
  /** Closed severity ladder. `error` = a build error (unbound target); `warning`
154
154
  * = a probable-mistake (position of a flow child); `info` = a valid-but-notable
155
- * observation (off-canvas, estimating measurer). */
155
+ * observation (estimating measurer). */
156
156
  type DiagnosticSeverity = 'error' | 'warning' | 'info';
157
157
  /**
158
158
  * Stable, ADDITIVE-ONLY diagnostic codes (never renamed/removed — the wire
159
159
  * contract). Chosen with BOTH `validateScene` and the future
160
160
  * `gs parity --semantic` surface in mind.
161
- * - `UNKNOWN_TARGET` — a track targets an id/prop that resolves to no signal.
162
- * - `ID_COLLISION` reserved: a duplicate node id (a built Scene rejects these
163
- * at assembly, so it is unreachable here today; kept for the shared contract).
164
- * - `OFF_CANVAS` — a node's static position places its box fully outside the
165
- * viewport (valid, but usually a mistake).
166
- * - `YOGA_CHILD_POSITION` — a track drives `position`/`position.*` of a FLOWABLE
167
- * child of a Layout, whose flex slot overrides/confounds that position.
168
- * - `MEASURER_FALLBACK` — the scene carries Text but no real measurer is
169
- * injected, so layout uses the rough per-character estimate.
161
+ *
162
+ * This enum is the shared diagnostic VOCABULARY NOT "everything validateScene
163
+ * emits." Each code maps to a distinct ENFORCEMENT POINT:
164
+ * - `UNKNOWN_TARGET` — EMITTED by validateScene: a track targets an id/prop that
165
+ * resolves to no signal.
166
+ * - `MEASURER_FALLBACK` — EMITTED by validateScene: the scene carries Text but no
167
+ * real measurer is injected, so layout uses the rough per-character estimate.
168
+ * - `YOGA_CHILD_POSITION` — EMITTED by validateScene: a track drives
169
+ * `position`/`position.*` of a FLOWABLE child of a Layout, whose flex slot
170
+ * overrides/confounds that position.
171
+ * - `OFF_CANVAS` — RESERVED for `critique()` (0.60): a node's RENDERED box lands
172
+ * fully outside the viewport. It is a composed-geometry check (needs ancestor
173
+ * Group world transforms from the DisplayList), so validateScene — which reads
174
+ * only static LOCAL positions — does NOT emit it (a nested child would
175
+ * false-positive). Kept in the enum as the additive-only wire contract so 0.60
176
+ * critique() can emit it without a schema bump.
177
+ * - `ID_COLLISION` — ENFORCED at `createScene()` (throws `DuplicateNodeIdError`):
178
+ * a built Scene structurally cannot contain a duplicate id, so validateScene
179
+ * never reaches this case. Kept for the shared contract / `gs parity` surface.
170
180
  */
171
181
  type DiagnosticCode = 'UNKNOWN_TARGET' | 'ID_COLLISION' | 'OFF_CANVAS' | 'YOGA_CHILD_POSITION' | 'MEASURER_FALLBACK';
172
182
  /** One diagnostic. The `{schemaVersion, code, severity, message, node?, track?}`
@@ -209,8 +219,10 @@ declare function nearestId(name: string, candidates: Iterable<string>): string |
209
219
  * `scene.resolveTarget`; an unresolved one becomes an `UNKNOWN_TARGET` error
210
220
  * with a Levenshtein nearest-id / nearest-prop suggestion, and a
211
221
  * `position`/`position.*` track on a flowable Layout child becomes a
212
- * `YOGA_CHILD_POSITION` warning. Scene-only checks (off-canvas, measurer
213
- * fallback) run regardless.
222
+ * `YOGA_CHILD_POSITION` warning. The scene-only MEASURER_FALLBACK check runs
223
+ * regardless. validateScene emits exactly three codes — UNKNOWN_TARGET,
224
+ * MEASURER_FALLBACK, YOGA_CHILD_POSITION; OFF_CANVAS/ID_COLLISION are reserved
225
+ * (see the DiagnosticCode doc for their enforcement points).
214
226
  */
215
227
  declare function validateScene(scene: Scene, doc?: Timeline): ValidateSceneResult;
216
228
  /**
@@ -284,7 +284,7 @@ async function validateSceneFonts(scene, doc, loadBytes, options = {}) {
284
284
  * THE THREE INVARIANTS THIS MODULE UPHOLDS:
285
285
  * - `validateScene(scene, doc)` is a PURE READ: it walks track targets through
286
286
  * the EXISTING `scene.resolveTarget` (no new resolution machinery), reads node
287
- * bounds/flow-flags, and reports. It NEVER draws RNG, warms a signal memo,
287
+ * flow-flags, and reports. It NEVER draws RNG, warms a signal memo,
288
288
  * populates a measurer/font cache, or mutates a node — so `render(scene)` is
289
289
  * byte-identical whether or not `validateScene` ran first. (Flowable-ness is
290
290
  * probed with the STATELESS estimating measurer, not the scene's injected one,
@@ -370,8 +370,10 @@ function isFlowableLayoutChild(node) {
370
370
  * `scene.resolveTarget`; an unresolved one becomes an `UNKNOWN_TARGET` error
371
371
  * with a Levenshtein nearest-id / nearest-prop suggestion, and a
372
372
  * `position`/`position.*` track on a flowable Layout child becomes a
373
- * `YOGA_CHILD_POSITION` warning. Scene-only checks (off-canvas, measurer
374
- * fallback) run regardless.
373
+ * `YOGA_CHILD_POSITION` warning. The scene-only MEASURER_FALLBACK check runs
374
+ * regardless. validateScene emits exactly three codes — UNKNOWN_TARGET,
375
+ * MEASURER_FALLBACK, YOGA_CHILD_POSITION; OFF_CANVAS/ID_COLLISION are reserved
376
+ * (see the DiagnosticCode doc for their enforcement points).
375
377
  */
376
378
  function validateScene(scene, doc) {
377
379
  const diagnostics = [];
@@ -401,20 +403,9 @@ function validateScene(scene, doc) {
401
403
  ...owner.node.id !== void 0 ? { node: owner.node.id } : {}
402
404
  });
403
405
  }
404
- const animatedPos = /* @__PURE__ */ new Set();
405
- if (doc) for (const tr of doc.tracks) {
406
- const m = /^(.+)\/position(?:\.[xy])?$/.exec(tr.target);
407
- if (m) animatedPos.add(m[1]);
408
- }
409
- const { w, h } = scene.size;
410
406
  let sawText = false;
411
407
  const visit = (node) => {
412
408
  if (isTextNode(node)) sawText = true;
413
- const pos = node.position;
414
- if (node.id !== void 0 && !animatedPos.has(node.id) && typeof pos === "function") {
415
- const [px, py] = pos();
416
- if (Number.isFinite(px) && Number.isFinite(py) && (px < 0 || py < 0 || px > w || py > h)) push("OFF_CANVAS", "info", `node '${node.id}' has a static position [${px}, ${py}] outside the ${w}×${h} viewport — it may not be visible (fine if intentional, e.g. an off-screen start).`, { node: node.id });
417
- }
418
409
  const children = node.children;
419
410
  if (Array.isArray(children)) for (const c of children) visit(c);
420
411
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.59.0-pre.0",
3
+ "version": "0.59.0",
4
4
  "description": "glissade scene graph: nodes, transforms, DisplayList emission. Renderer-agnostic; zero DOM/Node dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {
@@ -81,7 +81,7 @@
81
81
  ],
82
82
  "dependencies": {
83
83
  "yoga-layout": "^3.2.1",
84
- "@glissade/core": "0.59.0-pre.0"
84
+ "@glissade/core": "0.59.0"
85
85
  },
86
86
  "repository": {
87
87
  "type": "git",