@glissade/scene 0.29.0 → 0.30.0-pre.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
@@ -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.29.0";
25
+ const RAW_VERSION = "0.30.0-pre.0";
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) {
@@ -345,6 +345,12 @@ const HELPERS = [
345
345
  import: "@glissade/scene",
346
346
  usage: "echo(child: Node, opts?: { id?, count?: number, spacing?: number, decay?: number }): Echo"
347
347
  },
348
+ {
349
+ name: "motionBlur",
350
+ summary: "Real sampled motion blur: wrap a child so it renders at N sub-frame times across a shutter interval (centered on the frame) and AVERAGES them — tracks every animated prop, not a faked directional blur. A pure multi-time re-eval (playhead re-addressed per sample, running-mean opacity, restored), byte-exact on Skia; browser↔Skia is perceptual-tier for blur.",
351
+ import: "@glissade/scene",
352
+ usage: "motionBlur(child: Node, opts?: { id?, shutter?: number, samples?: number }): MotionBlur"
353
+ },
348
354
  {
349
355
  name: "clip",
350
356
  summary: "A reusable, target-agnostic motion captured once as a relative-time key schedule, then applied to a node at a wall-clock start time. Build-time sugar: clip.apply() compiles to ordinary Track[].",
package/dist/examples.js CHANGED
@@ -5,7 +5,7 @@ import { Grid } from "./grid.js";
5
5
  import { Stack } from "./layoutCtors.js";
6
6
  import { splitText } from "./type.js";
7
7
  import { i as orientToPath, r as lookAt, s as motionPath } from "./orient.js";
8
- import { n as echo } from "./echo.js";
8
+ import { i as echo, n as motionBlur } from "./motionBlur.js";
9
9
  import { pathFromSvg } from "./path.js";
10
10
  import { key, retime, timeline, track } from "@glissade/core";
11
11
  //#region src/examples.ts
@@ -257,6 +257,18 @@ const EXAMPLES = [
257
257
  spacing: .05,
258
258
  decay: .7
259
259
  })
260
+ },
261
+ {
262
+ key: "motionBlur",
263
+ code: "import { Circle, motionBlur } from '@glissade/scene';\n// real sampled motion blur: renders the child at N sub-frame times across `shutter` (seconds) and averages them.\n// Wrap the MOVING content; its background stays crisp. Byte-exact on Skia, perceptual browser↔Skia.\nconst dot = new Circle({ id: 'dot', radius: 16, fill: '#ffcf3f' });\nconst blurred = motionBlur(dot, { shutter: 0.06, samples: 16 });",
264
+ run: () => void motionBlur(new Circle({
265
+ id: "dot",
266
+ radius: 16,
267
+ fill: "#ffcf3f"
268
+ }), {
269
+ shutter: .06,
270
+ samples: 16
271
+ })
260
272
  }
261
273
  ];
262
274
  /**
package/dist/index.d.ts CHANGED
@@ -445,6 +445,25 @@ declare class Echo extends Group {
445
445
  * A convenience wrapper: pass the trailing content as children of the returned Echo. */
446
446
  declare function echo(child: Node, props?: Omit<EchoProps, 'children'>): Echo;
447
447
  //#endregion
448
+ //#region src/motionBlur.d.ts
449
+ interface MotionBlurProps extends NodeProps {
450
+ children?: Node[];
451
+ /** the shutter interval in SECONDS, centered on the frame time (0 = no blur); default 0.04. */
452
+ shutter?: number;
453
+ /** number of sub-frame samples averaged across the shutter (≥ 1); default 8. */
454
+ samples?: number;
455
+ }
456
+ declare class MotionBlur extends Group {
457
+ get describeType(): string;
458
+ readonly shutter: number;
459
+ readonly samples: number;
460
+ constructor(props?: MotionBlurProps);
461
+ protected draw(out: DisplayListBuilder, ctx: EvalContext): void;
462
+ }
463
+ /** `children: [motionBlur(fastDot, { shutter: 0.05 })]` — fastDot smears with real
464
+ * sub-frame motion blur. Wrap the moving content; its background stays crisp. */
465
+ declare function motionBlur(child: Node, props?: Omit<MotionBlurProps, 'children'>): MotionBlur;
466
+ //#endregion
448
467
  //#region src/raster2d.d.ts
449
468
  /** A backend gradient handle (DOM CanvasGradient and @napi-rs CanvasGradient both satisfy it). */
450
469
  interface CanvasGradientLike {
@@ -691,4 +710,4 @@ declare function meshRasterSize(bw: number, bh: number): {
691
710
  h: number;
692
711
  };
693
712
  //#endregion
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 };
713
+ 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, MotionBlur, type MotionBlurProps, 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, motionBlur, 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
@@ -1,7 +1,7 @@
1
1
  import { $ as multiply, A as setDefaultMeasurer, B as validateHachure, C as estimatingMeasurer, D as quantize, E as measureWrappedText, F as hachureLines, G as glow, H as FilterValidationError, I as hashStr, J as IDENTITY, K as validateFilters, L as resolveSketch, M as SketchValidationError, N as arcLength, O as segmentGraphemes, P as flatten, Q as matEquals, R as roughen, S as breakLines, T as isEstimatingMeasurer, U as createDisplayListBuilder, V as validateSketch, W as filtersToCanvasFilter, X as fromTRS, Y as applyToPoint, Z as invert, a as Path, b as __resetEstimateWarnings, c as Video, d as revealSchedule, f as roundedRectSegs, h as resolveAnchor, i as ImageNode, k as segmentWords, l as coercePathData, m as NodeConstructionError, n as Custom, o as Rect, p as Node, q as collapseReplacer, r as Group, s as Text, t as Circle, u as pathFromSegs, x as assertFiniteFontSize, y as MEASURE_QUANTUM_PX, z as sketchStrokes } from "./nodes.js";
2
2
  import { a as evaluate, i as createScene, n as ReservedNodeIdError, r as bindScene, t as DuplicateNodeIdError } from "./scene.js";
3
3
  import { i as setLayoutEngine, n as getLayoutEngine, r as requireLayoutEngine, t as LayoutEngineMissingError } from "./layoutEngine.js";
4
- import { n as echo, t as Echo } from "./echo.js";
4
+ import { i as echo, n as motionBlur, r as Echo, t as MotionBlur } from "./motionBlur.js";
5
5
  import { buildFontRegistry, emitDevWarning, key, lerpColor, oklabToRgba, parseCmap, parseColor, random, rgbaToOklab, signal, stagger, track, validateFonts } from "@glissade/core";
6
6
  //#region src/taxonomy.ts
7
7
  /**
@@ -1396,4 +1396,4 @@ var Raster2D = class {
1396
1396
  }
1397
1397
  };
1398
1398
  //#endregion
1399
- export { ALL_FILTER_KINDS, Circle, ColdAssetError, Custom, DeterminismViolationError, DuplicateNodeIdError, EachError, Echo, FilterValidationError, Group, Highlight, IDENTITY, ImageNode as Image, ImageNode, LayoutEngineMissingError, MEASURE_QUANTUM_PX, MESH_DOWNSCALE, MESH_SHEPARD_POWER, MESH_SIGMA, NODE_TAXONOMY, Node, NodeConstructionError, Path, Raster2D, Rect, ReservedNodeIdError, ShaderEffect, SketchValidationError, Text, TextCursor, Video, __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 };
1399
+ export { ALL_FILTER_KINDS, Circle, ColdAssetError, Custom, DeterminismViolationError, DuplicateNodeIdError, EachError, Echo, FilterValidationError, Group, Highlight, IDENTITY, ImageNode as Image, ImageNode, LayoutEngineMissingError, MEASURE_QUANTUM_PX, MESH_DOWNSCALE, MESH_SHEPARD_POWER, MESH_SIGMA, MotionBlur, NODE_TAXONOMY, Node, NodeConstructionError, Path, Raster2D, Rect, ReservedNodeIdError, ShaderEffect, SketchValidationError, Text, TextCursor, Video, __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, motionBlur, multiply, pathFromSegs, quantize, rasterizeMesh, requireLayoutEngine, resolveAnchor, resolveSketch, revealSchedule, roughen, roundedRectSegs, segmentGraphemes, segmentWords, setDefaultMeasurer, setLayoutEngine, sketchStrokes, textCursor, typewriter, validateFilters, validateHachure, validateSceneFonts, validateSketch, withDeterminismGuards };
@@ -75,4 +75,77 @@ function echo(child, props = {}) {
75
75
  });
76
76
  }
77
77
  //#endregion
78
- export { echo as n, Echo as t };
78
+ //#region src/motionBlur.ts
79
+ /**
80
+ * MotionBlur (0.30): real sampled motion blur — the flagship motion-craft feature.
81
+ * It renders its subtree at N sub-frame times across a shutter interval centered on
82
+ * the current frame and AVERAGES them, so a fast-moving element smears exactly the
83
+ * way an analog shutter captures it — and it tracks EVERY animated prop (position,
84
+ * rotation, scale, path progress, colour), not a faked directional blur.
85
+ *
86
+ * Like `Echo`, it re-addresses the scene playhead within one frame (wrapped in
87
+ * `batch()`, restored after) to sample sub-frame times. The averaging is a running
88
+ * mean done with plain compositing, NO backend change: paint the k-th sample (of N)
89
+ * at opacity 1/(k+1). Over source-over that is the exact equal-weight mean —
90
+ * L₀=∅; Lₖ₊₁ = Lₖ·(k/(k+1)) + sₖ·(1/(k+1)) = mean(s₀…sₖ)
91
+ * — so all N samples contribute equally (unlike a decaying trail). Each sub-frame t
92
+ * is a pure function of the current time, so evaluate() stays deterministic and the
93
+ * result is byte-stable on Skia (the golden twin); browser↔Skia is perceptual-tier
94
+ * for blur, marked in describe().
95
+ *
96
+ * Ships on the base scene index alongside Echo/ShaderEffect (off the closed 9-node
97
+ * taxonomy). No blur ⇒ pass `samples: 1` or `shutter: 0` and it's a plain group.
98
+ */
99
+ var MotionBlur = class extends Group {
100
+ get describeType() {
101
+ return "MotionBlur";
102
+ }
103
+ shutter;
104
+ samples;
105
+ constructor(props = {}) {
106
+ super(props);
107
+ this.shutter = props.shutter ?? .04;
108
+ this.samples = Math.max(1, Math.floor(props.samples ?? 8));
109
+ }
110
+ draw(out, ctx) {
111
+ const playhead = ctx.playhead;
112
+ if (this.samples <= 1 || this.shutter === 0 || playhead === void 0) {
113
+ super.draw(out, ctx);
114
+ return;
115
+ }
116
+ const now = ctx.time;
117
+ const n = this.samples;
118
+ batch(() => {
119
+ try {
120
+ for (let i = 0; i < n; i++) {
121
+ const t = now + (i / (n - 1) - .5) * this.shutter;
122
+ const opacity = 1 / (i + 1);
123
+ playhead.forceSet(t);
124
+ out.push({
125
+ op: "pushGroup",
126
+ opacity,
127
+ blend: "source-over",
128
+ filters: []
129
+ });
130
+ super.draw(out, {
131
+ ...ctx,
132
+ time: t
133
+ });
134
+ out.push({ op: "popGroup" });
135
+ }
136
+ } finally {
137
+ playhead.forceSet(now);
138
+ }
139
+ });
140
+ }
141
+ };
142
+ /** `children: [motionBlur(fastDot, { shutter: 0.05 })]` — fastDot smears with real
143
+ * sub-frame motion blur. Wrap the moving content; its background stays crisp. */
144
+ function motionBlur(child, props = {}) {
145
+ return new MotionBlur({
146
+ ...props,
147
+ children: [child]
148
+ });
149
+ }
150
+ //#endregion
151
+ export { echo as i, motionBlur as n, Echo as r, MotionBlur as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.29.0",
3
+ "version": "0.30.0-pre.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": {
@@ -65,7 +65,7 @@
65
65
  ],
66
66
  "dependencies": {
67
67
  "yoga-layout": "^3.2.1",
68
- "@glissade/core": "0.29.0"
68
+ "@glissade/core": "0.30.0-pre.0"
69
69
  },
70
70
  "repository": {
71
71
  "type": "git",