@glissade/scene 0.4.2 → 0.4.3

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
@@ -1,4 +1,4 @@
1
- import { $ as createDisplayListBuilder, A as NodeProps, B as DisplayList, C as WordBox, D as EvalContext, E as BindablePropTarget, F as breakLines, G as FontSpec, H as DrawCommand, I as estimatingMeasurer, J as Rect$1, K as Paint, L as quantize, M as resolveAnchor, N as TextMeasurer, O as HitArea, P as TextMetricsLite, Q as StrokeStyle, R as segmentWords, S as VideoProps, T as AnchorSpec, U as FilterSpec, V as DisplayListBuilder, W as FilterValidationError, X as ResourceId, Y as Resource, Z as ShaderRef, _ as Rect, a as LayoutEngineMissingError, at as applyToPoint, b as TextProps, c as requireLayoutEngine, ct as matEquals, d as Group, et as filtersToCanvasFilter, f as ImageNode, g as PathProps, h as Path, i as LayoutEngine, it as Mat2x3, j as PropInit, k as Node, l as setLayoutEngine, lt as multiply, m as LineBox, n as LayoutChildSpec, nt as validateFilters, ot as fromTRS, p as ImageProps, q as PathSeg, r as LayoutContainerSpec, rt as IDENTITY, s as getLayoutEngine, st as invert, t as LayoutBox, tt as glow, u as Circle, v as ShapeProps, w as roundedRectSegs, x as Video, y as Text, z as BlendMode } from "./layoutEngine.js";
1
+ import { $ as StrokeStyle, A as NodeProps, B as BlendMode, C as WordBox, D as EvalContext, E as BindablePropTarget, F as breakLines, G as FilterValidationError, H as DisplayListBuilder, I as estimatingMeasurer, J as PathSeg, K as FontSpec, L as quantize, M as resolveAnchor, N as TextMeasurer, O as HitArea, P as TextMetricsLite, Q as ShaderRef, R as segmentWords, S as VideoProps, T as AnchorSpec, U as DrawCommand, V as DisplayList, W as FilterSpec, X as Resource, Y as Rect$1, Z as ResourceId, _ as Rect, a as LayoutEngineMissingError, at as Mat2x3, b as TextProps, c as requireLayoutEngine, ct as invert, d as Group, et as createDisplayListBuilder, f as ImageNode, g as PathProps, h as Path, i as LayoutEngine, it as IDENTITY, j as PropInit, k as Node, l as setLayoutEngine, lt as matEquals, m as LineBox, n as LayoutChildSpec, nt as glow, ot as applyToPoint, p as ImageProps, q as Paint, r as LayoutContainerSpec, rt as validateFilters, s as getLayoutEngine, st as fromTRS, t as LayoutBox, tt as filtersToCanvasFilter, u as Circle, ut as multiply, v as ShapeProps, w as roundedRectSegs, x as Video, y as Text, z as setDefaultMeasurer } from "./layoutEngine.js";
2
2
  import { BindableSignal, BoundTimeline, CompiledTimeline, Playhead, Timeline } from "@glissade/core";
3
3
 
4
4
  //#region src/highlight.d.ts
@@ -218,4 +218,4 @@ declare function bindScene(scene: Scene, doc: Timeline): BindingCacheEntry;
218
218
  */
219
219
  declare function evaluate(scene: Scene, doc: Timeline, t: number): DisplayList;
220
220
  //#endregion
221
- export { type AnchorSpec, type BindablePropTarget, type BlendMode, type CanvasLike, Circle, ColdAssetError, type Ctx2DLike, type DisplayList, type DisplayListBuilder, type DrawCommand, DuplicateNodeIdError, type EvalContext, type FilterSpec, FilterValidationError, type FontSpec, Group, Highlight, type HighlightProps, type HitArea, IDENTITY, type ImageHandle, ImageNode, type ImageProps, type LayoutBox, type LayoutChildSpec, type LayoutContainerSpec, type LayoutEngine, LayoutEngineMissingError, type LineBox, type Mat2x3, Node, type NodeProps, type Paint, Path, type PathLike, type PathProps, type PathSeg, type PropInit, Raster2D, type Raster2DHost, Rect, type Rect$1 as RectShape, type Resource, type ResourceId, type Scene, type SceneInit, type SceneModule, type ShaderCaps, ShaderEffect, type ShaderEffectProps, type ShaderRef, type ShapeProps, type StrokeStyle, Text, type TextMeasurer, type TextMetricsLite, type TextProps, Video, type VideoFrameSource, type VideoProps, type WordBox, applyToPoint, bindScene, breakLines, createDisplayListBuilder, createScene, estimatingMeasurer, evaluate, filtersToCanvasFilter, fontString, fromTRS, getLayoutEngine, glow, highlight, invert, matEquals, multiply, quantize, requireLayoutEngine, resolveAnchor, roundedRectSegs, segmentWords, setLayoutEngine, validateFilters };
221
+ export { type AnchorSpec, type BindablePropTarget, type BlendMode, type CanvasLike, Circle, ColdAssetError, type Ctx2DLike, type DisplayList, type DisplayListBuilder, type DrawCommand, DuplicateNodeIdError, type EvalContext, type FilterSpec, FilterValidationError, type FontSpec, Group, Highlight, type HighlightProps, type HitArea, IDENTITY, type ImageHandle, ImageNode, type ImageProps, type LayoutBox, type LayoutChildSpec, type LayoutContainerSpec, type LayoutEngine, LayoutEngineMissingError, type LineBox, type Mat2x3, Node, type NodeProps, type Paint, Path, type PathLike, type PathProps, type PathSeg, type PropInit, Raster2D, type Raster2DHost, Rect, type Rect$1 as RectShape, type Resource, type ResourceId, type Scene, type SceneInit, type SceneModule, type ShaderCaps, ShaderEffect, type ShaderEffectProps, type ShaderRef, type ShapeProps, type StrokeStyle, Text, type TextMeasurer, type TextMetricsLite, type TextProps, Video, type VideoFrameSource, type VideoProps, type WordBox, applyToPoint, bindScene, breakLines, createDisplayListBuilder, createScene, estimatingMeasurer, evaluate, filtersToCanvasFilter, fontString, fromTRS, getLayoutEngine, glow, highlight, invert, matEquals, multiply, quantize, requireLayoutEngine, resolveAnchor, roundedRectSegs, segmentWords, setDefaultMeasurer, setLayoutEngine, validateFilters };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as validateFilters, D as invert, E as fromTRS, O as matEquals, S as glow, T as applyToPoint, _ as quantize, a as Circle, b as createDisplayListBuilder, c as Path, d as Video, f as roundedRectSegs, g as estimatingMeasurer, h as breakLines, i as setLayoutEngine, k as multiply, l as Rect, m as resolveAnchor, n as getLayoutEngine, o as Group, p as Node, r as requireLayoutEngine, s as ImageNode, t as LayoutEngineMissingError, u as Text, v as segmentWords, w as IDENTITY, x as filtersToCanvasFilter, y as FilterValidationError } from "./layoutEngine.js";
1
+ import { A as matEquals, C as filtersToCanvasFilter, D as applyToPoint, E as IDENTITY, O as fromTRS, S as createDisplayListBuilder, T as validateFilters, _ as fallbackMeasurer, a as Circle, b as setDefaultMeasurer, c as Path, d as Video, f as roundedRectSegs, g as estimatingMeasurer, h as breakLines, i as setLayoutEngine, j as multiply, k as invert, l as Rect, m as resolveAnchor, n as getLayoutEngine, o as Group, p as Node, r as requireLayoutEngine, s as ImageNode, t as LayoutEngineMissingError, u as Text, v as quantize, w as glow, x as FilterValidationError, y as segmentWords } from "./layoutEngine.js";
2
2
  import { bindTimeline, compileTimeline, createPlayhead, emitDevWarning, evaluateAt, signal } from "@glissade/core";
3
3
  //#region src/highlight.ts
4
4
  /**
@@ -505,8 +505,8 @@ function createScene(init) {
505
505
  });
506
506
  const nodes = /* @__PURE__ */ new Map();
507
507
  const playhead = createPlayhead();
508
- let measurer = estimatingMeasurer;
509
- indexNodes(root, nodes, () => measurer);
508
+ let measurer = null;
509
+ indexNodes(root, nodes, () => measurer ?? fallbackMeasurer());
510
510
  return {
511
511
  root,
512
512
  nodes,
@@ -521,7 +521,7 @@ function createScene(init) {
521
521
  measurer = m;
522
522
  },
523
523
  get textMeasurer() {
524
- return measurer;
524
+ return measurer ?? fallbackMeasurer();
525
525
  }
526
526
  };
527
527
  }
@@ -563,4 +563,4 @@ function evaluate(scene, doc, t) {
563
563
  });
564
564
  }
565
565
  //#endregion
566
- export { Circle, ColdAssetError, DuplicateNodeIdError, FilterValidationError, Group, Highlight, IDENTITY, ImageNode, LayoutEngineMissingError, Node, Path, Raster2D, Rect, ShaderEffect, Text, Video, applyToPoint, bindScene, breakLines, createDisplayListBuilder, createScene, estimatingMeasurer, evaluate, filtersToCanvasFilter, fontString, fromTRS, getLayoutEngine, glow, highlight, invert, matEquals, multiply, quantize, requireLayoutEngine, resolveAnchor, roundedRectSegs, segmentWords, setLayoutEngine, validateFilters };
566
+ export { Circle, ColdAssetError, DuplicateNodeIdError, FilterValidationError, Group, Highlight, IDENTITY, ImageNode, LayoutEngineMissingError, Node, Path, Raster2D, Rect, ShaderEffect, Text, Video, applyToPoint, bindScene, breakLines, createDisplayListBuilder, createScene, estimatingMeasurer, evaluate, filtersToCanvasFilter, fontString, fromTRS, getLayoutEngine, glow, highlight, invert, matEquals, multiply, quantize, requireLayoutEngine, resolveAnchor, roundedRectSegs, segmentWords, setDefaultMeasurer, setLayoutEngine, validateFilters };
package/dist/layout.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as NodeProps, D as EvalContext, N as TextMeasurer, V as DisplayListBuilder, a as LayoutEngineMissingError, d as Group, i as LayoutEngine, j as PropInit, k as Node, l as setLayoutEngine, n as LayoutChildSpec, o as LayoutResult, r as LayoutContainerSpec, s as getLayoutEngine, t as LayoutBox } from "./layoutEngine.js";
1
+ import { A as NodeProps, D as EvalContext, H as DisplayListBuilder, N as TextMeasurer, a as LayoutEngineMissingError, d as Group, i as LayoutEngine, j as PropInit, k as Node, l as setLayoutEngine, n as LayoutChildSpec, o as LayoutResult, r as LayoutContainerSpec, s as getLayoutEngine, t as LayoutBox } from "./layoutEngine.js";
2
2
  import { BindableSignal } from "@glissade/core";
3
3
 
4
4
  //#region src/layout.d.ts
package/dist/layout.js CHANGED
@@ -1,4 +1,4 @@
1
- import { g as estimatingMeasurer, i as setLayoutEngine, n as getLayoutEngine, o as Group, r as requireLayoutEngine, t as LayoutEngineMissingError } from "./layoutEngine.js";
1
+ import { _ as fallbackMeasurer, i as setLayoutEngine, n as getLayoutEngine, o as Group, r as requireLayoutEngine, t as LayoutEngineMissingError } from "./layoutEngine.js";
2
2
  import { signal } from "@glissade/core";
3
3
  //#region src/layout.ts
4
4
  /**
@@ -68,7 +68,7 @@ var Layout = class extends Group {
68
68
  * The measurer defaults to the scene-injected one (estimating pre-scene).
69
69
  */
70
70
  computedSize(measurer) {
71
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
71
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
72
72
  return this.#compute(m).size;
73
73
  }
74
74
  #compute(measurer) {
@@ -189,10 +189,16 @@ interface TextMeasurer {
189
189
  /** §3.6 measurement quantum. */
190
190
  declare function quantize(v: number): number;
191
191
  /**
192
- * Estimating fallback measurer used only when no backend has been injected
193
- * (e.g. evaluating for IR-level tests). Deterministic but not metrically
194
- * faithful; mount(), the CLI, and exporters always inject the real one.
192
+ * Process-wide fallback measurer for FACTORY-TIME measurement component
193
+ * factories run before any scene exists, so Text pulls (measuredSize,
194
+ * lineBoxes, wordBoxes) and createScene fall back here before the estimator.
195
+ * Node consumers: `setDefaultMeasurer(createMeasurer({ fonts }))` from
196
+ * @glissade/backend-skia gives factory code the rasterizer's real metrics.
197
+ * Scene-injected measurers (mount/CLI/golden harness) always win.
195
198
  */
199
+ declare function setDefaultMeasurer(m: TextMeasurer | null): void;
200
+ /** The default-or-estimating chain end; internal fallback for measurer pulls. */
201
+
196
202
  declare const estimatingMeasurer: TextMeasurer;
197
203
  /**
198
204
  * The draw-path word segmentation (Intl.Segmenter boundaries, punctuation
@@ -602,4 +608,4 @@ declare function setLayoutEngine(e: LayoutEngine): void;
602
608
  declare function getLayoutEngine(): LayoutEngine | null;
603
609
  declare function requireLayoutEngine(): LayoutEngine;
604
610
  //#endregion
605
- export { createDisplayListBuilder as $, NodeProps as A, DisplayList as B, WordBox as C, EvalContext as D, BindablePropTarget as E, breakLines as F, FontSpec as G, DrawCommand as H, estimatingMeasurer as I, Rect$1 as J, Paint as K, quantize as L, resolveAnchor as M, TextMeasurer as N, HitArea as O, TextMetricsLite as P, StrokeStyle as Q, segmentWords as R, VideoProps as S, AnchorSpec as T, FilterSpec as U, DisplayListBuilder as V, FilterValidationError as W, ResourceId as X, Resource as Y, ShaderRef as Z, Rect as _, LayoutEngineMissingError as a, applyToPoint as at, TextProps as b, requireLayoutEngine as c, matEquals as ct, Group as d, filtersToCanvasFilter as et, ImageNode as f, PathProps as g, Path as h, LayoutEngine as i, Mat2x3 as it, PropInit as j, Node as k, setLayoutEngine as l, multiply as lt, LineBox as m, LayoutChildSpec as n, validateFilters as nt, LayoutResult as o, fromTRS as ot, ImageProps as p, PathSeg as q, LayoutContainerSpec as r, IDENTITY as rt, getLayoutEngine as s, invert as st, LayoutBox as t, glow as tt, Circle as u, ShapeProps as v, roundedRectSegs as w, Video as x, Text as y, BlendMode as z };
611
+ export { StrokeStyle as $, NodeProps as A, BlendMode as B, WordBox as C, EvalContext as D, BindablePropTarget as E, breakLines as F, FilterValidationError as G, DisplayListBuilder as H, estimatingMeasurer as I, PathSeg as J, FontSpec as K, quantize as L, resolveAnchor as M, TextMeasurer as N, HitArea as O, TextMetricsLite as P, ShaderRef as Q, segmentWords as R, VideoProps as S, AnchorSpec as T, DrawCommand as U, DisplayList as V, FilterSpec as W, Resource as X, Rect$1 as Y, ResourceId as Z, Rect as _, LayoutEngineMissingError as a, Mat2x3 as at, TextProps as b, requireLayoutEngine as c, invert as ct, Group as d, createDisplayListBuilder as et, ImageNode as f, PathProps as g, Path as h, LayoutEngine as i, IDENTITY as it, PropInit as j, Node as k, setLayoutEngine as l, matEquals as lt, LineBox as m, LayoutChildSpec as n, glow as nt, LayoutResult as o, applyToPoint as ot, ImageProps as p, Paint as q, LayoutContainerSpec as r, validateFilters as rt, getLayoutEngine as s, fromTRS as st, LayoutBox as t, filtersToCanvasFilter as tt, Circle as u, multiply as ut, ShapeProps as v, roundedRectSegs as w, Video as x, Text as y, setDefaultMeasurer as z };
@@ -158,6 +158,22 @@ function quantize(v) {
158
158
  * (e.g. evaluating for IR-level tests). Deterministic but not metrically
159
159
  * faithful; mount(), the CLI, and exporters always inject the real one.
160
160
  */
161
+ let defaultMeasurer = null;
162
+ /**
163
+ * Process-wide fallback measurer for FACTORY-TIME measurement — component
164
+ * factories run before any scene exists, so Text pulls (measuredSize,
165
+ * lineBoxes, wordBoxes) and createScene fall back here before the estimator.
166
+ * Node consumers: `setDefaultMeasurer(createMeasurer({ fonts }))` from
167
+ * @glissade/backend-skia gives factory code the rasterizer's real metrics.
168
+ * Scene-injected measurers (mount/CLI/golden harness) always win.
169
+ */
170
+ function setDefaultMeasurer(m) {
171
+ defaultMeasurer = m;
172
+ }
173
+ /** The default-or-estimating chain end; internal fallback for measurer pulls. */
174
+ function fallbackMeasurer() {
175
+ return defaultMeasurer ?? estimatingMeasurer;
176
+ }
161
177
  const estimatingMeasurer = { measureText(text, font) {
162
178
  return {
163
179
  width: text.length * font.size * .52,
@@ -329,7 +345,7 @@ var Node = class {
329
345
  * left/center/right baseline origin; Path from author-positioned bounds.
330
346
  */
331
347
  drawOffset(measurer) {
332
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
348
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
333
349
  const size = this.intrinsicSize(m) ?? {
334
350
  w: 0,
335
351
  h: 0
@@ -345,7 +361,7 @@ var Node = class {
345
361
  * (−ax·w, −ay·h); the center default reproduces (−w/2, −h/2).
346
362
  */
347
363
  flowOffset(measurer) {
348
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
364
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
349
365
  const d = this.drawOffset(m);
350
366
  const [sx, sy] = this.anchorShift(m);
351
367
  return {
@@ -365,7 +381,7 @@ var Node = class {
365
381
  anchorShift(measurer) {
366
382
  if (!this.hasAnchor) return [0, 0];
367
383
  const [ax, ay] = this.anchor;
368
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
384
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
369
385
  const size = this.intrinsicSize(m);
370
386
  if (!size) {
371
387
  if (!this.#warnedAnchor) {
@@ -869,7 +885,7 @@ var Text = class extends Node {
869
885
  }
870
886
  /** Text draws from a baseline origin at its align edge, not a center (§3.6). */
871
887
  drawOffset(measurer) {
872
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
888
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
873
889
  const size = this.intrinsicSize(m);
874
890
  const font = {
875
891
  family: this.fontFamily,
@@ -889,7 +905,7 @@ var Text = class extends Node {
889
905
  * text dimensions (e.g. underline width = () => title.measuredSize().w).
890
906
  */
891
907
  measuredSize(measurer) {
892
- return this.intrinsicSize(measurer ?? this.measurerSource?.() ?? estimatingMeasurer);
908
+ return this.intrinsicSize(measurer ?? this.measurerSource?.() ?? fallbackMeasurer());
893
909
  }
894
910
  /**
895
911
  * Per-line ink boxes in this node's DRAW space (origin = first baseline at
@@ -899,7 +915,7 @@ var Text = class extends Node {
899
915
  * reveals, selections.
900
916
  */
901
917
  lineBoxes(measurer) {
902
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
918
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
903
919
  const text = this.text();
904
920
  if (!text) return [];
905
921
  const font = {
@@ -936,7 +952,7 @@ var Text = class extends Node {
936
952
  * karaoke; draw your own rects for sub-line multi-color token work.
937
953
  */
938
954
  wordBoxes(measurer) {
939
- const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
955
+ const m = measurer ?? this.measurerSource?.() ?? fallbackMeasurer();
940
956
  const text = this.text();
941
957
  if (!text) return [];
942
958
  const font = {
@@ -958,12 +974,15 @@ var Text = class extends Node {
958
974
  const h = met.ascent + met.descent;
959
975
  let prefix = "";
960
976
  for (const seg of segmentWords(line)) {
961
- const before = prefix === "" ? 0 : m.measureText(prefix, font).width;
977
+ const start = prefix;
962
978
  prefix += seg;
963
- if (seg.trim() === "") continue;
964
- const after = m.measureText(prefix, font).width;
979
+ const word = seg.trim();
980
+ if (word === "") continue;
981
+ const lead = seg.length - seg.trimStart().length;
982
+ const before = m.measureText(start + seg.slice(0, lead), font).width;
983
+ const after = m.measureText(start + seg.trimEnd(), font).width;
965
984
  boxes.push({
966
- text: seg,
985
+ text: word,
967
986
  line: i,
968
987
  x: lineX + before,
969
988
  y,
@@ -1022,4 +1041,4 @@ function requireLayoutEngine() {
1022
1041
  return engine;
1023
1042
  }
1024
1043
  //#endregion
1025
- export { validateFilters as C, invert as D, fromTRS as E, matEquals as O, glow as S, applyToPoint as T, quantize as _, Circle as a, createDisplayListBuilder as b, Path as c, Video as d, roundedRectSegs as f, estimatingMeasurer as g, breakLines as h, setLayoutEngine as i, multiply as k, Rect as l, resolveAnchor as m, getLayoutEngine as n, Group as o, Node as p, requireLayoutEngine as r, ImageNode as s, LayoutEngineMissingError as t, Text as u, segmentWords as v, IDENTITY as w, filtersToCanvasFilter as x, FilterValidationError as y };
1044
+ export { matEquals as A, filtersToCanvasFilter as C, applyToPoint as D, IDENTITY as E, fromTRS as O, createDisplayListBuilder as S, validateFilters as T, fallbackMeasurer as _, Circle as a, setDefaultMeasurer as b, Path as c, Video as d, roundedRectSegs as f, estimatingMeasurer as g, breakLines as h, setLayoutEngine as i, multiply as j, invert as k, Rect as l, resolveAnchor as m, getLayoutEngine as n, Group as o, Node as p, requireLayoutEngine as r, ImageNode as s, LayoutEngineMissingError as t, Text as u, quantize as v, glow as w, FilterValidationError as x, segmentWords as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "glissade scene graph: nodes, transforms, DisplayList emission. Renderer-agnostic; zero DOM/Node dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "yoga-layout": "^3.2.1",
23
- "@glissade/core": "0.4.2"
23
+ "@glissade/core": "0.4.3"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",