@glissade/scene 0.27.0 → 0.27.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/describe.js CHANGED
@@ -22,7 +22,7 @@ import { easings, listValueTypes } from "@glissade/core";
22
22
  * never pulled onto the base embed path — a scene that never calls `describe()`
23
23
  * pays zero bytes for it.
24
24
  */
25
- const RAW_VERSION = "0.27.0";
25
+ const RAW_VERSION = "0.27.1";
26
26
  const PACKAGE_VERSION = RAW_VERSION.includes("GLISSADE_".concat("VERSION")) ? "0.0.0-dev" : RAW_VERSION;
27
27
  /** Arity of a value type's numeric repr: vec2/vec2-arc → 2, number → 1; others (color/paint/path/string/boolean) carry no scalar arity. */
28
28
  function arityOf(type) {
package/dist/index.d.ts CHANGED
@@ -506,6 +506,9 @@ interface Ctx2DLike<TPath, TDrawable> {
506
506
  * blit it (clip + drawImage). Both DOM and @napi-rs/canvas expose these. */
507
507
  createImageData(w: number, h: number): ImageDataLike;
508
508
  putImageData(data: ImageDataLike, x: number, y: number): void;
509
+ /** Read straight-RGBA back out — used to persist a cached layer's raster to
510
+ * the disk layer store (§3.5 tier). Both DOM and @napi-rs/canvas expose it. */
511
+ getImageData(sx: number, sy: number, sw: number, sh: number): ImageDataLike;
509
512
  }
510
513
  /** The structural ImageData surface the mesh blit drives — DOM ImageData and
511
514
  * @napi-rs/canvas ImageData both satisfy it (writable `.data`). */
@@ -534,10 +537,48 @@ interface Raster2DHost<TCanvas extends CanvasLike, TPath extends PathLike, TDraw
534
537
  }
535
538
  type ShaderCaps = 'warn' | 'error';
536
539
  declare function fontString(font: FontSpec): string;
540
+ interface Bounds {
541
+ minX: number;
542
+ minY: number;
543
+ maxX: number;
544
+ maxY: number;
545
+ }
546
+ /**
547
+ * §3.5 DISK layer-cache tier. The in-memory raster LRU below spans one render;
548
+ * an injected `LayerStore` persists a cached layer's DEVICE-space RGBA across
549
+ * renders (and re-narrations), so an expensive static subtree — a blurred mesh
550
+ * backdrop — rasterizes ONCE and re-blits on later runs even when the whole-frame
551
+ * cache is defeated by a caption/timing change. The store is injected (scene stays
552
+ * Node-dep-free); the CLI provides an fs-backed impl that salts the key with the
553
+ * toolchain version + backend caps + frame size. A restored RGBA composites
554
+ * byte-identically to a fresh raster (getImageData → store → putImageData
555
+ * round-trips exactly — the same guarantee the frame cache relies on).
556
+ */
557
+ interface LayerCacheEntry {
558
+ /** straight-RGBA of the full w×h device-space layer canvas */
559
+ readonly rgba: Uint8ClampedArray;
560
+ readonly w: number;
561
+ readonly h: number;
562
+ /** device-space painted bounds (or null); rides along — the hit can't recompute it */
563
+ readonly bounds: Bounds | null;
564
+ readonly unbounded: boolean;
565
+ }
566
+ interface LayerStore {
567
+ /** key = `<sub-DisplayList fnv1a>@<deviceTransformKey>` (the store salts version/caps/size). */
568
+ get(key: string): LayerCacheEntry | undefined;
569
+ put(key: string, entry: LayerCacheEntry): void;
570
+ }
537
571
  declare class Raster2D<TCanvas extends CanvasLike, TPath extends PathLike, TDrawable> {
538
572
  private readonly host;
539
573
  /** caps.shaders (§3.7): what happens when a shader can't run here. */
540
574
  private readonly shaderCaps;
575
+ /**
576
+ * §3.5 disk layer-cache tier: an injected persistent store for cached-layer
577
+ * rasters (spans renders, survives re-narration). Undefined = in-memory only.
578
+ * Also settable post-construction (the CLI needs backend caps to salt the
579
+ * store's key, which aren't known until the backend exists).
580
+ */
581
+ private layerStore;
541
582
  private readonly pool;
542
583
  private readonly pathCache;
543
584
  private readonly pathBoundsCache;
@@ -560,7 +601,16 @@ declare class Raster2D<TCanvas extends CanvasLike, TPath extends PathLike, TDraw
560
601
  * RASTER_CACHE=0 force-disables it (the equality test renders both ways).
561
602
  * A disabled cache is byte-identical — it just always takes the miss path.
562
603
  */
563
- cacheEnabled?: boolean);
604
+ cacheEnabled?: boolean,
605
+ /**
606
+ * §3.5 disk layer-cache tier: an injected persistent store for cached-layer
607
+ * rasters (spans renders, survives re-narration). Undefined = in-memory only.
608
+ * Also settable post-construction (the CLI needs backend caps to salt the
609
+ * store's key, which aren't known until the backend exists).
610
+ */
611
+ layerStore?: LayerStore | undefined);
612
+ /** Attach (or clear) the §3.5 disk layer-cache store after construction. */
613
+ setLayerStore(store: LayerStore | undefined): void;
564
614
  /** Register a decoded still (kind 'image' assets). */
565
615
  setImageAsset(assetId: string, image: TDrawable): void;
566
616
  /** Register a warmed-on-demand video source (kind 'video' assets, §3.8). */
@@ -641,4 +691,4 @@ declare function meshRasterSize(bw: number, bh: number): {
641
691
  h: number;
642
692
  };
643
693
  //#endregion
644
- export { ALL_FILTER_KINDS, type AnchorSpec, type BackendCaps, type BindablePropTarget, type BlendMode, type CanvasLike, Circle, ColdAssetError, type Ctx2DLike, Custom, DeterminismViolationError, type DisplayList, type DisplayListBuilder, type DrawCommand, type DrawOnEachOptions, type DrawOnOptions, DuplicateNodeIdError, type EachBox, type EachContext, type EachDistribute, EachError, type EachLayout, type EachMotion, type EachOpts, type EachResult, Echo, type EchoProps, type EditMark, type EvalContext, type FilterKind, type FilterSpec, FilterValidationError, type FontByteLoader, type FontSpec, type GraphemeBox, Group, type GuardMode, type HachureSpec, Highlight, type HighlightProps, type HitArea, IDENTITY, ImageNode as Image, ImageNode, type ImageDataLike, type ImageHandle, type ImageProps, type LayoutBox, type LayoutChildSpec, type LayoutContainerSpec, type LayoutEngine, LayoutEngineMissingError, type LineBox, MEASURE_QUANTUM_PX, MESH_DOWNSCALE, MESH_SHEPARD_POWER, MESH_SIGMA, type Mat2x3, type MeshInterpolation, type MeshPaint, type MeshPoint, NODE_TAXONOMY, Node, NodeConstructionError, type NodeProps, type NodeTypeName, type Paint, Path, type PathLike, type PathProps, type PathSeg, type Place, type Polyline, type PropInit, Raster2D, type Raster2DHost, Rect, type Rect$1 as RectShape, type RenderBackend, ReservedNodeIdError, type ResolvedSketch, type Resource, type ResourceId, type RevealMark, type Scene, type SceneInit, type SceneModule, type ShaderCaps, ShaderEffect, type ShaderEffectProps, type ShaderRef, type ShapeProps, type SketchStyle, SketchValidationError, type StepMark, type StrokeStyle, Text, TextCursor, type TextCursorProps, type TextMeasurer, type TextMetricsLite, type TextProps, type TypeEdit, type TypewriterResult, type ValidateSceneFontsOptions, Video, type VideoFrameSource, type VideoProps, type WordBox, type WrappedTextMetrics, __resetEstimateWarnings, applyToPoint, arcLength, assertFiniteFontSize, bindScene, breakLines, coercePathData, collapseReplacer, collectLocalizedTextUsages, collectTextUsages, createDisplayListBuilder, createScene, drawOn, drawOnEach, each, echo, estimatingMeasurer, evaluate, filtersToCanvasFilter, flatten, fontString, fromTRS, getLayoutEngine, glow, hachureLines, highlight, invert, isEstimatingMeasurer, matEquals, measureWrappedText, meshRasterSize, multiply, pathFromSegs, quantize, rasterizeMesh, requireLayoutEngine, resolveAnchor, resolveSketch, revealSchedule, roughen, roundedRectSegs, segmentGraphemes, segmentWords, setDefaultMeasurer, setLayoutEngine, sketchStrokes, textCursor, typewriter, validateFilters, validateHachure, validateSceneFonts, validateSketch, withDeterminismGuards };
694
+ export { ALL_FILTER_KINDS, type AnchorSpec, type BackendCaps, type BindablePropTarget, type BlendMode, type Bounds, type CanvasLike, Circle, ColdAssetError, type Ctx2DLike, Custom, DeterminismViolationError, type DisplayList, type DisplayListBuilder, type DrawCommand, type DrawOnEachOptions, type DrawOnOptions, DuplicateNodeIdError, type EachBox, type EachContext, type EachDistribute, EachError, type EachLayout, type EachMotion, type EachOpts, type EachResult, Echo, type EchoProps, type EditMark, type EvalContext, type FilterKind, type FilterSpec, FilterValidationError, type FontByteLoader, type FontSpec, type GraphemeBox, Group, type GuardMode, type HachureSpec, Highlight, type HighlightProps, type HitArea, IDENTITY, ImageNode as Image, ImageNode, type ImageDataLike, type ImageHandle, type ImageProps, type LayerCacheEntry, type LayerStore, type LayoutBox, type LayoutChildSpec, type LayoutContainerSpec, type LayoutEngine, LayoutEngineMissingError, type LineBox, MEASURE_QUANTUM_PX, MESH_DOWNSCALE, MESH_SHEPARD_POWER, MESH_SIGMA, type Mat2x3, type MeshInterpolation, type MeshPaint, type MeshPoint, NODE_TAXONOMY, Node, NodeConstructionError, type NodeProps, type NodeTypeName, type Paint, Path, type PathLike, type PathProps, type PathSeg, type Place, type Polyline, type PropInit, Raster2D, type Raster2DHost, Rect, type Rect$1 as RectShape, type RenderBackend, ReservedNodeIdError, type ResolvedSketch, type Resource, type ResourceId, type RevealMark, type Scene, type SceneInit, type SceneModule, type ShaderCaps, ShaderEffect, type ShaderEffectProps, type ShaderRef, type ShapeProps, type SketchStyle, SketchValidationError, type StepMark, type StrokeStyle, Text, TextCursor, type TextCursorProps, type TextMeasurer, type TextMetricsLite, type TextProps, type TypeEdit, type TypewriterResult, type ValidateSceneFontsOptions, Video, type VideoFrameSource, type VideoProps, type WordBox, type WrappedTextMetrics, __resetEstimateWarnings, applyToPoint, arcLength, assertFiniteFontSize, bindScene, breakLines, coercePathData, collapseReplacer, collectLocalizedTextUsages, collectTextUsages, createDisplayListBuilder, createScene, drawOn, drawOnEach, each, echo, estimatingMeasurer, evaluate, filtersToCanvasFilter, flatten, fontString, fromTRS, getLayoutEngine, glow, hachureLines, highlight, invert, isEstimatingMeasurer, matEquals, measureWrappedText, meshRasterSize, multiply, pathFromSegs, quantize, rasterizeMesh, requireLayoutEngine, resolveAnchor, resolveSketch, revealSchedule, roughen, roundedRectSegs, segmentGraphemes, segmentWords, setDefaultMeasurer, setLayoutEngine, sketchStrokes, textCursor, typewriter, validateFilters, validateHachure, validateSceneFonts, validateSketch, withDeterminismGuards };
package/dist/index.js CHANGED
@@ -969,6 +969,7 @@ function segsBounds(segs) {
969
969
  var Raster2D = class {
970
970
  host;
971
971
  shaderCaps;
972
+ layerStore;
972
973
  pool = [];
973
974
  pathCache = /* @__PURE__ */ new WeakMap();
974
975
  pathBoundsCache = /* @__PURE__ */ new WeakMap();
@@ -984,11 +985,16 @@ var Raster2D = class {
984
985
  */
985
986
  rasterCache = /* @__PURE__ */ new Map();
986
987
  cacheEnabled;
987
- constructor(host, shaderCaps = "warn", cacheEnabled = (globalThis.process?.env?.["RASTER_CACHE"] ?? "1") !== "0") {
988
+ constructor(host, shaderCaps = "warn", cacheEnabled = (globalThis.process?.env?.["RASTER_CACHE"] ?? "1") !== "0", layerStore = void 0) {
988
989
  this.host = host;
989
990
  this.shaderCaps = shaderCaps;
991
+ this.layerStore = layerStore;
990
992
  this.cacheEnabled = cacheEnabled;
991
993
  }
994
+ /** Attach (or clear) the §3.5 disk layer-cache store after construction. */
995
+ setLayerStore(store) {
996
+ this.layerStore = store;
997
+ }
992
998
  /** Register a decoded still (kind 'image' assets). */
993
999
  setImageAsset(assetId, image) {
994
1000
  this.images.set(assetId, image);
@@ -1298,6 +1304,28 @@ var Raster2D = class {
1298
1304
  }
1299
1305
  break;
1300
1306
  }
1307
+ const disk = this.layerStore?.get(lruKey);
1308
+ if (disk !== void 0 && disk.w === w && disk.h === h) {
1309
+ const canvas = this.acquire(w, h);
1310
+ const dctx = this.host.context(canvas);
1311
+ dctx.resetTransform();
1312
+ const img = dctx.createImageData(w, h);
1313
+ img.data.set(disk.rgba);
1314
+ dctx.putImageData(img, 0, 0);
1315
+ this.cacheStore(lruKey, {
1316
+ canvas,
1317
+ bounds: disk.bounds,
1318
+ unbounded: disk.unbounded
1319
+ });
1320
+ this.composite(parent, top(), canvas, disk.bounds, disk.unbounded, false, cmd.opacity, cmd.blend, filtersToCanvasFilter(cmd.filters), cmd.filters, w, h);
1321
+ let depth = 1;
1322
+ while (depth > 0 && ++ci < commands.length) {
1323
+ const c = commands[ci];
1324
+ if (c.op === "pushGroup") depth++;
1325
+ else if (c.op === "popGroup") depth--;
1326
+ }
1327
+ break;
1328
+ }
1301
1329
  }
1302
1330
  const layerCanvas = this.acquire(w, h);
1303
1331
  const layerCtx = this.host.context(layerCanvas);
@@ -1343,12 +1371,23 @@ var Raster2D = class {
1343
1371
  }
1344
1372
  }
1345
1373
  this.composite(parent, top(), drawable, layer.bounds, layer.unbounded, shaderReplaced, layer.opacity, layer.blend, layer.filter, layer.filters, w, h);
1346
- if (layer.cacheStoreKey !== void 0 && !shaderReplaced) this.cacheStore(layer.cacheStoreKey, {
1347
- canvas: layer.canvas,
1348
- bounds: layer.bounds,
1349
- unbounded: layer.unbounded
1350
- });
1351
- else this.release(layer.canvas);
1374
+ if (layer.cacheStoreKey !== void 0 && !shaderReplaced) {
1375
+ this.cacheStore(layer.cacheStoreKey, {
1376
+ canvas: layer.canvas,
1377
+ bounds: layer.bounds,
1378
+ unbounded: layer.unbounded
1379
+ });
1380
+ if (this.layerStore !== void 0) {
1381
+ const rgba = this.host.context(layer.canvas).getImageData(0, 0, w, h).data;
1382
+ this.layerStore.put(layer.cacheStoreKey, {
1383
+ rgba,
1384
+ w,
1385
+ h,
1386
+ bounds: layer.bounds,
1387
+ unbounded: layer.unbounded
1388
+ });
1389
+ }
1390
+ } else this.release(layer.canvas);
1352
1391
  break;
1353
1392
  }
1354
1393
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
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": {
@@ -65,7 +65,7 @@
65
65
  ],
66
66
  "dependencies": {
67
67
  "yoga-layout": "^3.2.1",
68
- "@glissade/core": "0.27.0"
68
+ "@glissade/core": "0.27.1"
69
69
  },
70
70
  "repository": {
71
71
  "type": "git",