@glissade/backend-skia 0.74.0 → 0.75.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/index.d.ts CHANGED
@@ -75,10 +75,33 @@ declare function createMeasurer(opts?: {
75
75
  declare class SkiaBackend implements RenderBackend {
76
76
  private readonly canvas;
77
77
  private readonly raster;
78
+ /**
79
+ * OUTPUT raster scale for the `gs render --preview-res` two-tier draft (0.75).
80
+ * `undefined` = the DEFAULT full-res path: `render()` takes the EXACT current
81
+ * code path (no identity multiply, byte-for-byte the pre-0.75 goldens). When
82
+ * set, `render()` rasterizes the already-composited DisplayList into the SMALLER
83
+ * `width×height` canvas under an EFFECTIVE scale `sx=width/srcWidth`,
84
+ * `sy=height/srcHeight` — so the scaled canvas is exactly FILLED (no edge gap
85
+ * from the canonical `round()` dim). This is the OUTPUT-raster layer, ORTHOGONAL
86
+ * to and applied ON TOP OF any scene `.scale` transform already baked into the
87
+ * DisplayList (scene transform first, then output raster scale).
88
+ */
89
+ private readonly outputScale;
78
90
  /** Headless CPU Skia: all document filters, no GPU shader pass (§3.4/§3.7). */
79
91
  readonly caps: BackendCaps;
80
92
  constructor(width: number, height: number, opts?: {
81
93
  layerStore?: LayerStore;
94
+ /**
95
+ * §0.75 `gs render --preview-res`: render the composited DisplayList into
96
+ * this (already-scaled) `width×height` canvas at the EFFECTIVE output scale
97
+ * `width/srcWidth × height/srcHeight` — the canonical `srcWidth/srcHeight`
98
+ * are the scene's UNSCALED dims. Opt-in: omit it for the byte-identical
99
+ * full-res path. Only pass it for a real f<1 preview draft.
100
+ */
101
+ outputScale?: {
102
+ srcWidth: number;
103
+ srcHeight: number;
104
+ };
82
105
  });
83
106
  /** Attach the §3.5 disk layer-cache store (the CLI wires this once caps are known). */
84
107
  setLayerStore(store: LayerStore | undefined): void;
package/dist/index.js CHANGED
@@ -139,6 +139,18 @@ function createMeasurer(opts = {}) {
139
139
  var SkiaBackend = class {
140
140
  canvas;
141
141
  raster;
142
+ /**
143
+ * OUTPUT raster scale for the `gs render --preview-res` two-tier draft (0.75).
144
+ * `undefined` = the DEFAULT full-res path: `render()` takes the EXACT current
145
+ * code path (no identity multiply, byte-for-byte the pre-0.75 goldens). When
146
+ * set, `render()` rasterizes the already-composited DisplayList into the SMALLER
147
+ * `width×height` canvas under an EFFECTIVE scale `sx=width/srcWidth`,
148
+ * `sy=height/srcHeight` — so the scaled canvas is exactly FILLED (no edge gap
149
+ * from the canonical `round()` dim). This is the OUTPUT-raster layer, ORTHOGONAL
150
+ * to and applied ON TOP OF any scene `.scale` transform already baked into the
151
+ * DisplayList (scene transform first, then output raster scale).
152
+ */
153
+ outputScale;
142
154
  /** Headless CPU Skia: all document filters, no GPU shader pass (§3.4/§3.7). */
143
155
  caps = {
144
156
  filters: ALL_FILTER_KINDS,
@@ -147,6 +159,10 @@ var SkiaBackend = class {
147
159
  };
148
160
  constructor(width, height, opts = {}) {
149
161
  this.canvas = createCanvas(width, height);
162
+ this.outputScale = opts.outputScale !== void 0 ? {
163
+ sx: width / opts.outputScale.srcWidth,
164
+ sy: height / opts.outputScale.srcHeight
165
+ } : void 0;
150
166
  this.raster = new Raster2D({
151
167
  context: (c) => c.getContext("2d"),
152
168
  createCanvas: (w, h) => createCanvas(w, h),
@@ -179,7 +195,30 @@ var SkiaBackend = class {
179
195
  };
180
196
  }
181
197
  render(list) {
182
- this.raster.render(this.canvas, list);
198
+ if (this.outputScale === void 0) {
199
+ this.raster.render(this.canvas, list);
200
+ return;
201
+ }
202
+ const { sx, sy } = this.outputScale;
203
+ const scaled = {
204
+ ...list,
205
+ size: {
206
+ w: this.canvas.width,
207
+ h: this.canvas.height
208
+ },
209
+ commands: [{
210
+ op: "transform",
211
+ m: [
212
+ sx,
213
+ 0,
214
+ 0,
215
+ sy,
216
+ 0,
217
+ 0
218
+ ]
219
+ }, ...list.commands]
220
+ };
221
+ this.raster.render(this.canvas, scaled);
183
222
  }
184
223
  /** Raw RGBA — the FFmpeg pipe path (§5.1d). Resolves synchronously (no GPU readback) but typed Promise to match the RenderBackend contract. */
185
224
  readPixels() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/backend-skia",
3
- "version": "0.74.0",
3
+ "version": "0.75.0",
4
4
  "description": "glissade headless render backend: DisplayList -> @napi-rs/canvas (Skia). Node-only; the CI-grade deterministic path.",
5
5
  "license": "Apache-2.0",
6
6
  "engines": {
@@ -19,8 +19,8 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "@napi-rs/canvas": "^0.1.65",
22
- "@glissade/core": "0.74.0",
23
- "@glissade/scene": "0.74.0"
22
+ "@glissade/core": "0.75.0",
23
+ "@glissade/scene": "0.75.0"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",