@glissade/core 0.58.1 → 0.59.0-pre.1

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/index.d.ts CHANGED
@@ -448,6 +448,23 @@ interface BindOptions {
448
448
  * the generic "no property signal resolves to it".
449
449
  */
450
450
  unboundMessage?: (target: string) => string | undefined;
451
+ /**
452
+ * 0.59 "fail-loud ground floor" MODE GATE. What binding does when a track
453
+ * target fails to resolve to any property signal:
454
+ *
455
+ * - `'throw'` (DEFAULT — loud) raises {@link UnboundTargetError} at bind, the
456
+ * dev/CI behavior authors want (a typo'd target is a build error, §2.2).
457
+ * - `'warn'` DOWNGRADES the throw to a one-line dev-warning and SKIPS the
458
+ * track. Shipped/prod embeds opt into this via `mount({ production: true })`,
459
+ * so an external scene degrades (the offending track simply doesn't apply)
460
+ * instead of hard-failing the whole render.
461
+ *
462
+ * DETERMINISM (0.59 invariant): the leaf `if (!sig)` below is the ONLY branch
463
+ * that differs between modes. A VALID scene (every target resolves) never
464
+ * reaches it, so both modes install the IDENTICAL bindings and produce
465
+ * byte-identical output — the mode is byte-neutral for every valid scene.
466
+ */
467
+ onUnbound?: 'throw' | 'warn';
451
468
  }
452
469
  /**
453
470
  * Bind a compiled timeline's tracks to property signals. `resolve` returns
package/dist/index.js CHANGED
@@ -967,7 +967,14 @@ function bindTimeline(compiled, resolve, playhead = createPlayhead(), options =
967
967
  const samplers = /* @__PURE__ */ new Map();
968
968
  for (const [target, tr] of compiled.tracks) {
969
969
  const sig = resolve(target);
970
- if (!sig) throw new UnboundTargetError(target, options.unboundMessage?.(target));
970
+ if (!sig) {
971
+ const message = options.unboundMessage?.(target);
972
+ if (options.onUnbound === "warn") {
973
+ emitDevWarning(message ?? `timeline targets '${target}' but no property signal resolves to it — track skipped (production mode)`);
974
+ continue;
975
+ }
976
+ throw new UnboundTargetError(target, message);
977
+ }
971
978
  const got = tr.type;
972
979
  const expects = sig.expects;
973
980
  if (expects !== void 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/core",
3
- "version": "0.58.1",
3
+ "version": "0.59.0-pre.1",
4
4
  "description": "glissade core: signals, tracks, timeline document, evaluation, easing, springs, seeded RNG. Zero DOM/Node dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {