@vectojs/core 1.35.3 → 1.37.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.
@@ -283,9 +283,20 @@ var Entity = class {
283
283
  * and promotes it.
284
284
  *
285
285
  * `'never'` suppresses the node entirely. Prefer `interactive = false` unless
286
- * the entity genuinely needs pointer events without any semantic presence;
287
- * this exists so a purely decorative interactive surface can opt out without
288
- * losing canvas hit-testing.
286
+ * the entity genuinely needs to stay hit-testable without any semantic
287
+ * presence — this exists so a purely decorative interactive surface can opt
288
+ * out of the a11y tree.
289
+ *
290
+ * **Pointer input is routed through the projected mirror.** The engine binds
291
+ * `pointerdown`/`pointermove`/`pointerup`/`click`/`dblclick` to each shadow
292
+ * element (the canvas itself only tracks `mouseX`/`mouseY`), so an entity
293
+ * with no materialized node receives **no pointer events at all** — neither
294
+ * in `'never'` mode nor in `'onDemand'` before it is engaged (focused,
295
+ * pointer target, or `requestA11yProjection`). Canvas hit-testing exists
296
+ * (`Scene.findEntityAt`) but is a query API, not a dispatch path. For a
297
+ * pointer-reactive region with no role (e.g. a desktop click-catcher), use
298
+ * `'eager'` + `a11yFullViewport` + `tabIndex: -1` with a role-less
299
+ * `getA11yAttributes()`: the mirror is AT-invisible but pointer-visible.
289
300
  *
290
301
  * **This does not replace an aggregate description.** A thousand `'onDemand'`
291
302
  * danmaku are individually reachable but say nothing collectively. The proven
@@ -1241,8 +1252,8 @@ var MSDFTextEntity = class extends Entity {
1241
1252
  *
1242
1253
  * Measured on Chromium and Firefox (2026-07-31) with a 600 ms atlas: the
1243
1254
  * scene's own rAF loop never uploaded a decoded atlas in EITHER render mode.
1244
- * `onDemand` skips idle frames outright; `always` throttles to 2 FPS when
1245
- * idle, so whether it recovers is down to whether a throttled tick happens to
1255
+ * `onDemand` skips idle frames outright; `always` throttles to the idle FPS
1256
+ * floor when idle, so whether it recovers is down to whether a throttled tick happens to
1246
1257
  * land after the decode — Chromium got one, Firefox did not. Neither is a
1247
1258
  * mechanism, which is why this listener exists rather than relying on the
1248
1259
  * frame loop to come back around.
@@ -285,9 +285,20 @@ var Entity = (_class2 = class {
285
285
  * and promotes it.
286
286
  *
287
287
  * `'never'` suppresses the node entirely. Prefer `interactive = false` unless
288
- * the entity genuinely needs pointer events without any semantic presence;
289
- * this exists so a purely decorative interactive surface can opt out without
290
- * losing canvas hit-testing.
288
+ * the entity genuinely needs to stay hit-testable without any semantic
289
+ * presence — this exists so a purely decorative interactive surface can opt
290
+ * out of the a11y tree.
291
+ *
292
+ * **Pointer input is routed through the projected mirror.** The engine binds
293
+ * `pointerdown`/`pointermove`/`pointerup`/`click`/`dblclick` to each shadow
294
+ * element (the canvas itself only tracks `mouseX`/`mouseY`), so an entity
295
+ * with no materialized node receives **no pointer events at all** — neither
296
+ * in `'never'` mode nor in `'onDemand'` before it is engaged (focused,
297
+ * pointer target, or `requestA11yProjection`). Canvas hit-testing exists
298
+ * (`Scene.findEntityAt`) but is a query API, not a dispatch path. For a
299
+ * pointer-reactive region with no role (e.g. a desktop click-catcher), use
300
+ * `'eager'` + `a11yFullViewport` + `tabIndex: -1` with a role-less
301
+ * `getA11yAttributes()`: the mirror is AT-invisible but pointer-visible.
291
302
  *
292
303
  * **This does not replace an aggregate description.** A thousand `'onDemand'`
293
304
  * danmaku are individually reachable but say nothing collectively. The proven
@@ -1243,8 +1254,8 @@ var MSDFTextEntity = (_class3 = class extends Entity {
1243
1254
  *
1244
1255
  * Measured on Chromium and Firefox (2026-07-31) with a 600 ms atlas: the
1245
1256
  * scene's own rAF loop never uploaded a decoded atlas in EITHER render mode.
1246
- * `onDemand` skips idle frames outright; `always` throttles to 2 FPS when
1247
- * idle, so whether it recovers is down to whether a throttled tick happens to
1257
+ * `onDemand` skips idle frames outright; `always` throttles to the idle FPS
1258
+ * floor when idle, so whether it recovers is down to whether a throttled tick happens to
1248
1259
  * land after the decode — Chromium got one, Firefox did not. Neither is a
1249
1260
  * mechanism, which is why this listener exists rather than relying on the
1250
1261
  * frame loop to come back around.
@@ -304,11 +304,15 @@ var CanvasRenderer = class _CanvasRenderer {
304
304
  this.ctx.globalAlpha = alpha;
305
305
  }
306
306
  /** @inheritdoc */
307
- clip(x, y, width, height) {
307
+ clip(x, y, width, height, radii) {
308
308
  this.flush();
309
309
  if (this.counters) this.counters.clips++;
310
310
  this.ctx.beginPath();
311
- this.ctx.rect(x, y, width, height);
311
+ if (radii !== void 0) {
312
+ this.ctx.roundRect(x, y, width, height, radii);
313
+ } else {
314
+ this.ctx.rect(x, y, width, height);
315
+ }
312
316
  this.ctx.clip();
313
317
  }
314
318
  /** @inheritdoc */
@@ -854,11 +858,21 @@ var SVGRenderer = class {
854
858
  createMatrix: [this.ma, this.mb, this.mc, this.md, this.me, this.mf]
855
859
  };
856
860
  }
857
- clip(x, y, width, height) {
861
+ clip(x, y, width, height, radii) {
858
862
  this.flush();
859
863
  const id = `clip-${this.clipCounter++}`;
860
864
  const transformStr = `matrix(${this.ma},${this.mb},${this.mc},${this.md},${this.me},${this.mf})`;
861
- const clipXML = `<clipPath id="${id}"><rect x="${x}" y="${y}" width="${width}" height="${height}" transform="${transformStr}" /></clipPath>`;
865
+ let clipShape;
866
+ if (radii !== void 0) {
867
+ const savedPath = this.currentPath;
868
+ this.currentPath = [];
869
+ this.roundRect(x, y, width, height, radii);
870
+ clipShape = `<path d="${this.currentPath.join(" ")}" transform="${transformStr}" />`;
871
+ this.currentPath = savedPath;
872
+ } else {
873
+ clipShape = `<rect x="${x}" y="${y}" width="${width}" height="${height}" transform="${transformStr}" />`;
874
+ }
875
+ const clipXML = `<clipPath id="${id}">${clipShape}</clipPath>`;
862
876
  this.defsBuffer.push(clipXML);
863
877
  this.buffer.push(`<g clip-path="url(#${id})">`);
864
878
  this.clipDepth++;
@@ -306,11 +306,15 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
306
306
  this.ctx.globalAlpha = alpha;
307
307
  }
308
308
  /** @inheritdoc */
309
- clip(x, y, width, height) {
309
+ clip(x, y, width, height, radii) {
310
310
  this.flush();
311
311
  if (this.counters) this.counters.clips++;
312
312
  this.ctx.beginPath();
313
- this.ctx.rect(x, y, width, height);
313
+ if (radii !== void 0) {
314
+ this.ctx.roundRect(x, y, width, height, radii);
315
+ } else {
316
+ this.ctx.rect(x, y, width, height);
317
+ }
314
318
  this.ctx.clip();
315
319
  }
316
320
  /** @inheritdoc */
@@ -856,11 +860,21 @@ var SVGRenderer = (_class2 = class {
856
860
  createMatrix: [this.ma, this.mb, this.mc, this.md, this.me, this.mf]
857
861
  };
858
862
  }
859
- clip(x, y, width, height) {
863
+ clip(x, y, width, height, radii) {
860
864
  this.flush();
861
865
  const id = `clip-${this.clipCounter++}`;
862
866
  const transformStr = `matrix(${this.ma},${this.mb},${this.mc},${this.md},${this.me},${this.mf})`;
863
- const clipXML = `<clipPath id="${id}"><rect x="${x}" y="${y}" width="${width}" height="${height}" transform="${transformStr}" /></clipPath>`;
867
+ let clipShape;
868
+ if (radii !== void 0) {
869
+ const savedPath = this.currentPath;
870
+ this.currentPath = [];
871
+ this.roundRect(x, y, width, height, radii);
872
+ clipShape = `<path d="${this.currentPath.join(" ")}" transform="${transformStr}" />`;
873
+ this.currentPath = savedPath;
874
+ } else {
875
+ clipShape = `<rect x="${x}" y="${y}" width="${width}" height="${height}" transform="${transformStr}" />`;
876
+ }
877
+ const clipXML = `<clipPath id="${id}">${clipShape}</clipPath>`;
864
878
  this.defsBuffer.push(clipXML);
865
879
  this.buffer.push(`<g clip-path="url(#${id})">`);
866
880
  this.clipDepth++;