@vectojs/core 0.1.0 → 0.2.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.
Files changed (46) hide show
  1. package/dist/animation/drivers.d.ts +48 -0
  2. package/dist/animation/easing.d.ts +16 -0
  3. package/dist/{chunk-M2IZPGOL.mjs → chunk-H3QIE77O.mjs} +316 -12
  4. package/dist/{chunk-53DAQC3U.js → chunk-LA3FJLP2.js} +369 -65
  5. package/dist/components/GridTextEntity.d.ts +15 -0
  6. package/dist/components/SplineEntity.d.ts +144 -0
  7. package/dist/components/TextEntity.d.ts +35 -0
  8. package/dist/index.d.ts +26 -577
  9. package/dist/index.js +121 -136
  10. package/dist/index.mjs +19 -34
  11. package/dist/{layout.d.mts → layout/LayoutEngine.d.ts} +15 -70
  12. package/dist/layout/LayoutWorker.d.ts +23 -0
  13. package/dist/layout/LayoutWorkerManager.d.ts +22 -0
  14. package/dist/layout/LayoutWorkerSource.d.ts +1 -0
  15. package/dist/layout/index.d.ts +3 -0
  16. package/dist/layout/measure.d.ts +20 -0
  17. package/dist/math/SpatialHashGrid.d.ts +53 -0
  18. package/dist/math/SpringPhysics.d.ts +13 -0
  19. package/dist/renderer/CanvasRenderer.d.ts +81 -0
  20. package/dist/renderer/IRenderer.d.ts +178 -0
  21. package/dist/renderer/SVGRenderer.d.ts +69 -0
  22. package/dist/renderer/WebGLPointRenderer.d.ts +62 -0
  23. package/dist/renderer/WebGPUParticleSystemManager.d.ts +14 -0
  24. package/dist/renderer/colorParse.d.ts +17 -0
  25. package/dist/renderer/index.d.ts +6 -0
  26. package/dist/text/ArabicShaper.d.ts +10 -0
  27. package/dist/text/BidiResolver.d.ts +6 -0
  28. package/dist/{text.d.ts → text/MSDFFont.d.ts} +10 -82
  29. package/dist/text/MSDFTextEntity.d.ts +30 -0
  30. package/dist/text/SVGEntity.d.ts +22 -0
  31. package/dist/text/index.d.ts +5 -0
  32. package/dist/text.js +2 -2
  33. package/dist/text.mjs +1 -1
  34. package/dist/tree/ComputeParticleEntity.d.ts +118 -0
  35. package/dist/tree/DOMPortalEntity.d.ts +18 -0
  36. package/dist/{Entity-D-rfAFCf.d.mts → tree/Entity.d.ts} +71 -201
  37. package/dist/tree/Scene.d.ts +302 -0
  38. package/package.json +5 -5
  39. package/dist/Entity-D-rfAFCf.d.ts +0 -572
  40. package/dist/index-ByBDSmMK.d.mts +0 -365
  41. package/dist/index-C3Fd_XmG.d.ts +0 -365
  42. package/dist/index.d.mts +0 -577
  43. package/dist/layout.d.ts +0 -319
  44. package/dist/renderer.d.mts +0 -2
  45. package/dist/renderer.d.ts +0 -2
  46. package/dist/text.d.mts +0 -201
package/dist/index.mjs CHANGED
@@ -12,12 +12,17 @@ import {
12
12
  parseColorToRGBA
13
13
  } from "./chunk-2Y45S4JK.mjs";
14
14
  import {
15
+ Easing,
15
16
  Entity,
16
17
  MSDFFont,
17
18
  MSDFTextEntity,
18
19
  SVGEntity,
19
- VectoJSEvent
20
- } from "./chunk-M2IZPGOL.mjs";
20
+ SpringDriver,
21
+ SpringPhysics,
22
+ TweenDriver,
23
+ VectoJSEvent,
24
+ isTweenConfig
25
+ } from "./chunk-H3QIE77O.mjs";
21
26
  import {
22
27
  ArabicShaper,
23
28
  BidiResolver,
@@ -313,6 +318,8 @@ var Scene = class _Scene {
313
318
  */
314
319
  renderMode = "always";
315
320
  dirty = true;
321
+ /** Whether to throttle rendering to 2 FPS when the scene is static to save power. */
322
+ autoThrottle = true;
316
323
  /**
317
324
  * Frame-rate cap (power saving). `0` = uncapped (native refresh). When set,
318
325
  * the loop renders at most `maxFPS` times per second; animations still run,
@@ -323,6 +330,10 @@ var Scene = class _Scene {
323
330
  respectReducedMotion = true;
324
331
  /** Cached media-query list; `.matches` is read live each frame. */
325
332
  reducedMotionQuery = null;
333
+ /** True when the OS asks for reduced motion and we respect it. Read by the animation drivers. */
334
+ get prefersReducedMotion() {
335
+ return this.respectReducedMotion && !!this.reducedMotionQuery?.matches;
336
+ }
326
337
  /**
327
338
  * Throttle interval (ms) for the a11y/automation shadow sync. `0` = every
328
339
  * frame. See {@link SceneOptions.a11ySyncInterval}.
@@ -393,6 +404,7 @@ var Scene = class _Scene {
393
404
  const isTest = globalProcess && (globalProcess.env?.NODE_ENV === "test" || globalProcess.env?.VITEST === "true");
394
405
  this.maxFPS = options.maxFPS ?? (isTest ? 0 : 60);
395
406
  this.respectReducedMotion = options.respectReducedMotion ?? true;
407
+ this.autoThrottle = options.autoThrottle ?? true;
396
408
  this.particleBackend = options.particleBackend ?? "auto";
397
409
  this.a11ySyncInterval = options.a11ySyncInterval ?? 0;
398
410
  this.reducedMotionQuery = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
@@ -1081,7 +1093,7 @@ var Scene = class _Scene {
1081
1093
  loop(time) {
1082
1094
  if (!this.isRunning) return;
1083
1095
  let cap = this.effectiveMaxFPS();
1084
- const isStatic = !this.dirty && !this.hasAnyPendingAnimation(this.root) && !this.hasAnyPendingAnimation(this.overlayRoot);
1096
+ const isStatic = this.autoThrottle && !this.dirty && !this.hasAnyPendingAnimation(this.root) && !this.hasAnyPendingAnimation(this.overlayRoot);
1085
1097
  if (isStatic && this.renderMode === "always" && this.maxFPS > 0) {
1086
1098
  cap = Math.min(cap, 2);
1087
1099
  }
@@ -2064,37 +2076,6 @@ var SpatialHashGrid = class {
2064
2076
  }
2065
2077
  };
2066
2078
 
2067
- // src/math/SpringPhysics.ts
2068
- var SpringPhysics = class {
2069
- value;
2070
- target;
2071
- velocity = 0;
2072
- stiffness = 180;
2073
- damping = 12;
2074
- mass = 1;
2075
- valEpsilon = 5e-3;
2076
- velEpsilon = 5e-3;
2077
- constructor(initial) {
2078
- this.value = initial;
2079
- this.target = initial;
2080
- }
2081
- update(dt) {
2082
- if (this.isAtRest()) {
2083
- this.value = this.target;
2084
- this.velocity = 0;
2085
- return;
2086
- }
2087
- const forceSpring = -this.stiffness * (this.value - this.target);
2088
- const forceDamping = -this.damping * this.velocity;
2089
- const acceleration = (forceSpring + forceDamping) / this.mass;
2090
- this.velocity += acceleration * dt;
2091
- this.value += this.velocity * dt;
2092
- }
2093
- isAtRest() {
2094
- return Math.abs(this.value - this.target) < this.valEpsilon && Math.abs(this.velocity) < this.velEpsilon;
2095
- }
2096
- };
2097
-
2098
2079
  // src/tree/DOMPortalEntity.ts
2099
2080
  var DOMPortalEntity = class extends Entity {
2100
2081
  domElement;
@@ -2203,6 +2184,7 @@ export {
2203
2184
  CanvasRenderer,
2204
2185
  ComputeParticleEntity,
2205
2186
  DOMPortalEntity,
2187
+ Easing,
2206
2188
  Entity,
2207
2189
  GridTextEntity,
2208
2190
  LayoutEngine,
@@ -2225,13 +2207,16 @@ export {
2225
2207
  Scene,
2226
2208
  SpatialHashGrid,
2227
2209
  SplineEntity,
2210
+ SpringDriver,
2228
2211
  SpringPhysics,
2229
2212
  TextEntity,
2213
+ TweenDriver,
2230
2214
  VectoJSEvent,
2231
2215
  WebGPUParticleSystemManager,
2232
2216
  computeLineSegments,
2233
2217
  createCanvasMeasurer,
2234
2218
  createWebGLPointRenderer,
2219
+ isTweenConfig,
2235
2220
  loadSpline,
2236
2221
  parseColorToRGBA,
2237
2222
  polySegmentToBezier
@@ -4,7 +4,7 @@
4
4
  * Each entry provides the glyph's pixel `width` at `baseSize`, and an `ast`
5
5
  * property holding the raw vector path data used by the renderer.
6
6
  */
7
- interface GlyphAtlas {
7
+ export interface GlyphAtlas {
8
8
  [char: string]: {
9
9
  width: number;
10
10
  baseSize: number;
@@ -18,14 +18,14 @@ interface GlyphAtlas {
18
18
  * Implemented by {@link createCanvasMeasurer} (canvas `measureText`), but kept
19
19
  * abstract so callers can supply their own metrics source.
20
20
  */
21
- interface GlyphMeasurer {
21
+ export interface GlyphMeasurer {
22
22
  measure(char: string, fontSize: number): number;
23
23
  }
24
24
  /**
25
25
  * Per-run inline style for rich text ({@link LayoutEngine.prepareRich}). All
26
26
  * fields are optional and inherited from the call's base style when omitted.
27
27
  */
28
- interface TextStyle {
28
+ export interface TextStyle {
29
29
  /** Font size in px for this run; overrides the base size (affects width + line height). */
30
30
  fontSize?: number;
31
31
  /** Fill color, e.g. `'#38bdf8'`. */
@@ -38,14 +38,14 @@ interface TextStyle {
38
38
  href?: string;
39
39
  }
40
40
  /** A run of text sharing one {@link TextStyle}, the input unit of {@link LayoutEngine.prepareRich}. */
41
- interface StyledSpan {
41
+ export interface StyledSpan {
42
42
  text: string;
43
43
  style?: TextStyle;
44
44
  }
45
45
  /**
46
46
  * A single positioned glyph produced by {@link LayoutEngine.layoutText}.
47
47
  */
48
- interface LayoutNode {
48
+ export interface LayoutNode {
49
49
  char: string;
50
50
  x: number;
51
51
  y: number;
@@ -62,14 +62,14 @@ interface LayoutNode {
62
62
  * The complete output of a text layout pass — an ordered list of positioned
63
63
  * glyphs and the total bounding-box dimensions.
64
64
  */
65
- interface LayoutResult {
65
+ export interface LayoutResult {
66
66
  nodes: LayoutNode[];
67
67
  totalWidth: number;
68
68
  totalHeight: number;
69
69
  fallbackToCanvas?: boolean;
70
70
  }
71
71
  /** A single measured grapheme (the "cold" half of the cold/hot split). */
72
- interface PreparedGlyph {
72
+ export interface PreparedGlyph {
73
73
  char: string;
74
74
  /** Advance width at the prepared `fontSize`. */
75
75
  width: number;
@@ -81,7 +81,7 @@ interface PreparedGlyph {
81
81
  combining?: string[];
82
82
  }
83
83
  /** A measured word/segment, ready to be placed without re-measuring. */
84
- interface PreparedWord {
84
+ export interface PreparedWord {
85
85
  glyphs: PreparedGlyph[];
86
86
  /** Sum of glyph advances — used for word-level wrap decisions. */
87
87
  width: number;
@@ -90,7 +90,7 @@ interface PreparedWord {
90
90
  isWhitespace: boolean;
91
91
  }
92
92
  /** A measured paragraph; `isEmpty` marks a blank line (forced newline). */
93
- interface PreparedParagraph {
93
+ export interface PreparedParagraph {
94
94
  words: PreparedWord[];
95
95
  isEmpty: boolean;
96
96
  fallbackToCanvas?: boolean;
@@ -103,7 +103,7 @@ interface PreparedParagraph {
103
103
  * re-layouts ({@link LayoutEngine.layoutPrepared}) on resize / reposition,
104
104
  * avoiding the per-frame `Intl.Segmenter` + measurement cost.
105
105
  */
106
- interface PreparedText {
106
+ export interface PreparedText {
107
107
  paragraphs: PreparedParagraph[];
108
108
  fontSize: number;
109
109
  fallbackToCanvas?: boolean;
@@ -113,14 +113,14 @@ interface PreparedText {
113
113
  * flow around — the v1 of text flow exclusion shapes. A left/right rect acts
114
114
  * like a CSS float; a centered rect splits the affected lines in two.
115
115
  */
116
- interface ExclusionRect {
116
+ export interface ExclusionRect {
117
117
  x: number;
118
118
  y: number;
119
119
  width: number;
120
120
  height: number;
121
121
  }
122
122
  /** A free horizontal interval `[x0, x1)` available for text on one line. */
123
- interface LineSegment {
123
+ export interface LineSegment {
124
124
  x0: number;
125
125
  x1: number;
126
126
  }
@@ -133,12 +133,12 @@ interface LineSegment {
133
133
  *
134
134
  * Time O(n log n) in the number of overlapping exclusions; space O(n).
135
135
  */
136
- declare function computeLineSegments(top: number, bottom: number, maxWidth: number, exclusions: ExclusionRect[]): LineSegment[];
136
+ export declare function computeLineSegments(top: number, bottom: number, maxWidth: number, exclusions: ExclusionRect[]): LineSegment[];
137
137
  /**
138
138
  * VectoJS Global Layout Engine (Intl.Segmenter)
139
139
  * Advanced Typography Engine supporting CJK, Emoji, and Western Graphemes
140
140
  */
141
- declare class LayoutEngine {
141
+ export declare class LayoutEngine {
142
142
  maxWidth: number;
143
143
  maxHeight: number;
144
144
  preserveLeadingSpaces: boolean;
@@ -243,7 +243,7 @@ declare class LayoutEngine {
243
243
  * Pre-allocated buffer for zero-GC layout results.
244
244
  * Reuse a single instance across frames by calling reset() before each layout pass.
245
245
  */
246
- declare class LayoutResultBuffer {
246
+ export declare class LayoutResultBuffer {
247
247
  static readonly CAPACITY = 16384;
248
248
  /** X positions of each glyph. */
249
249
  xs: Float32Array;
@@ -262,58 +262,3 @@ declare class LayoutResultBuffer {
262
262
  /** Convert to the standard LayoutResult format (allocates — use sparingly). */
263
263
  toLayoutResult(): LayoutResult;
264
264
  }
265
-
266
- /**
267
- * Create a {@link GlyphMeasurer} backed by a single lazily-created offscreen
268
- * Canvas 2D context.
269
- *
270
- * Each grapheme is measured once at `baseSize` and cached; because canvas
271
- * `measureText` advance width is linear in font size, later queries at any
272
- * `fontSize` are derived by pure arithmetic (no re-measure). This gives the
273
- * {@link LayoutEngine} real per-glyph metrics for text that has no pre-baked
274
- * vector atlas, fixing the coarse `0.5em` line-breaking fallback.
275
- *
276
- * Returns `null` in DOM-free environments (SSR, workers without a canvas) so
277
- * callers stay portable and the engine keeps its `0.5em` fallback.
278
- *
279
- * @param fontFamily - CSS font family used for measurement; should match what
280
- * the renderer actually draws (e.g. `TextEntity` falls back to `sans-serif`).
281
- * @param baseSize - Pixel size at which each glyph is measured and cached.
282
- * @returns A measurer, or `null` when no Canvas 2D context is available.
283
- */
284
- declare function createCanvasMeasurer(fontFamily?: string, baseSize?: number): GlyphMeasurer | null;
285
-
286
- interface LayoutWorkerResponse {
287
- id: string;
288
- seqId: number;
289
- width: number;
290
- height: number;
291
- codePoints: Uint32Array;
292
- xCoords: Float32Array;
293
- yCoords: Float32Array;
294
- packedStyles: Uint32Array;
295
- }
296
-
297
- declare class LayoutWorkerManager {
298
- private static instance;
299
- private worker;
300
- private registeredFonts;
301
- private pendingCallbacks;
302
- private seqIdCounter;
303
- private debounceTimers;
304
- private constructor();
305
- static getInstance(): LayoutWorkerManager;
306
- queueLayout(entityId: string, text: string, options: {
307
- fontId: string;
308
- fontSize: number;
309
- maxWidth: number;
310
- maxHeight: number;
311
- fontData?: any;
312
- lineHeight?: number;
313
- letterSpacing?: number;
314
- callback: (res: LayoutWorkerResponse) => void;
315
- }): void;
316
- cancelLayout(entityId: string): void;
317
- }
318
-
319
- export { type ExclusionRect, type GlyphAtlas, type GlyphMeasurer, LayoutEngine, type LayoutNode, type LayoutResult, LayoutResultBuffer, LayoutWorkerManager, type LineSegment, type PreparedGlyph, type PreparedParagraph, type PreparedText, type PreparedWord, type StyledSpan, type TextStyle, computeLineSegments, createCanvasMeasurer };
@@ -0,0 +1,23 @@
1
+ import { MSDFFontData } from '../text/MSDFFont';
2
+ export interface LayoutWorkerRequest {
3
+ id: string;
4
+ seqId: number;
5
+ text: string;
6
+ fontId: string;
7
+ fontData?: MSDFFontData;
8
+ maxWidth: number;
9
+ maxHeight: number;
10
+ fontSize: number;
11
+ lineHeight?: number;
12
+ letterSpacing?: number;
13
+ }
14
+ export interface LayoutWorkerResponse {
15
+ id: string;
16
+ seqId: number;
17
+ width: number;
18
+ height: number;
19
+ codePoints: Uint32Array;
20
+ xCoords: Float32Array;
21
+ yCoords: Float32Array;
22
+ packedStyles: Uint32Array;
23
+ }
@@ -0,0 +1,22 @@
1
+ import { LayoutWorkerResponse } from './LayoutWorker';
2
+ export declare class LayoutWorkerManager {
3
+ private static instance;
4
+ private worker;
5
+ private registeredFonts;
6
+ private pendingCallbacks;
7
+ private seqIdCounter;
8
+ private debounceTimers;
9
+ private constructor();
10
+ static getInstance(): LayoutWorkerManager;
11
+ queueLayout(entityId: string, text: string, options: {
12
+ fontId: string;
13
+ fontSize: number;
14
+ maxWidth: number;
15
+ maxHeight: number;
16
+ fontData?: any;
17
+ lineHeight?: number;
18
+ letterSpacing?: number;
19
+ callback: (res: LayoutWorkerResponse) => void;
20
+ }): void;
21
+ cancelLayout(entityId: string): void;
22
+ }
@@ -0,0 +1 @@
1
+ export declare const WORKER_SOURCE_STRING = "\"use strict\";(()=>{var b=new Map;self.onmessage=x=>{let{id:S,seqId:k,text:A,fontId:i,fontData:c,maxWidth:d,maxHeight:H,fontSize:o,lineHeight:F,letterSpacing:C}=x.data;c&&b.set(i,c);let n=b.get(i);if(!n)return;let f=[],u=[],y=[],l=[],e=0,r=0,h=n.metrics?.ascender??.8,D=n.metrics?.descender??-.2,m=F??o*(h-D),p=Array.from(A);for(let s=0;s<p.length;s++){let a=p[s].codePointAt(0),g=(n.glyphs?.find(w=>w.unicode===a)?.advance??1)*o;e+g>d&&a===32&&(e=0,r++),f.push(a),u.push(e);let M=r*m+h*o;y.push(M),l.push(-256),e+=g+(C??0)}let t={id:S,seqId:k,width:Math.min(e,d),height:(r+1)*m,codePoints:new Uint32Array(f),xCoords:new Float32Array(u),yCoords:new Float32Array(y),packedStyles:new Uint32Array(l)};self.postMessage(t,[t.codePoints.buffer,t.xCoords.buffer,t.yCoords.buffer,t.packedStyles.buffer])};})();\n";
@@ -0,0 +1,3 @@
1
+ export * from './LayoutEngine';
2
+ export * from './LayoutWorkerManager';
3
+ export * from './measure';
@@ -0,0 +1,20 @@
1
+ import type { GlyphMeasurer } from './LayoutEngine';
2
+ /**
3
+ * Create a {@link GlyphMeasurer} backed by a single lazily-created offscreen
4
+ * Canvas 2D context.
5
+ *
6
+ * Each grapheme is measured once at `baseSize` and cached; because canvas
7
+ * `measureText` advance width is linear in font size, later queries at any
8
+ * `fontSize` are derived by pure arithmetic (no re-measure). This gives the
9
+ * {@link LayoutEngine} real per-glyph metrics for text that has no pre-baked
10
+ * vector atlas, fixing the coarse `0.5em` line-breaking fallback.
11
+ *
12
+ * Returns `null` in DOM-free environments (SSR, workers without a canvas) so
13
+ * callers stay portable and the engine keeps its `0.5em` fallback.
14
+ *
15
+ * @param fontFamily - CSS font family used for measurement; should match what
16
+ * the renderer actually draws (e.g. `TextEntity` falls back to `sans-serif`).
17
+ * @param baseSize - Pixel size at which each glyph is measured and cached.
18
+ * @returns A measurer, or `null` when no Canvas 2D context is available.
19
+ */
20
+ export declare function createCanvasMeasurer(fontFamily?: string, baseSize?: number): GlyphMeasurer | null;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Fixed-cell Spatial Hash Grid for O(1) average-case AABB neighbor queries.
3
+ * Insert entities each frame, then query by AABB to find nearby entity IDs.
4
+ */
5
+ export declare class SpatialHashGrid {
6
+ private cellSize;
7
+ private grid;
8
+ private entityCells;
9
+ constructor(cellSize?: number);
10
+ private hash;
11
+ private cellsForAABB;
12
+ /**
13
+ * Insert or update an entity's axis-aligned bounding box in the grid.
14
+ *
15
+ * If the entity is already registered its old cell memberships are removed
16
+ * before the new ones are computed, so this method is safe to call every
17
+ * frame.
18
+ *
19
+ * @param id - Unique string identifier for the entity.
20
+ * @param x - Left edge of the AABB in world space.
21
+ * @param y - Top edge of the AABB in world space.
22
+ * @param w - Width of the AABB.
23
+ * @param h - Height of the AABB.
24
+ */
25
+ insert(id: string, x: number, y: number, w: number, h: number): void;
26
+ /**
27
+ * Remove an entity from all grid cells it currently occupies.
28
+ *
29
+ * Silently does nothing if the entity is not registered.
30
+ *
31
+ * @param id - Unique string identifier of the entity to remove.
32
+ */
33
+ remove(id: string): void;
34
+ /**
35
+ * Return all entity IDs whose grid cells overlap the given AABB.
36
+ *
37
+ * Time complexity: O(k) where k is the number of cells the query AABB spans
38
+ * plus the number of results — O(1) average for small, similarly-sized entities.
39
+ *
40
+ * @param x - Left edge of the query AABB.
41
+ * @param y - Top edge of the query AABB.
42
+ * @param w - Width of the query AABB.
43
+ * @param h - Height of the query AABB.
44
+ * @returns A `Set` of entity ID strings whose cells intersect the query region.
45
+ */
46
+ query(x: number, y: number, w: number, h: number): Set<string>;
47
+ /**
48
+ * Clear all cells and entity registrations, resetting the grid to an empty state.
49
+ *
50
+ * Call once per frame before re-inserting all dynamic entities.
51
+ */
52
+ clear(): void;
53
+ }
@@ -0,0 +1,13 @@
1
+ export declare class SpringPhysics {
2
+ value: number;
3
+ target: number;
4
+ velocity: number;
5
+ stiffness: number;
6
+ damping: number;
7
+ mass: number;
8
+ private readonly valEpsilon;
9
+ private readonly velEpsilon;
10
+ constructor(initial: number);
11
+ update(dt: number): void;
12
+ isAtRest(): boolean;
13
+ }
@@ -0,0 +1,81 @@
1
+ import { IRenderer } from './IRenderer';
2
+ export declare class CanvasRenderer implements IRenderer {
3
+ private ctx;
4
+ private width;
5
+ private height;
6
+ /**
7
+ * Max circles per batched `fill()`. A single Canvas 2D `fill()` over a path is
8
+ * superlinear in sub-path count, so an unbounded batch is *slower* than many
9
+ * small fills at high entity counts. Capping bounds each fill's path
10
+ * complexity while still amortizing per-draw overhead. Tuned via the benchmark.
11
+ */
12
+ static readonly MAX_BATCH = 64;
13
+ private batchActive;
14
+ private batchColor;
15
+ private batchAlpha;
16
+ private batchCount;
17
+ constructor(canvas: HTMLCanvasElement);
18
+ /**
19
+ * Expose the underlying `CanvasRenderingContext2D` for operations not
20
+ * covered by the {@link IRenderer} interface.
21
+ *
22
+ * @returns The raw 2D rendering context.
23
+ */
24
+ getContext(): CanvasRenderingContext2D;
25
+ /**
26
+ * Resize the backing canvas buffer and re-apply DPR scaling.
27
+ *
28
+ * Called automatically by {@link Scene} on `window.resize` events.
29
+ *
30
+ * @param width - New logical width in CSS pixels.
31
+ * @param height - New logical height in CSS pixels.
32
+ */
33
+ resize(width: number, height: number): void;
34
+ /** @inheritdoc */
35
+ clear(): void;
36
+ /** @inheritdoc */
37
+ save(): void;
38
+ /** @inheritdoc */
39
+ restore(): void;
40
+ /** @inheritdoc */
41
+ translate(x: number, y: number): void;
42
+ /** @inheritdoc */
43
+ scale(x: number, y: number): void;
44
+ /** @inheritdoc */
45
+ rotate(angle: number): void;
46
+ /** @inheritdoc */
47
+ setGlobalAlpha(alpha: number): void;
48
+ /** @inheritdoc */
49
+ clip(x: number, y: number, width: number, height: number): void;
50
+ /** @inheritdoc */
51
+ beginPath(): void;
52
+ /** @inheritdoc */
53
+ moveTo(x: number, y: number): void;
54
+ /** @inheritdoc */
55
+ lineTo(x: number, y: number): void;
56
+ /** @inheritdoc */
57
+ bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
58
+ /** @inheritdoc */
59
+ closePath(): void;
60
+ /** @inheritdoc */
61
+ arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
62
+ /** @inheritdoc */
63
+ roundRect(x: number, y: number, width: number, height: number, radii: number | number[]): void;
64
+ /** @inheritdoc */
65
+ drawImage(source: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
66
+ /** @inheritdoc */
67
+ fillCircle(cx: number, cy: number, radius: number, color: string, alpha?: number): void;
68
+ /** @inheritdoc */
69
+ flush(): void;
70
+ /** @inheritdoc */
71
+ fill(color: string | any): void;
72
+ /** @inheritdoc */
73
+ stroke(color: string | any, lineWidth?: number): void;
74
+ /** @inheritdoc */
75
+ fillText(text: string, x: number, y: number, font: string, color: string | any): void;
76
+ /** @inheritdoc */
77
+ createLinearGradient(x0: number, y0: number, x1: number, y1: number, colorStops: {
78
+ stop: number;
79
+ color: string;
80
+ }[]): any;
81
+ }