@flighthq/path 0.1.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.
Files changed (115) hide show
  1. package/dist/containsPathPoint.d.ts +13 -0
  2. package/dist/containsPathPoint.d.ts.map +1 -0
  3. package/dist/containsPathPoint.js +194 -0
  4. package/dist/containsPathPoint.js.map +1 -0
  5. package/dist/copyPath.d.ts +4 -0
  6. package/dist/copyPath.d.ts.map +1 -0
  7. package/dist/copyPath.js +28 -0
  8. package/dist/copyPath.js.map +1 -0
  9. package/dist/dashPath.d.ts +3 -0
  10. package/dist/dashPath.d.ts.map +1 -0
  11. package/dist/dashPath.js +105 -0
  12. package/dist/dashPath.js.map +1 -0
  13. package/dist/fitPathCurves.d.ts +3 -0
  14. package/dist/fitPathCurves.d.ts.map +1 -0
  15. package/dist/fitPathCurves.js +222 -0
  16. package/dist/fitPathCurves.js.map +1 -0
  17. package/dist/flattenPath.d.ts +3 -0
  18. package/dist/flattenPath.d.ts.map +1 -0
  19. package/dist/flattenPath.js +145 -0
  20. package/dist/flattenPath.js.map +1 -0
  21. package/dist/forEachPathSegment.d.ts +3 -0
  22. package/dist/forEachPathSegment.d.ts.map +1 -0
  23. package/dist/forEachPathSegment.js +66 -0
  24. package/dist/forEachPathSegment.js.map +1 -0
  25. package/dist/getPathBounds.d.ts +3 -0
  26. package/dist/getPathBounds.d.ts.map +1 -0
  27. package/dist/getPathBounds.js +167 -0
  28. package/dist/getPathBounds.js.map +1 -0
  29. package/dist/getPathContourLengths.d.ts +3 -0
  30. package/dist/getPathContourLengths.d.ts.map +1 -0
  31. package/dist/getPathContourLengths.js +21 -0
  32. package/dist/getPathContourLengths.js.map +1 -0
  33. package/dist/getPathLength.d.ts +3 -0
  34. package/dist/getPathLength.d.ts.map +1 -0
  35. package/dist/getPathLength.js +23 -0
  36. package/dist/getPathLength.js.map +1 -0
  37. package/dist/getPathNearestPoint.d.ts +3 -0
  38. package/dist/getPathNearestPoint.d.ts.map +1 -0
  39. package/dist/getPathNearestPoint.js +47 -0
  40. package/dist/getPathNearestPoint.js.map +1 -0
  41. package/dist/getPathPointAtDistance.d.ts +5 -0
  42. package/dist/getPathPointAtDistance.d.ts.map +1 -0
  43. package/dist/getPathPointAtDistance.js +100 -0
  44. package/dist/getPathPointAtDistance.js.map +1 -0
  45. package/dist/getPathSegmentAtParameter.d.ts +8 -0
  46. package/dist/getPathSegmentAtParameter.d.ts.map +1 -0
  47. package/dist/getPathSegmentAtParameter.js +163 -0
  48. package/dist/getPathSegmentAtParameter.js.map +1 -0
  49. package/dist/getPathSignedArea.d.ts +4 -0
  50. package/dist/getPathSignedArea.d.ts.map +1 -0
  51. package/dist/getPathSignedArea.js +43 -0
  52. package/dist/getPathSignedArea.js.map +1 -0
  53. package/dist/index.d.ts +23 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +23 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/offsetPath.d.ts +3 -0
  58. package/dist/offsetPath.d.ts.map +1 -0
  59. package/dist/offsetPath.js +146 -0
  60. package/dist/offsetPath.js.map +1 -0
  61. package/dist/path.d.ts +17 -0
  62. package/dist/path.d.ts.map +1 -0
  63. package/dist/path.js +293 -0
  64. package/dist/path.js.map +1 -0
  65. package/dist/pathMeshPool.d.ts +6 -0
  66. package/dist/pathMeshPool.d.ts.map +1 -0
  67. package/dist/pathMeshPool.js +58 -0
  68. package/dist/pathMeshPool.js.map +1 -0
  69. package/dist/reversePath.d.ts +3 -0
  70. package/dist/reversePath.d.ts.map +1 -0
  71. package/dist/reversePath.js +95 -0
  72. package/dist/reversePath.js.map +1 -0
  73. package/dist/simplifyPath.d.ts +3 -0
  74. package/dist/simplifyPath.d.ts.map +1 -0
  75. package/dist/simplifyPath.js +78 -0
  76. package/dist/simplifyPath.js.map +1 -0
  77. package/dist/strokePath.d.ts +4 -0
  78. package/dist/strokePath.d.ts.map +1 -0
  79. package/dist/strokePath.js +458 -0
  80. package/dist/strokePath.js.map +1 -0
  81. package/dist/tessellatePath.d.ts +3 -0
  82. package/dist/tessellatePath.d.ts.map +1 -0
  83. package/dist/tessellatePath.js +107 -0
  84. package/dist/tessellatePath.js.map +1 -0
  85. package/dist/tessellatePathTyped.d.ts +3 -0
  86. package/dist/tessellatePathTyped.d.ts.map +1 -0
  87. package/dist/tessellatePathTyped.js +12 -0
  88. package/dist/tessellatePathTyped.js.map +1 -0
  89. package/dist/transformPath.d.ts +4 -0
  90. package/dist/transformPath.d.ts.map +1 -0
  91. package/dist/transformPath.js +62 -0
  92. package/dist/transformPath.js.map +1 -0
  93. package/package.json +37 -0
  94. package/src/containsPathPoint.test.ts +125 -0
  95. package/src/copyPath.test.ts +56 -0
  96. package/src/dashPath.test.ts +76 -0
  97. package/src/fitPathCurves.test.ts +65 -0
  98. package/src/flattenPath.test.ts +87 -0
  99. package/src/forEachPathSegment.test.ts +82 -0
  100. package/src/getPathBounds.test.ts +84 -0
  101. package/src/getPathContourLengths.test.ts +51 -0
  102. package/src/getPathLength.test.ts +33 -0
  103. package/src/getPathNearestPoint.test.ts +64 -0
  104. package/src/getPathPointAtDistance.test.ts +94 -0
  105. package/src/getPathSegmentAtParameter.test.ts +178 -0
  106. package/src/getPathSignedArea.test.ts +45 -0
  107. package/src/offsetPath.test.ts +78 -0
  108. package/src/path.test.ts +376 -0
  109. package/src/pathMeshPool.test.ts +78 -0
  110. package/src/reversePath.test.ts +51 -0
  111. package/src/simplifyPath.test.ts +69 -0
  112. package/src/strokePath.test.ts +150 -0
  113. package/src/tessellatePath.test.ts +62 -0
  114. package/src/tessellatePathTyped.test.ts +26 -0
  115. package/src/transformPath.test.ts +79 -0
package/dist/path.js ADDED
@@ -0,0 +1,293 @@
1
+ import { PathCommand } from '@flighthq/types';
2
+ // Approximates an arc centered at (cx, cy) from `startAngle` to `endAngle` (radians) with the given
3
+ // `radius`, using one or more cubic bezier segments. Each cubic segment spans at most π/2 (90°) to
4
+ // keep the kappa approximation error under 0.03% of the radius. Appends a MOVE_TO at the arc start
5
+ // unless `connectToCurrent` is true, in which case the arc start is reached by a LINE_TO (useful for
6
+ // building arcs as part of a larger contour). Anticlockwise arcs are supported via the `anticlockwise`
7
+ // flag (default false = clockwise).
8
+ export function appendPathArc(path, cx, cy, radius, startAngle, endAngle, anticlockwise = false, connectToCurrent = false) {
9
+ if (radius <= 0)
10
+ return;
11
+ // Normalize the angle sweep to the correct winding direction.
12
+ let sweep = endAngle - startAngle;
13
+ if (anticlockwise) {
14
+ if (sweep > 0)
15
+ sweep -= Math.PI * 2;
16
+ }
17
+ else {
18
+ if (sweep < 0)
19
+ sweep += Math.PI * 2;
20
+ }
21
+ const arcStartX = cx + Math.cos(startAngle) * radius;
22
+ const arcStartY = cy + Math.sin(startAngle) * radius;
23
+ if (connectToCurrent) {
24
+ appendPathLineTo(path, arcStartX, arcStartY);
25
+ }
26
+ else {
27
+ appendPathMoveTo(path, arcStartX, arcStartY);
28
+ }
29
+ appendArcCubics(path, cx, cy, radius, radius, 0, startAngle, sweep);
30
+ }
31
+ // Appends an SVG-style elliptic arc from the current point to (endX, endY). The arc is defined
32
+ // by the ellipse with semi-axes (radiusX, radiusY) rotated by `xAxisRotation` radians. When the
33
+ // start and end points do not uniquely identify an arc, `largeArc` and `sweep` select among the
34
+ // four candidate arcs: `largeArc=true` picks the arc spanning more than 180°; `sweep=true` picks
35
+ // the CW arc (positive-angle direction). Converts the SVG endpoint parameterization to the center
36
+ // parameterization and then to cubic bezier segments.
37
+ //
38
+ // If radiusX or radiusY is 0, appends a LINE_TO to (endX, endY). If the current point equals
39
+ // the endpoint, appends nothing. This matches the SVG arc spec behavior.
40
+ export function appendPathArcTo(path, radiusX, radiusY, xAxisRotation, largeArc, sweep, endX, endY) {
41
+ if (radiusX === 0 || radiusY === 0) {
42
+ appendPathLineTo(path, endX, endY);
43
+ return;
44
+ }
45
+ // Determine the current point. If the path is empty use (0,0).
46
+ let x1 = 0;
47
+ let y1 = 0;
48
+ {
49
+ const last = getPathLastPoint(path);
50
+ if (last !== null) {
51
+ x1 = last[0];
52
+ y1 = last[1];
53
+ }
54
+ }
55
+ const x2 = endX;
56
+ const y2 = endY;
57
+ // If start == end, do nothing (SVG spec).
58
+ if (x1 === x2 && y1 === y2)
59
+ return;
60
+ // Ensure positive radii.
61
+ let rx = Math.abs(radiusX);
62
+ let ry = Math.abs(radiusY);
63
+ const cosφ = Math.cos(xAxisRotation);
64
+ const sinφ = Math.sin(xAxisRotation);
65
+ // Step 1: Compute (x1', y1') in the rotated ellipse frame.
66
+ const dx = (x1 - x2) / 2;
67
+ const dy = (y1 - y2) / 2;
68
+ const x1p = cosφ * dx + sinφ * dy;
69
+ const y1p = -sinφ * dx + cosφ * dy;
70
+ // Step 2: Scale radii up if too small (SVG spec §F.6.6.3).
71
+ const x1pSq = x1p * x1p;
72
+ const y1pSq = y1p * y1p;
73
+ const rxSq = rx * rx;
74
+ const rySq = ry * ry;
75
+ const lambda = x1pSq / rxSq + y1pSq / rySq;
76
+ if (lambda > 1) {
77
+ const sqrtLambda = Math.sqrt(lambda);
78
+ rx *= sqrtLambda;
79
+ ry *= sqrtLambda;
80
+ }
81
+ const rxSq2 = rx * rx;
82
+ const rySq2 = ry * ry;
83
+ // Step 3: Compute center (cx', cy') in the rotated frame.
84
+ const num = rxSq2 * rySq2 - rxSq2 * y1pSq - rySq2 * x1pSq;
85
+ const den = rxSq2 * y1pSq + rySq2 * x1pSq;
86
+ const sq = den <= 0 ? 0 : Math.sqrt(Math.max(0, num / den));
87
+ const sign = largeArc === sweep ? -1 : 1;
88
+ const cxp = (sign * sq * (rx * y1p)) / ry;
89
+ const cyp = (sign * sq * (-ry * x1p)) / rx;
90
+ // Step 4: Compute center (cx, cy) in the original frame.
91
+ const cx = cosφ * cxp - sinφ * cyp + (x1 + x2) / 2;
92
+ const cy = sinφ * cxp + cosφ * cyp + (y1 + y2) / 2;
93
+ // Step 5: Compute start angle θ1 and sweep angle Δθ.
94
+ const ux = (x1p - cxp) / rx;
95
+ const uy = (y1p - cyp) / ry;
96
+ const vx = (-x1p - cxp) / rx;
97
+ const vy = (-y1p - cyp) / ry;
98
+ const theta1 = vectorAngle(1, 0, ux, uy);
99
+ let dtheta = vectorAngle(ux, uy, vx, vy);
100
+ if (!sweep && dtheta > 0)
101
+ dtheta -= Math.PI * 2;
102
+ if (sweep && dtheta < 0)
103
+ dtheta += Math.PI * 2;
104
+ appendArcCubics(path, cx, cy, rx, ry, xAxisRotation, theta1, dtheta);
105
+ }
106
+ // Approximates a circle centered at (cx, cy) with the given radius using four cubic bezier segments.
107
+ // The standard kappa constant (4*(sqrt(2)-1)/3) gives the best cubic approximation of an arc.
108
+ // Appends a MOVE_TO before the circle and a CLOSE at the end.
109
+ export function appendPathCircle(path, cx, cy, radius) {
110
+ appendPathEllipse(path, cx, cy, radius, radius);
111
+ }
112
+ // Closes the current contour back to the most recent MOVE_TO origin. Appends a CLOSE verb (0 data
113
+ // values). After CLOSE, the next draw verb starts a new implicit contour unless preceded by MOVE_TO.
114
+ export function appendPathClose(path) {
115
+ path.commands.push(PathCommand.CLOSE);
116
+ }
117
+ export function appendPathCubicCurveTo(path, control1X, control1Y, control2X, control2Y, anchorX, anchorY) {
118
+ path.commands.push(PathCommand.CUBIC_CURVE_TO);
119
+ path.data.push(control1X, control1Y, control2X, control2Y, anchorX, anchorY);
120
+ }
121
+ export function appendPathCurveTo(path, controlX, controlY, anchorX, anchorY) {
122
+ path.commands.push(PathCommand.CURVE_TO);
123
+ path.data.push(controlX, controlY, anchorX, anchorY);
124
+ }
125
+ // Approximates an axis-aligned ellipse using four cubic bezier segments (standard kappa approximation:
126
+ // kappa = 4*(sqrt(2)-1)/3 ≈ 0.5522847498). The error is less than 0.03% of the radius. Appends a
127
+ // MOVE_TO at the rightmost point and a CLOSE after the fourth arc segment.
128
+ export function appendPathEllipse(path, cx, cy, radiusX, radiusY) {
129
+ // kappa: the distance along each tangent handle for the optimal cubic arc approximation.
130
+ const kx = radiusX * KAPPA;
131
+ const ky = radiusY * KAPPA;
132
+ appendPathMoveTo(path, cx + radiusX, cy);
133
+ appendPathCubicCurveTo(path, cx + radiusX, cy - ky, cx + kx, cy - radiusY, cx, cy - radiusY);
134
+ appendPathCubicCurveTo(path, cx - kx, cy - radiusY, cx - radiusX, cy - ky, cx - radiusX, cy);
135
+ appendPathCubicCurveTo(path, cx - radiusX, cy + ky, cx - kx, cy + radiusY, cx, cy + radiusY);
136
+ appendPathCubicCurveTo(path, cx + kx, cy + radiusY, cx + radiusX, cy + ky, cx + radiusX, cy);
137
+ appendPathClose(path);
138
+ }
139
+ export function appendPathLineTo(path, x, y) {
140
+ path.commands.push(PathCommand.LINE_TO);
141
+ path.data.push(x, y);
142
+ }
143
+ export function appendPathMoveTo(path, x, y) {
144
+ path.commands.push(PathCommand.MOVE_TO);
145
+ path.data.push(x, y);
146
+ }
147
+ // Appends a closed polygon from a flat array of [x0, y0, x1, y1, ...] coordinate pairs. Emits a
148
+ // MOVE_TO at the first point, LINE_TO for each subsequent point, and a CLOSE at the end.
149
+ // Requires at least 3 points (6 values); returns immediately if fewer are provided.
150
+ export function appendPathPolygon(path, points) {
151
+ if (points.length < 6)
152
+ return;
153
+ appendPathMoveTo(path, points[0], points[1]);
154
+ for (let i = 2; i < points.length; i += 2) {
155
+ appendPathLineTo(path, points[i], points[i + 1]);
156
+ }
157
+ appendPathClose(path);
158
+ }
159
+ // Appends an open polyline from a flat array of [x0, y0, x1, y1, ...] coordinate pairs. Emits a
160
+ // MOVE_TO at the first point and LINE_TO for each subsequent point. No CLOSE is appended.
161
+ // Requires at least 2 points (4 values); returns immediately if fewer are provided.
162
+ export function appendPathPolyline(path, points) {
163
+ if (points.length < 4)
164
+ return;
165
+ appendPathMoveTo(path, points[0], points[1]);
166
+ for (let i = 2; i < points.length; i += 2) {
167
+ appendPathLineTo(path, points[i], points[i + 1]);
168
+ }
169
+ }
170
+ // Appends a closed axis-aligned rectangle as a moveTo + three lineTo + close. The winding is CW
171
+ // in screen space (y-down), matching the standard path fill convention.
172
+ export function appendPathRectangle(path, x, y, width, height) {
173
+ appendPathMoveTo(path, x, y);
174
+ appendPathLineTo(path, x + width, y);
175
+ appendPathLineTo(path, x + width, y + height);
176
+ appendPathLineTo(path, x, y + height);
177
+ appendPathClose(path);
178
+ }
179
+ // Appends a closed axis-aligned rounded rectangle. Corner radii are uniform when passed as a single
180
+ // number, or per-corner when passed as [topLeft, topRight, bottomRight, bottomLeft]. Each radius is
181
+ // clamped to half the adjacent edge so the corners never overlap. Radii of 0 produce sharp corners.
182
+ // Corners are approximated using the kappa cubic arc method (same as `appendPathEllipse`).
183
+ export function appendPathRoundRectangle(path, x, y, width, height, radius) {
184
+ const [rtl, rtr, rbr, rbl] = normalizeCornerRadii(radius, width, height);
185
+ // Start at the top-left corner arc start (top edge, after top-left radius).
186
+ appendPathMoveTo(path, x + rtl, y);
187
+ // Top edge → top-right corner.
188
+ appendPathLineTo(path, x + width - rtr, y);
189
+ appendCornerArc(path, x + width - rtr, y + rtr, rtr, -Math.PI / 2, 0);
190
+ // Right edge → bottom-right corner.
191
+ appendPathLineTo(path, x + width, y + height - rbr);
192
+ appendCornerArc(path, x + width - rbr, y + height - rbr, rbr, 0, Math.PI / 2);
193
+ // Bottom edge → bottom-left corner.
194
+ appendPathLineTo(path, x + rbl, y + height);
195
+ appendCornerArc(path, x + rbl, y + height - rbl, rbl, Math.PI / 2, Math.PI);
196
+ // Left edge → top-left corner.
197
+ appendPathLineTo(path, x, y + rtl);
198
+ appendCornerArc(path, x + rtl, y + rtl, rtl, Math.PI, (Math.PI * 3) / 2);
199
+ appendPathClose(path);
200
+ }
201
+ // Allocates an empty path. Winding defaults to nonZero: same-wound subpaths union (the common clip
202
+ // case) and counter-wound subpaths cut holes. Pass 'evenOdd' for parity fills.
203
+ export function createPath(winding = 'nonZero') {
204
+ return { commands: [], data: [], winding };
205
+ }
206
+ // Appends a quarter-circle arc (90°) centered at (cx, cy) with the given radius, from `startAngle`
207
+ // to `startAngle + π/2`. Uses a single cubic bezier with the kappa approximation.
208
+ function appendCornerArc(path, cx, cy, radius, startAngle, endAngle) {
209
+ if (radius <= 0)
210
+ return;
211
+ // Single cubic approximation for a quarter arc using kappa.
212
+ const k = radius * KAPPA;
213
+ const cosStart = Math.cos(startAngle);
214
+ const sinStart = Math.sin(startAngle);
215
+ const cosEnd = Math.cos(endAngle);
216
+ const sinEnd = Math.sin(endAngle);
217
+ appendPathCubicCurveTo(path, cx + cosStart * radius - sinStart * k, cy + sinStart * radius + cosStart * k, cx + cosEnd * radius + sinEnd * k, cy + sinEnd * radius - cosEnd * k, cx + cosEnd * radius, cy + sinEnd * radius);
218
+ }
219
+ // Appends cubic bezier segments approximating an elliptic arc. The arc is described in the center
220
+ // parameterization: (cx, cy) = center, (rx, ry) = semi-axes, xAxisRotation = ellipse rotation,
221
+ // theta1 = start angle, dtheta = sweep angle (signed). Segments span at most π/2 to keep error low.
222
+ function appendArcCubics(path, cx, cy, rx, ry, xAxisRotation, theta1, dtheta) {
223
+ if (dtheta === 0)
224
+ return;
225
+ // Split into segments of at most π/2.
226
+ const nSegs = Math.max(1, Math.ceil(Math.abs(dtheta) / (Math.PI / 2)));
227
+ const dt = dtheta / nSegs;
228
+ const cosφ = Math.cos(xAxisRotation);
229
+ const sinφ = Math.sin(xAxisRotation);
230
+ for (let i = 0; i < nSegs; i++) {
231
+ const t1 = theta1 + i * dt;
232
+ const t2 = t1 + dt;
233
+ // Endpoint angles.
234
+ const cos1 = Math.cos(t1);
235
+ const sin1 = Math.sin(t1);
236
+ const cos2 = Math.cos(t2);
237
+ const sin2 = Math.sin(t2);
238
+ // The kappa factor for the half-sweep of this segment.
239
+ const alpha = (4 / 3) * Math.tan(dt / 4);
240
+ // Control points in the ellipse frame, then rotated.
241
+ const dx1 = -rx * sin1 * alpha;
242
+ const dy1 = ry * cos1 * alpha;
243
+ const dx2 = rx * sin2 * alpha;
244
+ const dy2 = -ry * cos2 * alpha;
245
+ const p1x = cx + cosφ * rx * cos1 - sinφ * ry * sin1;
246
+ const p1y = cy + sinφ * rx * cos1 + cosφ * ry * sin1;
247
+ const p2x = cx + cosφ * rx * cos2 - sinφ * ry * sin2;
248
+ const p2y = cy + sinφ * rx * cos2 + cosφ * ry * sin2;
249
+ const c1x = p1x + cosφ * dx1 - sinφ * dy1;
250
+ const c1y = p1y + sinφ * dx1 + cosφ * dy1;
251
+ const c2x = p2x + cosφ * dx2 - sinφ * dy2;
252
+ const c2y = p2y + sinφ * dx2 + cosφ * dy2;
253
+ appendPathCubicCurveTo(path, c1x, c1y, c2x, c2y, p2x, p2y);
254
+ }
255
+ }
256
+ // Every point-producing command (MOVE_TO, LINE_TO, CURVE_TO, CUBIC_CURVE_TO, and their
257
+ // WIDE variants) stores its anchor as the last two values pushed to `data[]`. CLOSE and
258
+ // NO_OP push no data. So the last anchor is always at the tail of the data array — O(1).
259
+ export function getPathLastPoint(path) {
260
+ const data = path.data;
261
+ if (data.length < 2)
262
+ return null;
263
+ return [data[data.length - 2], data[data.length - 1]];
264
+ }
265
+ // Normalizes corner radii for a rounded rectangle, clamping each corner radius to at most half the
266
+ // adjacent edge length so corners never overlap. Returns [topLeft, topRight, bottomRight, bottomLeft].
267
+ function normalizeCornerRadii(radius, width, height) {
268
+ const [rtl, rtr, rbr, rbl] = typeof radius === 'number' ? [radius, radius, radius, radius] : radius;
269
+ // Clamp each radius to half of the shorter adjacent edge.
270
+ const halfW = Math.abs(width) / 2;
271
+ const halfH = Math.abs(height) / 2;
272
+ const clampTL = Math.max(0, Math.min(rtl, halfW, halfH));
273
+ const clampTR = Math.max(0, Math.min(rtr, halfW, halfH));
274
+ const clampBR = Math.max(0, Math.min(rbr, halfW, halfH));
275
+ const clampBL = Math.max(0, Math.min(rbl, halfW, halfH));
276
+ return [clampTL, clampTR, clampBR, clampBL];
277
+ }
278
+ // Computes the signed angle from vector (ux,uy) to vector (vx,vy), following the SVG spec §F.6.5.6.
279
+ // The result is in the range (-π, π].
280
+ function vectorAngle(ux, uy, vx, vy) {
281
+ const dot = ux * vx + uy * vy;
282
+ const lenU = Math.sqrt(ux * ux + uy * uy);
283
+ const lenV = Math.sqrt(vx * vx + vy * vy);
284
+ if (lenU === 0 || lenV === 0)
285
+ return 0;
286
+ const cosAngle = Math.max(-1, Math.min(1, dot / (lenU * lenV)));
287
+ const angle = Math.acos(cosAngle);
288
+ return ux * vy - uy * vx < 0 ? -angle : angle;
289
+ }
290
+ // Optimal cubic Bezier arc approximation constant: 4*(sqrt(2)-1)/3.
291
+ // Maximum radial error is < 0.03% of the radius.
292
+ const KAPPA = 0.5522847498308936;
293
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Path, PathMesh, PathMeshTyped } from '@flighthq/types';
2
+ export declare function acquirePathMesh(path: Readonly<Path>, tolerance?: number): PathMesh;
3
+ export declare function acquirePathMeshTyped(path: Readonly<Path>, tolerance?: number): PathMeshTyped;
4
+ export declare function releasePathMesh(mesh: PathMesh): void;
5
+ export declare function releasePathMeshTyped(mesh: PathMeshTyped): void;
6
+ //# sourceMappingURL=pathMeshPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathMeshPool.d.ts","sourceRoot":"","sources":["../src/pathMeshPool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAarE,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,SAAO,GAAG,QAAQ,CAahF;AAID,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,SAAO,GAAG,aAAa,CAS1F;AAID,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAIpD;AAGD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAI9D"}
@@ -0,0 +1,58 @@
1
+ import { tessellatePath } from './tessellatePath';
2
+ import { tessellatePathTyped } from './tessellatePathTyped';
3
+ // Pool-backed flatten+tessellate for hot-loop usage. Each `acquirePathMesh` retrieves a `PathMesh`
4
+ // from a shared pool, tessellates the given path into it (replacing its contents), and returns it.
5
+ // Call `releasePathMesh` when done; the mesh is returned to the pool and must not be used again.
6
+ //
7
+ // Intended for scenes that flatten+tessellate the same paths every frame (particles, procedural
8
+ // shapes) to avoid per-frame heap allocation. The pool itself has no fixed capacity; released
9
+ // meshes are held until the pool grows beyond the high-water mark, then excess meshes are dropped.
10
+ // Each acquire/release pair is a matching bracket — do not acquire without releasing.
11
+ export function acquirePathMesh(path, tolerance = 0.25) {
12
+ const mesh = pathMeshPool.length > 0 ? pathMeshPool.pop() : { vertices: [], indices: [] };
13
+ // Reuse backing arrays: clear them and re-tessellate in place.
14
+ mesh.vertices.length = 0;
15
+ mesh.indices.length = 0;
16
+ const fresh = tessellatePath(path, tolerance);
17
+ // Copy into the pooled mesh rather than replacing, to preserve the array identity the caller
18
+ // receives (important if the caller passed an array reference into a renderer upload).
19
+ for (let i = 0; i < fresh.vertices.length; i++)
20
+ mesh.vertices[i] = fresh.vertices[i];
21
+ mesh.vertices.length = fresh.vertices.length;
22
+ for (let i = 0; i < fresh.indices.length; i++)
23
+ mesh.indices[i] = fresh.indices[i];
24
+ mesh.indices.length = fresh.indices.length;
25
+ return mesh;
26
+ }
27
+ // Pool-backed flatten+tessellate returning a `PathMeshTyped` (Float32Array / Uint32Array). The same
28
+ // acquire/release contract applies: one matching `releasePathMeshTyped` per `acquirePathMeshTyped`.
29
+ export function acquirePathMeshTyped(path, tolerance = 0.25) {
30
+ // Typed array meshes are reallocated on each acquire (the underlying ArrayBuffer cannot be
31
+ // resized to a different length). Pooling amortizes the allocation when the path data size is
32
+ // stable across frames; if size varies significantly the gain is smaller.
33
+ const fresh = tessellatePathTyped(path, tolerance);
34
+ const mesh = typedPool.length > 0 ? typedPool.pop() : { vertices: new Float32Array(0), indices: new Uint32Array(0) };
35
+ mesh.vertices = fresh.vertices;
36
+ mesh.indices = fresh.indices;
37
+ return mesh;
38
+ }
39
+ // Returns a `PathMesh` previously obtained from `acquirePathMesh` to the pool.
40
+ // The mesh must not be used after this call.
41
+ export function releasePathMesh(mesh) {
42
+ if (pathMeshPool.length < POOL_HIGH_WATER) {
43
+ pathMeshPool.push(mesh);
44
+ }
45
+ }
46
+ // Returns a `PathMeshTyped` previously obtained from `acquirePathMeshTyped` to the pool.
47
+ export function releasePathMeshTyped(mesh) {
48
+ if (typedPool.length < POOL_HIGH_WATER) {
49
+ typedPool.push(mesh);
50
+ }
51
+ }
52
+ // Maximum number of meshes held in each pool. Beyond this count, released meshes are dropped.
53
+ // A single active scene rarely needs more than a few dozen simultaneous meshes; 64 is a generous
54
+ // upper bound that still keeps pool overhead negligible.
55
+ const POOL_HIGH_WATER = 64;
56
+ const pathMeshPool = [];
57
+ const typedPool = [];
58
+ //# sourceMappingURL=pathMeshPool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathMeshPool.js","sourceRoot":"","sources":["../src/pathMeshPool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,mGAAmG;AACnG,mGAAmG;AACnG,iGAAiG;AACjG,EAAE;AACF,gGAAgG;AAChG,8FAA8F;AAC9F,mGAAmG;AACnG,sFAAsF;AACtF,MAAM,UAAU,eAAe,CAAC,IAAoB,EAAE,SAAS,GAAG,IAAI;IACpE,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,EAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC3F,+DAA+D;IAC/D,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACxB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC9C,6FAA6F;IAC7F,uFAAuF;IACvF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrF,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAClF,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;IAC3C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,oGAAoG;AACpG,oGAAoG;AACpG,MAAM,UAAU,oBAAoB,CAAC,IAAoB,EAAE,SAAS,GAAG,IAAI;IACzE,2FAA2F;IAC3F,8FAA8F;IAC9F,0EAA0E;IAC1E,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,EAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IACtH,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC/B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+EAA+E;AAC/E,6CAA6C;AAC7C,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,IAAI,YAAY,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAC1C,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,oBAAoB,CAAC,IAAmB;IACtD,IAAI,SAAS,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACvC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,8FAA8F;AAC9F,iGAAiG;AACjG,yDAAyD;AACzD,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,YAAY,GAAe,EAAE,CAAC;AACpC,MAAM,SAAS,GAAoB,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Path } from '@flighthq/types';
2
+ export declare function reversePath(source: Readonly<Path>, out: Path): void;
3
+ //# sourceMappingURL=reversePath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversePath.d.ts","sourceRoot":"","sources":["../src/reversePath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAY5C,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,CAQnE"}
@@ -0,0 +1,95 @@
1
+ import { PathCommand } from '@flighthq/types';
2
+ import { forEachPathSegment } from './forEachPathSegment';
3
+ // Reverses the winding direction of all contours in `source` and writes the result into `out`.
4
+ // Each subpath (from MOVE_TO to MOVE_TO / end) is independently reversed: its anchor sequence is
5
+ // flipped and control points are re-paired to match the reversed direction. The winding rule is
6
+ // preserved unchanged. Alias-safe: `out` may be the same object as `source`.
7
+ //
8
+ // Reversing a CCW contour produces CW, which is the standard technique for carving holes in a
9
+ // nonZero fill: append a CW copy of the inner boundary as a counter-wound subpath.
10
+ export function reversePath(source, out) {
11
+ const subpaths = decodeSubpaths(source);
12
+ out.commands.length = 0;
13
+ out.data.length = 0;
14
+ out.winding = source.winding;
15
+ for (const subpath of subpaths) {
16
+ encodeReversedSubpath(subpath, out);
17
+ }
18
+ }
19
+ function decodeSubpaths(path) {
20
+ const subpaths = [];
21
+ let current = null;
22
+ const ensureCurrent = () => {
23
+ if (current === null) {
24
+ current = { points: [{ x: 0, y: 0, kind: 'move' }], closed: false };
25
+ subpaths.push(current);
26
+ }
27
+ return current;
28
+ };
29
+ forEachPathSegment(path, (segment) => {
30
+ if (segment.kind === 'moveTo') {
31
+ current = { points: [{ x: segment.x, y: segment.y, kind: 'move' }], closed: false };
32
+ subpaths.push(current);
33
+ }
34
+ else if (segment.kind === 'lineTo') {
35
+ ensureCurrent().points.push({ x: segment.x, y: segment.y, kind: 'line' });
36
+ }
37
+ else if (segment.kind === 'curveTo') {
38
+ ensureCurrent().points.push({
39
+ x: segment.x,
40
+ y: segment.y,
41
+ kind: 'quad',
42
+ cx: segment.controlX,
43
+ cy: segment.controlY,
44
+ });
45
+ }
46
+ else if (segment.kind === 'cubicCurveTo') {
47
+ ensureCurrent().points.push({
48
+ x: segment.x,
49
+ y: segment.y,
50
+ kind: 'cubic',
51
+ c1x: segment.control1X,
52
+ c1y: segment.control1Y,
53
+ c2x: segment.control2X,
54
+ c2y: segment.control2Y,
55
+ });
56
+ }
57
+ else if (segment.kind === 'close') {
58
+ if (current !== null)
59
+ current.closed = true;
60
+ }
61
+ });
62
+ return subpaths;
63
+ }
64
+ function encodeReversedSubpath(subpath, out) {
65
+ const pts = subpath.points;
66
+ if (pts.length === 0)
67
+ return;
68
+ // The last point becomes the new start.
69
+ const last = pts[pts.length - 1];
70
+ out.commands.push(PathCommand.MOVE_TO);
71
+ out.data.push(last.x, last.y);
72
+ // Walk backwards from (n-1) down to 0, emitting the segment type of the point we're leaving.
73
+ for (let i = pts.length - 1; i >= 1; i--) {
74
+ const from = pts[i];
75
+ const to = pts[i - 1];
76
+ if (from.kind === 'line' || from.kind === 'move') {
77
+ out.commands.push(PathCommand.LINE_TO);
78
+ out.data.push(to.x, to.y);
79
+ }
80
+ else if (from.kind === 'quad') {
81
+ // Reversed quadratic: control stays the same, anchor is now `to`.
82
+ out.commands.push(PathCommand.CURVE_TO);
83
+ out.data.push(from.cx, from.cy, to.x, to.y);
84
+ }
85
+ else if (from.kind === 'cubic') {
86
+ // Reversed cubic: swap control points c1↔c2.
87
+ out.commands.push(PathCommand.CUBIC_CURVE_TO);
88
+ out.data.push(from.c2x, from.c2y, from.c1x, from.c1y, to.x, to.y);
89
+ }
90
+ }
91
+ if (subpath.closed) {
92
+ out.commands.push(PathCommand.CLOSE);
93
+ }
94
+ }
95
+ //# sourceMappingURL=reversePath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversePath.js","sourceRoot":"","sources":["../src/reversePath.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Path } from '@flighthq/types';
2
+ export declare function simplifyPath(source: Readonly<Path>, tolerance: number, out: Path, flattenTolerance?: number): void;
3
+ //# sourceMappingURL=simplifyPath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simplifyPath.d.ts","sourceRoot":"","sources":["../src/simplifyPath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAW5C,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,gBAAgB,SAAO,GAAG,IAAI,CAgChH"}
@@ -0,0 +1,78 @@
1
+ import { PathCommand } from '@flighthq/types';
2
+ import { flattenPath } from './flattenPath';
3
+ // Simplifies `source` by flattening curves and applying Douglas-Peucker decimation to each
4
+ // contour, removing points that deviate less than `tolerance` from the simplified line. Writes
5
+ // the result into `out`. Alias-safe: `out` may be the same object as `source`.
6
+ //
7
+ // Curves are first flattened (using `flattenTolerance`), then the resulting polylines are
8
+ // decimated. Closed contours that end at their start point remain closed in the output.
9
+ export function simplifyPath(source, tolerance, out, flattenTolerance = 0.25) {
10
+ const contours = flattenPath(source, flattenTolerance);
11
+ out.commands.length = 0;
12
+ out.data.length = 0;
13
+ out.winding = source.winding;
14
+ for (const contour of contours) {
15
+ const n = contour.length >> 1;
16
+ if (n < 2)
17
+ continue;
18
+ const closed = n >= 3 && contour[0] === contour[contour.length - 2] && contour[1] === contour[contour.length - 1];
19
+ const last = closed ? n - 1 : n;
20
+ const keep = new Uint8Array(last);
21
+ keep[0] = 1;
22
+ keep[last - 1] = 1;
23
+ douglasPeucker(contour, 0, last - 1, tolerance * tolerance, keep);
24
+ let first = true;
25
+ for (let i = 0; i < last; i++) {
26
+ if (!keep[i])
27
+ continue;
28
+ if (first) {
29
+ out.commands.push(PathCommand.MOVE_TO);
30
+ first = false;
31
+ }
32
+ else {
33
+ out.commands.push(PathCommand.LINE_TO);
34
+ }
35
+ out.data.push(contour[i * 2], contour[i * 2 + 1]);
36
+ }
37
+ if (closed) {
38
+ out.commands.push(PathCommand.CLOSE);
39
+ }
40
+ }
41
+ }
42
+ function douglasPeucker(pts, first, last, toleranceSq, keep) {
43
+ if (last - first < 2)
44
+ return;
45
+ const x0 = pts[first * 2];
46
+ const y0 = pts[first * 2 + 1];
47
+ const x1 = pts[last * 2];
48
+ const y1 = pts[last * 2 + 1];
49
+ const dx = x1 - x0;
50
+ const dy = y1 - y0;
51
+ const lenSq = dx * dx + dy * dy;
52
+ let maxDistSq = 0;
53
+ let maxIdx = first;
54
+ for (let i = first + 1; i < last; i++) {
55
+ const px = pts[i * 2];
56
+ const py = pts[i * 2 + 1];
57
+ let distSq;
58
+ if (lenSq === 0) {
59
+ const ax = px - x0;
60
+ const ay = py - y0;
61
+ distSq = ax * ax + ay * ay;
62
+ }
63
+ else {
64
+ const cross = dx * (y0 - py) - dy * (x0 - px);
65
+ distSq = (cross * cross) / lenSq;
66
+ }
67
+ if (distSq > maxDistSq) {
68
+ maxDistSq = distSq;
69
+ maxIdx = i;
70
+ }
71
+ }
72
+ if (maxDistSq > toleranceSq) {
73
+ keep[maxIdx] = 1;
74
+ douglasPeucker(pts, first, maxIdx, toleranceSq, keep);
75
+ douglasPeucker(pts, maxIdx, last, toleranceSq, keep);
76
+ }
77
+ }
78
+ //# sourceMappingURL=simplifyPath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simplifyPath.js","sourceRoot":"","sources":["../src/simplifyPath.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Path, StrokeStyle } from '@flighthq/types';
2
+ export type { StrokeStyle } from '@flighthq/types';
3
+ export declare function strokePath(path: Readonly<Path>, style: Readonly<StrokeStyle>, tolerance?: number): Path;
4
+ //# sourceMappingURL=strokePath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strokePath.d.ts","sourceRoot":"","sources":["../src/strokePath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKzD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAYnD,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,SAAO,GAAG,IAAI,CAsBrG"}