@glissade/scene 0.10.0 → 0.10.1-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 +6 -0
- package/dist/index.js +59 -8
- package/dist/layoutEngine.d.ts +7 -8
- package/dist/layoutEngine.js +10 -9
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -440,6 +440,10 @@ declare class ShaderEffect extends Group {
|
|
|
440
440
|
}
|
|
441
441
|
//#endregion
|
|
442
442
|
//#region src/raster2d.d.ts
|
|
443
|
+
/** A backend gradient handle (DOM CanvasGradient and @napi-rs CanvasGradient both satisfy it). */
|
|
444
|
+
interface CanvasGradientLike {
|
|
445
|
+
addColorStop(offset: number, color: string): void;
|
|
446
|
+
}
|
|
443
447
|
/** The structural path surface buildPath drives — DOM Path2D and @napi-rs Path2D both satisfy it. */
|
|
444
448
|
interface PathLike {
|
|
445
449
|
moveTo(x: number, y: number): void;
|
|
@@ -468,6 +472,8 @@ interface Ctx2DLike<TPath, TDrawable> {
|
|
|
468
472
|
drawImage(image: TDrawable, x: number, y: number, w?: number, h?: number): void;
|
|
469
473
|
drawImage(image: TDrawable, sx: number, sy: number, sw: number, sh: number, x: number, y: number, w: number, h: number): void;
|
|
470
474
|
setLineDash(segments: number[]): void;
|
|
475
|
+
createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradientLike;
|
|
476
|
+
createLinearGradient(x0: number, y0: number, x1: number, y1: number): CanvasGradientLike;
|
|
471
477
|
lineDashOffset: number;
|
|
472
478
|
fillStyle: unknown;
|
|
473
479
|
strokeStyle: unknown;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as quantize, B as applyToPoint, C as validateSketch, D as breakLines, E as MEASURE_QUANTUM_PX, F as createDisplayListBuilder, H as invert, I as filtersToCanvasFilter, L as glow, M as segmentWords, N as setDefaultMeasurer, O as estimatingMeasurer, P as FilterValidationError, R as validateFilters, S as validateHachure, T as resolveAnchor, U as matEquals, V as fromTRS, W as multiply, _ as flatten, a as Circle, b as roughen, c as Path, d as Video, f as pathFromSegs, g as arcLength, h as SketchValidationError, i as setLayoutEngine, j as segmentGraphemes, k as fallbackMeasurer, l as Rect, m as roundedRectSegs, n as getLayoutEngine, o as Group, p as revealSchedule, r as requireLayoutEngine, s as ImageNode, t as LayoutEngineMissingError, u as Text, v as hachureLines, w as Node, x as sketchStrokes, y as resolveSketch, z as IDENTITY } from "./layoutEngine.js";
|
|
2
|
-
import { bindTimeline, buildFontRegistry, compileTimeline, createPlayhead, emitDevWarning, evaluateAt, key, parseCmap, signal, stagger, track, validateFonts, vec2Signal } from "@glissade/core";
|
|
2
|
+
import { bindTimeline, buildFontRegistry, compileTimeline, createPlayhead, emitDevWarning, evaluateAt, key, lerpColor, parseCmap, signal, stagger, track, validateFonts, vec2Signal } from "@glissade/core";
|
|
3
3
|
//#region src/highlight.ts
|
|
4
4
|
/**
|
|
5
5
|
* Marker-style text highlight: per-line rounded rects behind a Text node's
|
|
@@ -958,6 +958,38 @@ var ShaderEffect = class extends Group {
|
|
|
958
958
|
};
|
|
959
959
|
}
|
|
960
960
|
};
|
|
961
|
+
const smoothstep = (u) => u * u * (3 - 2 * u);
|
|
962
|
+
const GAUSS_K = 2.4;
|
|
963
|
+
const GAUSS_NORM = 1 - Math.exp(-5.76 / 2);
|
|
964
|
+
const gaussianEase = (u) => (1 - Math.exp(-((u * GAUSS_K) ** 2) / 2)) / GAUSS_NORM;
|
|
965
|
+
/**
|
|
966
|
+
* Densify `stops` into a `smooth`/`gaussian` oklab ramp. The output spans the
|
|
967
|
+
* input's offset range with GRADIENT_RAMP_STEPS uniformly-spaced stops; each
|
|
968
|
+
* point eases its blend within the authored segment it falls in. Returns the
|
|
969
|
+
* input unchanged for `linear` (or a single stop) — the canvas-native path.
|
|
970
|
+
*/
|
|
971
|
+
function densifyStops(stops, mode) {
|
|
972
|
+
if (mode === "linear" || stops.length < 2) return stops;
|
|
973
|
+
const ease = mode === "gaussian" ? gaussianEase : smoothstep;
|
|
974
|
+
const o0 = stops[0].offset;
|
|
975
|
+
const span = stops[stops.length - 1].offset - o0;
|
|
976
|
+
if (span <= 0) return stops;
|
|
977
|
+
const out = [];
|
|
978
|
+
let seg = 0;
|
|
979
|
+
for (let i = 0; i < 64; i++) {
|
|
980
|
+
const offset = o0 + span * (i / 63);
|
|
981
|
+
while (seg < stops.length - 2 && offset > stops[seg + 1].offset) seg++;
|
|
982
|
+
const a = stops[seg];
|
|
983
|
+
const b = stops[seg + 1];
|
|
984
|
+
const w = b.offset - a.offset;
|
|
985
|
+
const u = w > 0 ? Math.min(1, Math.max(0, (offset - a.offset) / w)) : 0;
|
|
986
|
+
out.push({
|
|
987
|
+
offset,
|
|
988
|
+
color: lerpColor(a.color, b.color, ease(u))
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
return out;
|
|
992
|
+
}
|
|
961
993
|
//#endregion
|
|
962
994
|
//#region src/raster2d.ts
|
|
963
995
|
/**
|
|
@@ -967,6 +999,25 @@ var ShaderEffect = class extends Group {
|
|
|
967
999
|
* four-line adapters, so the twin rasterizers structurally cannot drift —
|
|
968
1000
|
* the golden + SSIM suites verify the refactor preserved every byte.
|
|
969
1001
|
*/
|
|
1002
|
+
function resolveFill(ctx, paint, bounds) {
|
|
1003
|
+
if (paint.kind === "color") return paint.color;
|
|
1004
|
+
let g;
|
|
1005
|
+
if (paint.kind === "radial") {
|
|
1006
|
+
const cx = paint.center ? paint.center[0] : bounds ? (bounds.minX + bounds.maxX) / 2 : 0;
|
|
1007
|
+
const cy = paint.center ? paint.center[1] : bounds ? (bounds.minY + bounds.maxY) / 2 : 0;
|
|
1008
|
+
const r = paint.radius !== void 0 ? paint.radius : bounds ? Math.hypot(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 2 : 0;
|
|
1009
|
+
g = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);
|
|
1010
|
+
} else {
|
|
1011
|
+
const fx = paint.from ? paint.from[0] : bounds ? (bounds.minX + bounds.maxX) / 2 : 0;
|
|
1012
|
+
const fy = paint.from ? paint.from[1] : bounds ? bounds.minY : 0;
|
|
1013
|
+
const tx = paint.to ? paint.to[0] : bounds ? (bounds.minX + bounds.maxX) / 2 : 0;
|
|
1014
|
+
const ty = paint.to ? paint.to[1] : bounds ? bounds.maxY : 0;
|
|
1015
|
+
g = ctx.createLinearGradient(fx, fy, tx, ty);
|
|
1016
|
+
}
|
|
1017
|
+
const stops = paint.interpolation ? densifyStops(paint.stops, paint.interpolation) : paint.stops;
|
|
1018
|
+
for (const s of stops) g.addColorStop(s.offset, s.color);
|
|
1019
|
+
return g;
|
|
1020
|
+
}
|
|
970
1021
|
function fontString(font) {
|
|
971
1022
|
return `${font.style === "italic" ? "italic " : ""}${font.weight !== void 0 && font.weight !== 400 ? `${font.weight} ` : ""}${font.size}px ${font.family}`;
|
|
972
1023
|
}
|
|
@@ -1260,15 +1311,16 @@ var Raster2D = class {
|
|
|
1260
1311
|
break;
|
|
1261
1312
|
case "fillPath": {
|
|
1262
1313
|
const ctx = ctxOf();
|
|
1263
|
-
ctx.fillStyle = cmd.paint.color;
|
|
1264
|
-
ctx.fill(this.path(list.resources, cmd.path));
|
|
1265
1314
|
const b = this.pathBounds(list.resources, cmd.path);
|
|
1315
|
+
ctx.fillStyle = resolveFill(ctx, cmd.paint, b);
|
|
1316
|
+
ctx.fill(this.path(list.resources, cmd.path));
|
|
1266
1317
|
if (b) accumulateRect(top(), mat, b.minX, b.minY, b.maxX, b.maxY);
|
|
1267
1318
|
break;
|
|
1268
1319
|
}
|
|
1269
1320
|
case "strokePath": {
|
|
1270
1321
|
const ctx = ctxOf();
|
|
1271
|
-
|
|
1322
|
+
const sb = this.pathBounds(list.resources, cmd.path);
|
|
1323
|
+
ctx.strokeStyle = resolveFill(ctx, cmd.paint, sb);
|
|
1272
1324
|
ctx.lineWidth = cmd.stroke.width;
|
|
1273
1325
|
ctx.lineCap = cmd.stroke.cap ?? "butt";
|
|
1274
1326
|
ctx.lineJoin = cmd.stroke.join ?? "miter";
|
|
@@ -1281,17 +1333,16 @@ var Raster2D = class {
|
|
|
1281
1333
|
ctx.setLineDash([]);
|
|
1282
1334
|
ctx.lineDashOffset = 0;
|
|
1283
1335
|
}
|
|
1284
|
-
|
|
1285
|
-
if (b) {
|
|
1336
|
+
if (sb) {
|
|
1286
1337
|
const o = cmd.stroke.width * ((cmd.stroke.join ?? "miter") === "miter" ? 5 : 1);
|
|
1287
|
-
accumulateRect(top(), mat,
|
|
1338
|
+
accumulateRect(top(), mat, sb.minX - o, sb.minY - o, sb.maxX + o, sb.maxY + o);
|
|
1288
1339
|
}
|
|
1289
1340
|
break;
|
|
1290
1341
|
}
|
|
1291
1342
|
case "fillText": {
|
|
1292
1343
|
const ctx = ctxOf();
|
|
1293
1344
|
ctx.font = fontString(cmd.font);
|
|
1294
|
-
ctx.fillStyle = cmd.paint
|
|
1345
|
+
ctx.fillStyle = resolveFill(ctx, cmd.paint, null);
|
|
1295
1346
|
ctx.textBaseline = "alphabetic";
|
|
1296
1347
|
ctx.textAlign = cmd.align ?? "left";
|
|
1297
1348
|
ctx.fillText(cmd.text, cmd.x, cmd.y);
|
package/dist/layoutEngine.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BindableSignal, PathValue, ReadonlySignal, Rng, Track, Vec2, Vec2Signal } from "@glissade/core";
|
|
1
|
+
import { BindableSignal, Paint, PathValue, ReadonlySignal, Rng, Track, Vec2, Vec2Signal } from "@glissade/core";
|
|
2
2
|
|
|
3
3
|
//#region src/matrix.d.ts
|
|
4
4
|
|
|
@@ -33,11 +33,6 @@ type Resource = {
|
|
|
33
33
|
mediaT: number;
|
|
34
34
|
};
|
|
35
35
|
type BlendMode = 'source-over' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten';
|
|
36
|
-
/** M1: solid colors. Gradients/patterns are additive later — backends switch on kind. */
|
|
37
|
-
type Paint = {
|
|
38
|
-
kind: 'color';
|
|
39
|
-
color: string;
|
|
40
|
-
};
|
|
41
36
|
interface StrokeStyle {
|
|
42
37
|
width: number;
|
|
43
38
|
cap?: 'butt' | 'round' | 'square';
|
|
@@ -498,8 +493,12 @@ declare class Group extends Node {
|
|
|
498
493
|
remove(child: Node): this;
|
|
499
494
|
protected draw(out: DisplayListBuilder, ctx: EvalContext): void;
|
|
500
495
|
}
|
|
496
|
+
/** A color string is sugar for a solid `color` Paint; a Paint passes through. */
|
|
497
|
+
|
|
501
498
|
interface ShapeProps extends NodeProps {
|
|
502
|
-
|
|
499
|
+
/** A CSS color string, or a `Paint` (e.g. a `radial` gradient — soft-light
|
|
500
|
+
* fills with no blur filter; center/radius default to the shape bounds). */
|
|
501
|
+
fill?: PropInit<string | Paint>;
|
|
503
502
|
stroke?: PropInit<string>;
|
|
504
503
|
strokeWidth?: PropInit<number>;
|
|
505
504
|
/** hand-drawn look: the outline is geometrically roughened (see sketch.ts) */
|
|
@@ -515,7 +514,7 @@ interface ShapeProps extends NodeProps {
|
|
|
515
514
|
sketchFill?: HachureSpec;
|
|
516
515
|
}
|
|
517
516
|
declare abstract class Shape extends Node {
|
|
518
|
-
readonly fill: BindableSignal<string>;
|
|
517
|
+
readonly fill: BindableSignal<string | Paint>;
|
|
519
518
|
readonly stroke: BindableSignal<string>;
|
|
520
519
|
readonly strokeWidth: BindableSignal<number>;
|
|
521
520
|
readonly sketch: SketchStyle | undefined;
|
package/dist/layoutEngine.js
CHANGED
|
@@ -948,6 +948,13 @@ var Group = class extends Node {
|
|
|
948
948
|
for (const child of sorted) child.emit(out, ctx);
|
|
949
949
|
}
|
|
950
950
|
};
|
|
951
|
+
/** A color string is sugar for a solid `color` Paint; a Paint passes through. */
|
|
952
|
+
function toPaint(fill) {
|
|
953
|
+
return typeof fill === "string" ? {
|
|
954
|
+
kind: "color",
|
|
955
|
+
color: fill
|
|
956
|
+
} : fill;
|
|
957
|
+
}
|
|
951
958
|
var Shape = class extends Node {
|
|
952
959
|
fill;
|
|
953
960
|
stroke;
|
|
@@ -984,10 +991,7 @@ var Shape = class extends Node {
|
|
|
984
991
|
if (fill) out.push({
|
|
985
992
|
op: "fillPath",
|
|
986
993
|
path,
|
|
987
|
-
paint:
|
|
988
|
-
kind: "color",
|
|
989
|
-
color: fill
|
|
990
|
-
}
|
|
994
|
+
paint: toPaint(fill)
|
|
991
995
|
});
|
|
992
996
|
const stroke = this.stroke();
|
|
993
997
|
const width = this.strokeWidth();
|
|
@@ -1021,14 +1025,11 @@ var Shape = class extends Node {
|
|
|
1021
1025
|
out.push({
|
|
1022
1026
|
op: "fillPath",
|
|
1023
1027
|
path,
|
|
1024
|
-
paint:
|
|
1025
|
-
kind: "color",
|
|
1026
|
-
color: fill
|
|
1027
|
-
}
|
|
1028
|
+
paint: toPaint(fill)
|
|
1028
1029
|
});
|
|
1029
1030
|
}
|
|
1030
1031
|
const { strokes, resolved } = roughen(segs, this.sketch, rng);
|
|
1031
|
-
const ink = this.stroke() || fill || "#000000";
|
|
1032
|
+
const ink = this.stroke() || (typeof fill === "string" ? fill : "") || "#000000";
|
|
1032
1033
|
if (this.sketchFill) {
|
|
1033
1034
|
const clipPath = out.resource({
|
|
1034
1035
|
kind: "path",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/scene",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1-pre.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
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"yoga-layout": "^3.2.1",
|
|
23
|
-
"@glissade/core": "0.10.
|
|
23
|
+
"@glissade/core": "0.10.1-pre.1"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|