@glissade/scene 0.4.1 → 0.4.2

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 glow, A as PropInit, B as DrawCommand, C as roundedRectSegs, D as HitArea, E as EvalContext, F as estimatingMeasurer, G as PathSeg, H as FilterValidationError, I as quantize, J as ResourceId, K as Rect$1, L as BlendMode, M as TextMeasurer, N as TextMetricsLite, O as Node, P as breakLines, Q as filtersToCanvasFilter, R as DisplayList, S as VideoProps, T as BindablePropTarget, U as FontSpec, V as FilterSpec, W as Paint, X as StrokeStyle, Y as ShaderRef, Z as createDisplayListBuilder, _ as Rect, a as LayoutEngineMissingError, at as invert, b as TextProps, c as requireLayoutEngine, d as Group, et as validateFilters, f as ImageNode, g as PathProps, h as Path, i as LayoutEngine, it as fromTRS, j as resolveAnchor, k as NodeProps, l as setLayoutEngine, m as LineBox, n as LayoutChildSpec, nt as Mat2x3, ot as matEquals, p as ImageProps, q as Resource, r as LayoutContainerSpec, rt as applyToPoint, s as getLayoutEngine, st as multiply, t as LayoutBox, tt as IDENTITY, u as Circle, v as ShapeProps, w as AnchorSpec, x as Video, y as Text, z as DisplayListBuilder } from "./layoutEngine.js";
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";
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, applyToPoint, bindScene, breakLines, createDisplayListBuilder, createScene, estimatingMeasurer, evaluate, filtersToCanvasFilter, fontString, fromTRS, getLayoutEngine, glow, highlight, invert, matEquals, multiply, quantize, requireLayoutEngine, resolveAnchor, roundedRectSegs, 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, setLayoutEngine, validateFilters };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as IDENTITY, D as matEquals, E as invert, O as multiply, S as validateFilters, T as fromTRS, _ as quantize, a as Circle, b as filtersToCanvasFilter, c as Path, d as Video, f as roundedRectSegs, g as estimatingMeasurer, h as breakLines, i as setLayoutEngine, 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 FilterValidationError, w as applyToPoint, x as glow, y as createDisplayListBuilder } from "./layoutEngine.js";
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";
2
2
  import { bindTimeline, compileTimeline, createPlayhead, emitDevWarning, evaluateAt, signal } from "@glissade/core";
3
3
  //#region src/highlight.ts
4
4
  /**
@@ -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, 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, setLayoutEngine, validateFilters };
package/dist/layout.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as PropInit, E as EvalContext, M as TextMeasurer, O as Node, a as LayoutEngineMissingError, d as Group, i as LayoutEngine, k as NodeProps, l as setLayoutEngine, n as LayoutChildSpec, o as LayoutResult, r as LayoutContainerSpec, s as getLayoutEngine, t as LayoutBox, z as DisplayListBuilder } from "./layoutEngine.js";
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";
2
2
  import { BindableSignal } from "@glissade/core";
3
3
 
4
4
  //#region src/layout.d.ts
@@ -194,6 +194,12 @@ declare function quantize(v: number): number;
194
194
  * faithful; mount(), the CLI, and exporters always inject the real one.
195
195
  */
196
196
  declare const estimatingMeasurer: TextMeasurer;
197
+ /**
198
+ * The draw-path word segmentation (Intl.Segmenter boundaries, punctuation
199
+ * glued to its predecessor) — exported so Text.wordBoxes() boxes EXACTLY the
200
+ * units the breaker flows.
201
+ */
202
+ declare function segmentWords(text: string): string[];
197
203
  /**
198
204
  * Greedy line breaking: explicit '\n' always breaks; otherwise word segments
199
205
  * flow until maxWidth is exceeded (Intl.Segmenter boundaries, so CJK wraps
@@ -477,6 +483,16 @@ interface LineBox {
477
483
  w: number;
478
484
  h: number;
479
485
  }
486
+ /** One word's ink box within a laid-out line, in the Text node's draw space. */
487
+ interface WordBox {
488
+ text: string;
489
+ /** laid-out line index (blank lines keep their slot in the numbering) */
490
+ line: number;
491
+ x: number;
492
+ y: number;
493
+ w: number;
494
+ h: number;
495
+ }
480
496
  interface TextProps extends NodeProps {
481
497
  text?: PropInit<string>;
482
498
  fill?: PropInit<string>;
@@ -526,6 +542,15 @@ declare class Text extends Node {
526
542
  * reveals, selections.
527
543
  */
528
544
  lineBoxes(measurer?: TextMeasurer): LineBox[];
545
+ /**
546
+ * Per-word ink boxes within each laid-out line — the SAME segmentation the
547
+ * breaker flows (Intl.Segmenter boundaries, punctuation glued), positioned
548
+ * by cumulative prefix advances so cross-word kerning is exact and word
549
+ * widths sum to the line's width. Whitespace contributes advance but no
550
+ * box. Pair index-wise with a narration manifest's word timestamps for
551
+ * karaoke; draw your own rects for sub-line multi-color token work.
552
+ */
553
+ wordBoxes(measurer?: TextMeasurer): WordBox[];
529
554
  protected draw(out: DisplayListBuilder, ctx: EvalContext): void;
530
555
  }
531
556
  //#endregion
@@ -577,4 +602,4 @@ declare function setLayoutEngine(e: LayoutEngine): void;
577
602
  declare function getLayoutEngine(): LayoutEngine | null;
578
603
  declare function requireLayoutEngine(): LayoutEngine;
579
604
  //#endregion
580
- export { glow as $, PropInit as A, DrawCommand as B, roundedRectSegs as C, HitArea as D, EvalContext as E, estimatingMeasurer as F, PathSeg as G, FilterValidationError as H, quantize as I, ResourceId as J, Rect$1 as K, BlendMode as L, TextMeasurer as M, TextMetricsLite as N, Node as O, breakLines as P, filtersToCanvasFilter as Q, DisplayList as R, VideoProps as S, BindablePropTarget as T, FontSpec as U, FilterSpec as V, Paint as W, StrokeStyle as X, ShaderRef as Y, createDisplayListBuilder as Z, Rect as _, LayoutEngineMissingError as a, invert as at, TextProps as b, requireLayoutEngine as c, Group as d, validateFilters as et, ImageNode as f, PathProps as g, Path as h, LayoutEngine as i, fromTRS as it, resolveAnchor as j, NodeProps as k, setLayoutEngine as l, LineBox as m, LayoutChildSpec as n, Mat2x3 as nt, LayoutResult as o, matEquals as ot, ImageProps as p, Resource as q, LayoutContainerSpec as r, applyToPoint as rt, getLayoutEngine as s, multiply as st, LayoutBox as t, IDENTITY as tt, Circle as u, ShapeProps as v, AnchorSpec as w, Video as x, Text as y, DisplayListBuilder as z };
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 };
@@ -166,6 +166,11 @@ const estimatingMeasurer = { measureText(text, font) {
166
166
  };
167
167
  } };
168
168
  let wordSegmenter;
169
+ /**
170
+ * The draw-path word segmentation (Intl.Segmenter boundaries, punctuation
171
+ * glued to its predecessor) — exported so Text.wordBoxes() boxes EXACTLY the
172
+ * units the breaker flows.
173
+ */
169
174
  function segmentWords(text) {
170
175
  if (wordSegmenter === void 0) wordSegmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "word" }) : null;
171
176
  if (wordSegmenter) {
@@ -922,6 +927,53 @@ var Text = class extends Node {
922
927
  }
923
928
  return boxes;
924
929
  }
930
+ /**
931
+ * Per-word ink boxes within each laid-out line — the SAME segmentation the
932
+ * breaker flows (Intl.Segmenter boundaries, punctuation glued), positioned
933
+ * by cumulative prefix advances so cross-word kerning is exact and word
934
+ * widths sum to the line's width. Whitespace contributes advance but no
935
+ * box. Pair index-wise with a narration manifest's word timestamps for
936
+ * karaoke; draw your own rects for sub-line multi-color token work.
937
+ */
938
+ wordBoxes(measurer) {
939
+ const m = measurer ?? this.measurerSource?.() ?? estimatingMeasurer;
940
+ const text = this.text();
941
+ if (!text) return [];
942
+ const font = {
943
+ family: this.fontFamily,
944
+ size: this.fontSize(),
945
+ weight: this.fontWeight
946
+ };
947
+ const maxWidth = this.width();
948
+ const lines = breakLines(text, font, maxWidth > 0 ? maxWidth : void 0, m);
949
+ const step = quantize(font.size * this.lineHeight);
950
+ const boxes = [];
951
+ for (let i = 0; i < lines.length; i++) {
952
+ const line = lines[i];
953
+ if (!line) continue;
954
+ const met = m.measureText(line, font);
955
+ const lineW = quantize(met.width);
956
+ const lineX = this.align === "left" ? 0 : this.align === "center" ? -lineW / 2 : -lineW;
957
+ const y = i * step - met.ascent;
958
+ const h = met.ascent + met.descent;
959
+ let prefix = "";
960
+ for (const seg of segmentWords(line)) {
961
+ const before = prefix === "" ? 0 : m.measureText(prefix, font).width;
962
+ prefix += seg;
963
+ if (seg.trim() === "") continue;
964
+ const after = m.measureText(prefix, font).width;
965
+ boxes.push({
966
+ text: seg,
967
+ line: i,
968
+ x: lineX + before,
969
+ y,
970
+ w: after - before,
971
+ h
972
+ });
973
+ }
974
+ }
975
+ return boxes;
976
+ }
925
977
  draw(out, ctx) {
926
978
  const text = this.text();
927
979
  if (!text) return;
@@ -970,4 +1022,4 @@ function requireLayoutEngine() {
970
1022
  return engine;
971
1023
  }
972
1024
  //#endregion
973
- export { IDENTITY as C, matEquals as D, invert as E, multiply as O, validateFilters as S, fromTRS as T, quantize as _, Circle as a, filtersToCanvasFilter as b, Path as c, Video as d, roundedRectSegs as f, estimatingMeasurer as g, breakLines as h, setLayoutEngine as i, 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, FilterValidationError as v, applyToPoint as w, glow as x, createDisplayListBuilder as y };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
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.1"
23
+ "@glissade/core": "0.4.2"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",