@glissade/scene 0.21.0 → 0.22.0-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/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.21.0";
25
+ const RAW_VERSION = "0.22.0-pre.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) {
@@ -74,6 +74,7 @@ const CONSTRUCTION_PROP_META = {
74
74
  fontStyle: { type: "'normal'|'italic'" },
75
75
  align: { type: "'left'|'center'|'right'" },
76
76
  lineHeight: { type: "number" },
77
+ letterSpacing: { type: "number" },
77
78
  fontVariationSettings: { type: "string" }
78
79
  },
79
80
  Image: { assetId: {
@@ -58,6 +58,16 @@ interface FontSpec {
58
58
  * hard-throws `UnboundTargetError` (no signal resolves to it).
59
59
  */
60
60
  fontVariationSettings?: string;
61
+ /**
62
+ * Letter-spacing (tracking) in **px**, applied between glyphs. Maps 1:1 to
63
+ * `ctx.letterSpacing` on the canvas/Skia path (both `@napi-rs/canvas` and the
64
+ * modern browser 2D context honor it — and it affects `measureText`, so
65
+ * wrapping stays correct) and to CSS `letter-spacing` on the DOM backend.
66
+ * OMITTED for default Text, so a node without tracking emits a byte-identical
67
+ * FontSpec (the golden corpus depends on this). For em-relative tracking pass
68
+ * `em * fontSize` (px is the engine's unit everywhere else).
69
+ */
70
+ letterSpacing?: number;
61
71
  }
62
72
  /**
63
73
  * Group filters (§3.4): a CLOSED union — validated data, never a CSS
package/dist/index.js CHANGED
@@ -1243,6 +1243,8 @@ var Raster2D = class {
1243
1243
  case "fillText": {
1244
1244
  const ctx = ctxOf();
1245
1245
  ctx.font = fontString(cmd.font);
1246
+ const ls = cmd.font.letterSpacing;
1247
+ if (ls !== void 0 && "letterSpacing" in ctx) ctx.letterSpacing = `${ls}px`;
1246
1248
  const axes = cmd.font.fontVariationSettings;
1247
1249
  if (axes !== void 0) {
1248
1250
  if ("fontVariationSettings" in ctx) ctx.fontVariationSettings = axes;
@@ -1265,6 +1267,7 @@ var Raster2D = class {
1265
1267
  } catch {
1266
1268
  top().unbounded = true;
1267
1269
  }
1270
+ if (ls !== void 0 && "letterSpacing" in ctx) ctx.letterSpacing = "0px";
1268
1271
  break;
1269
1272
  }
1270
1273
  case "drawImage": {
package/dist/nodes.d.ts CHANGED
@@ -671,6 +671,15 @@ interface TextProps extends NodeProps {
671
671
  width?: PropInit<number>;
672
672
  /** Line height as a multiple of fontSize; default 1.25. */
673
673
  lineHeight?: number;
674
+ /**
675
+ * Letter-spacing (tracking) in **px** between glyphs; unset = none (0). STATIC
676
+ * passthrough threaded into the FontSpec — applied 1:1 by every backend
677
+ * (`ctx.letterSpacing` on canvas/Skia, CSS `letter-spacing` on DOM) and it
678
+ * affects measurement, so wrapping stays correct. Not a registered target (no
679
+ * animatable tracking in 0.21); when unset the FontSpec omits it, so default
680
+ * Text stays byte-identical. For em-relative tracking pass `em * fontSize`.
681
+ */
682
+ letterSpacing?: number;
674
683
  /**
675
684
  * Typewriter reveal: how many graphemes of the laid-out text are shown,
676
685
  * left-to-right. Default Infinity = fully shown (byte-identical to no
@@ -705,6 +714,8 @@ declare class Text extends Node {
705
714
  readonly align: 'left' | 'center' | 'right';
706
715
  readonly width: BindableSignal<number>;
707
716
  readonly lineHeight: number;
717
+ /** Static letter-spacing (tracking) in px; undefined = none. */
718
+ readonly letterSpacing: number | undefined;
708
719
  readonly reveal: BindableSignal<number>;
709
720
  /**
710
721
  * Reveal fraction in [0, 1]; NaN (the default) means "unset" so plain `reveal`
package/dist/nodes.js CHANGED
@@ -722,7 +722,8 @@ const NODE_CONSTRUCTION_PROP_NAMES = {
722
722
  "fontStyle",
723
723
  "align",
724
724
  "lineHeight",
725
- "fontVariationSettings"
725
+ "fontVariationSettings",
726
+ "letterSpacing"
726
727
  ],
727
728
  Image: ["assetId"],
728
729
  Video: [
@@ -1830,6 +1831,8 @@ var Text = class Text extends Node {
1830
1831
  align;
1831
1832
  width;
1832
1833
  lineHeight;
1834
+ /** Static letter-spacing (tracking) in px; undefined = none. */
1835
+ letterSpacing;
1833
1836
  reveal;
1834
1837
  /**
1835
1838
  * Reveal fraction in [0, 1]; NaN (the default) means "unset" so plain `reveal`
@@ -1849,6 +1852,7 @@ var Text = class Text extends Node {
1849
1852
  this.align = props.align ?? "left";
1850
1853
  this.width = initProp(signal(0), props.width);
1851
1854
  this.lineHeight = props.lineHeight ?? 1.25;
1855
+ this.letterSpacing = props.letterSpacing;
1852
1856
  this.reveal = initProp(signal(Number.POSITIVE_INFINITY), props.reveal);
1853
1857
  this.revealFraction = initProp(signal(NaN), props.revealFraction);
1854
1858
  this.registerTarget("width", this.width, "number");
@@ -1872,7 +1876,8 @@ var Text = class Text extends Node {
1872
1876
  size: this.fontSize(),
1873
1877
  weight: this.fontWeight,
1874
1878
  ...this.fontStyle === "italic" ? { style: "italic" } : {},
1875
- ...this.fontVariationSettings !== void 0 ? { fontVariationSettings: this.fontVariationSettings } : {}
1879
+ ...this.fontVariationSettings !== void 0 ? { fontVariationSettings: this.fontVariationSettings } : {},
1880
+ ...this.letterSpacing !== void 0 ? { letterSpacing: this.letterSpacing } : {}
1876
1881
  };
1877
1882
  }
1878
1883
  /**
package/dist/type.js CHANGED
@@ -59,7 +59,8 @@ function splitText(source, opts = {}) {
59
59
  fontWeight: text.fontWeight,
60
60
  fontStyle: text.fontStyle,
61
61
  fill: text.fill(),
62
- lineHeight: text.lineHeight
62
+ lineHeight: text.lineHeight,
63
+ letterSpacing: text.letterSpacing
63
64
  };
64
65
  const step = quantize(font.fontSize * font.lineHeight);
65
66
  const boxes = by === "line" ? text.lineBoxes(m).map((b, i) => ({
@@ -98,6 +99,7 @@ function splitText(source, opts = {}) {
98
99
  fontWeight: font.fontWeight,
99
100
  ...font.fontStyle === "italic" ? { fontStyle: "italic" } : {},
100
101
  lineHeight: font.lineHeight,
102
+ ...font.letterSpacing !== void 0 ? { letterSpacing: font.letterSpacing } : {},
101
103
  align: "left",
102
104
  position: [b.x, b.line * step]
103
105
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/scene",
3
- "version": "0.21.0",
3
+ "version": "0.22.0-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
  "engines": {
@@ -59,7 +59,7 @@
59
59
  ],
60
60
  "dependencies": {
61
61
  "yoga-layout": "^3.2.1",
62
- "@glissade/core": "0.21.0"
62
+ "@glissade/core": "0.22.0-pre.1"
63
63
  },
64
64
  "repository": {
65
65
  "type": "git",