@emasoft/svg-matrix 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -1,25 +1,415 @@
1
- # SVG-MATRIX
1
+ # @emasoft/svg-matrix
2
2
 
3
3
  Arbitrary-precision matrix, vector and affine transformation library for JavaScript using decimal.js.
4
4
 
5
- This repository contains:
6
- - Decimal-backed Matrix and Vector classes.
7
- - 2D (3x3) and 3D (4x4) transform helpers.
5
+ ## Features
8
6
 
9
- Install:
7
+ - **Decimal-backed** Matrix and Vector classes for high-precision geometry
8
+ - **2D transforms** (3x3 homogeneous matrices): translation, rotation, scale, skew, reflection
9
+ - **3D transforms** (4x4 homogeneous matrices): translation, rotation (X/Y/Z axis), scale, reflection
10
+ - **SVG transform flattening**: parse transform attributes, build CTMs, flatten nested hierarchies
11
+ - **Linear algebra**: LU/QR decomposition, determinant, inverse, solve, matrix exponential
12
+ - **10^77 times better precision** than JavaScript floats for round-trip transforms
13
+ - Works in **Node.js** and **browsers** (via CDN)
14
+
15
+ ## Installation
16
+
17
+ ### npm
18
+
19
+ ```bash
20
+ npm install @emasoft/svg-matrix
21
+ ```
22
+
23
+ ```js
24
+ import { Decimal, Matrix, Vector, Transforms2D, Transforms3D, SVGFlatten } from '@emasoft/svg-matrix';
10
25
  ```
11
- npm install svg-matrix
26
+
27
+ ### CDN (Browser)
28
+
29
+ Using esm.sh (recommended - auto-resolves dependencies):
30
+
31
+ ```html
32
+ <script type="module">
33
+ import { Decimal, Matrix, Vector, Transforms2D, Transforms3D, SVGFlatten } from 'https://esm.sh/@emasoft/svg-matrix';
34
+
35
+ Decimal.set({ precision: 80 });
36
+
37
+ // Create and compose 2D transforms
38
+ const M = Transforms2D.translation(2, 3)
39
+ .mul(Transforms2D.rotate(Math.PI / 4))
40
+ .mul(Transforms2D.scale(1.5));
41
+
42
+ // Apply to a point
43
+ const [x, y] = Transforms2D.applyTransform(M, 1, 0);
44
+ console.log('Transformed:', x.toString(), y.toString());
45
+ </script>
46
+ ```
47
+
48
+ Using Skypack:
49
+
50
+ ```html
51
+ <script type="module">
52
+ import { Matrix, Vector } from 'https://cdn.skypack.dev/@emasoft/svg-matrix';
53
+ </script>
12
54
  ```
13
55
 
14
- Usage example:
56
+ Using import maps:
57
+
58
+ ```html
59
+ <script type="importmap">
60
+ {
61
+ "imports": {
62
+ "@emasoft/svg-matrix": "https://esm.sh/@emasoft/svg-matrix"
63
+ }
64
+ }
65
+ </script>
66
+ <script type="module">
67
+ import { Matrix, Vector, Transforms2D } from '@emasoft/svg-matrix';
68
+ </script>
69
+ ```
70
+
71
+ ## Usage Examples
72
+
73
+ ### Vector Operations
74
+
15
75
  ```js
16
- import { Decimal, Matrix, Vector, Transforms2D } from 'svg-matrix';
76
+ import { Vector, Decimal } from '@emasoft/svg-matrix';
77
+
17
78
  Decimal.set({ precision: 80 });
18
79
 
19
- const M = Transforms2D.translation(2, 3).mul(Transforms2D.rotate(Math.PI/4)).mul(Transforms2D.scale(1.5));
20
- const p2 = Transforms2D.applyTransform(M, 1, 0);
21
- console.log('Transformed point:', p2.map(x => x.toString()));
80
+ const v = Vector.from([1, 2, 3]);
81
+ const w = Vector.from([4, 5, 6]);
82
+
83
+ // Basic operations
84
+ console.log('Add:', v.add(w).toNumberArray()); // [5, 7, 9]
85
+ console.log('Scale:', v.scale(2).toNumberArray()); // [2, 4, 6]
86
+ console.log('Dot:', v.dot(w).toString()); // 32
87
+ console.log('Cross:', v.cross(w).toNumberArray()); // [-3, 6, -3]
88
+
89
+ // Geometry
90
+ console.log('Norm:', v.norm().toString()); // 3.7416...
91
+ console.log('Normalized:', v.normalize().toNumberArray());
92
+ console.log('Angle:', v.angleBetween(w).toString()); // radians
93
+
94
+ // Projection
95
+ const proj = v.projectOnto(w);
96
+ console.log('Projection:', proj.toNumberArray());
97
+ ```
98
+
99
+ ### Matrix Operations
100
+
101
+ ```js
102
+ import { Matrix } from '@emasoft/svg-matrix';
103
+
104
+ const A = Matrix.from([[1, 2], [3, 4]]);
105
+ const B = Matrix.from([[5, 6], [7, 8]]);
106
+
107
+ // Basic operations
108
+ console.log('Multiply:', A.mul(B).toNumberArray());
109
+ console.log('Transpose:', A.transpose().toNumberArray());
110
+ console.log('Determinant:', A.determinant().toString()); // -2
111
+ console.log('Trace:', A.trace().toString()); // 5
112
+
113
+ // Linear algebra
114
+ const inv = A.inverse();
115
+ console.log('Inverse:', inv.toNumberArray());
116
+
117
+ // Solve Ax = b
118
+ const x = A.solve([1, 1]);
119
+ console.log('Solution:', x.toNumberArray());
120
+
121
+ // Decompositions
122
+ const { L, U, P } = A.lu();
123
+ const { Q, R } = A.qr();
124
+
125
+ // Matrix exponential
126
+ const expA = A.exp();
127
+ ```
128
+
129
+ ### 2D Transforms
130
+
131
+ ```js
132
+ import { Transforms2D } from '@emasoft/svg-matrix';
133
+
134
+ // Basic transforms
135
+ const T = Transforms2D.translation(10, 20);
136
+ const R = Transforms2D.rotate(Math.PI / 4); // 45 degrees
137
+ const S = Transforms2D.scale(2, 3); // non-uniform
138
+ const Su = Transforms2D.scale(2); // uniform
139
+
140
+ // Rotation around a point
141
+ const Rp = Transforms2D.rotateAroundPoint(Math.PI / 2, 5, 5);
142
+
143
+ // Skew and stretch
144
+ const Sk = Transforms2D.skew(0.5, 0);
145
+ const St = Transforms2D.stretchAlongAxis(1, 0, 2); // stretch 2x along X
146
+
147
+ // Reflections
148
+ const Rx = Transforms2D.reflectX(); // flip Y
149
+ const Ry = Transforms2D.reflectY(); // flip X
150
+ const Ro = Transforms2D.reflectOrigin(); // flip both
151
+
152
+ // Compose transforms (right-to-left: S first, then R, then T)
153
+ const M = T.mul(R).mul(S);
154
+
155
+ // Apply to point
156
+ const [x, y] = Transforms2D.applyTransform(M, 1, 0);
157
+
158
+ // Inverse transform
159
+ const Minv = M.inverse();
160
+ const [xBack, yBack] = Transforms2D.applyTransform(Minv, x, y);
161
+ ```
162
+
163
+ ### 3D Transforms
164
+
165
+ ```js
166
+ import { Transforms3D } from '@emasoft/svg-matrix';
167
+
168
+ // Basic transforms
169
+ const T = Transforms3D.translation(1, 2, 3);
170
+ const S = Transforms3D.scale(2, 2, 2);
171
+
172
+ // Axis rotations (radians, right-hand rule)
173
+ const Rx = Transforms3D.rotateX(Math.PI / 2);
174
+ const Ry = Transforms3D.rotateY(Math.PI / 4);
175
+ const Rz = Transforms3D.rotateZ(Math.PI / 6);
176
+
177
+ // Rotation around arbitrary axis
178
+ const Raxis = Transforms3D.rotateAroundAxis(1, 1, 0, Math.PI / 3);
179
+
180
+ // Rotation around a point
181
+ const Rpt = Transforms3D.rotateAroundPoint(0, 0, 1, Math.PI / 2, 5, 5, 0);
182
+
183
+ // Reflections
184
+ const RfXY = Transforms3D.reflectXY(); // flip Z
185
+ const RfXZ = Transforms3D.reflectXZ(); // flip Y
186
+ const RfYZ = Transforms3D.reflectYZ(); // flip X
187
+ const RfO = Transforms3D.reflectOrigin(); // flip all
188
+
189
+ // Compose and apply
190
+ const M = T.mul(Rx).mul(S);
191
+ const [x, y, z] = Transforms3D.applyTransform(M, 1, 0, 0);
192
+ ```
193
+
194
+ ## API Reference
195
+
196
+ ### Vector
197
+
198
+ | Method | Description |
199
+ |--------|-------------|
200
+ | `Vector.from(arr)` | Create vector from array |
201
+ | `add(v)` | Element-wise addition |
202
+ | `sub(v)` | Element-wise subtraction |
203
+ | `scale(s)` | Scalar multiplication |
204
+ | `negate()` | Negate all components |
205
+ | `dot(v)` | Dot product |
206
+ | `cross(v)` | Cross product (3D only) |
207
+ | `outer(v)` | Outer product (returns 2D array) |
208
+ | `norm()` | Euclidean length |
209
+ | `normalize()` | Unit vector |
210
+ | `angleBetween(v)` | Angle in radians |
211
+ | `projectOnto(v)` | Vector projection |
212
+ | `orthogonal()` | Perpendicular vector |
213
+ | `distance(v)` | Euclidean distance |
214
+ | `equals(v, tol?)` | Equality check with optional tolerance |
215
+ | `toArray()` | Get Decimal array |
216
+ | `toNumberArray()` | Get number array |
217
+ | `toStringArray()` | Get string array |
218
+
219
+ ### Matrix
220
+
221
+ | Method | Description |
222
+ |--------|-------------|
223
+ | `Matrix.from(arr)` | Create from 2D array |
224
+ | `Matrix.zeros(r, c)` | Zero matrix |
225
+ | `Matrix.identity(n)` | Identity matrix |
226
+ | `add(M)` | Element-wise addition |
227
+ | `sub(M)` | Element-wise subtraction |
228
+ | `mul(M)` | Matrix multiplication |
229
+ | `div(s)` | Scalar division |
230
+ | `negate()` | Negate all elements |
231
+ | `transpose()` | Transpose |
232
+ | `trace()` | Sum of diagonal |
233
+ | `determinant()` | Determinant |
234
+ | `inverse()` | Matrix inverse |
235
+ | `solve(b)` | Solve Ax = b |
236
+ | `lu()` | LU decomposition |
237
+ | `qr()` | QR decomposition |
238
+ | `exp()` | Matrix exponential |
239
+ | `applyToVector(v)` | Matrix-vector product |
240
+ | `equals(M, tol?)` | Equality check |
241
+ | `isSquare()` | Check if square |
242
+ | `toNumberArray()` | Get number 2D array |
243
+ | `toArrayOfStrings()` | Get string 2D array |
244
+
245
+ ### Transforms2D
246
+
247
+ | Function | Description |
248
+ |----------|-------------|
249
+ | `translation(tx, ty)` | Translation matrix |
250
+ | `scale(sx, sy?)` | Scale matrix (uniform if sy omitted) |
251
+ | `rotate(theta)` | Rotation matrix (radians) |
252
+ | `rotateAroundPoint(theta, px, py)` | Rotation around point |
253
+ | `skew(ax, ay)` | Skew/shear matrix |
254
+ | `stretchAlongAxis(ux, uy, k)` | Stretch along direction |
255
+ | `reflectX()` | Reflect across X axis |
256
+ | `reflectY()` | Reflect across Y axis |
257
+ | `reflectOrigin()` | Reflect through origin |
258
+ | `applyTransform(M, x, y)` | Apply matrix to point |
259
+
260
+ ### Transforms3D
261
+
262
+ | Function | Description |
263
+ |----------|-------------|
264
+ | `translation(tx, ty, tz)` | Translation matrix |
265
+ | `scale(sx, sy?, sz?)` | Scale matrix |
266
+ | `rotateX(theta)` | Rotation around X axis |
267
+ | `rotateY(theta)` | Rotation around Y axis |
268
+ | `rotateZ(theta)` | Rotation around Z axis |
269
+ | `rotateAroundAxis(ux, uy, uz, theta)` | Rotation around arbitrary axis |
270
+ | `rotateAroundPoint(ux, uy, uz, theta, px, py, pz)` | Rotation around point |
271
+ | `reflectXY()` | Reflect across XY plane |
272
+ | `reflectXZ()` | Reflect across XZ plane |
273
+ | `reflectYZ()` | Reflect across YZ plane |
274
+ | `reflectOrigin()` | Reflect through origin |
275
+ | `applyTransform(M, x, y, z)` | Apply matrix to point |
276
+
277
+ ### SVGFlatten
278
+
279
+ | Function | Description |
280
+ |----------|-------------|
281
+ | `parseTransformFunction(func, args)` | Parse a single SVG transform function |
282
+ | `parseTransformAttribute(str)` | Parse a full SVG transform attribute string |
283
+ | `buildCTM(transformStack)` | Build CTM from array of transform strings |
284
+ | `applyToPoint(ctm, x, y)` | Apply CTM to a 2D point |
285
+ | `toSVGMatrix(ctm, precision?)` | Convert CTM back to SVG matrix() notation |
286
+ | `isIdentity(m, tolerance?)` | Check if matrix is effectively identity |
287
+ | `transformPathData(pathD, ctm)` | Transform path data coordinates |
288
+ | `PRECISION_INFO` | Object with precision comparison data |
289
+
290
+ ## SVG Transform Flattening
291
+
292
+ The `SVGFlatten` module provides tools for parsing SVG transform attributes, building CTMs (Current Transform Matrices), and flattening nested transforms with arbitrary precision.
293
+
294
+ ### Why Use SVGFlatten?
295
+
296
+ SVG elements can have deeply nested transforms through parent groups. When coordinates are transformed from local space to viewport and back using JavaScript's native 64-bit floats, precision is lost:
297
+
298
+ ```
299
+ Original coordinates: (10, 10)
300
+ After round-trip (float): (9.9857, 9.9857) // Error: 0.0143
301
+ ```
302
+
303
+ With `@emasoft/svg-matrix` using 80-digit Decimal precision:
304
+
305
+ ```
306
+ Original coordinates: (10, 10)
307
+ After round-trip: (10.00000000000000000000000000000000000000,
308
+ 9.999999999999999999999999999999999999999999999999999999999999999999999999999999998)
309
+ Round-trip error: X=0, Y=2e-79
310
+ ```
311
+
312
+ **Improvement: 10^77 times better precision than JavaScript floats.**
313
+
314
+ ### Parsing SVG Transforms
315
+
316
+ ```js
317
+ import { SVGFlatten } from '@emasoft/svg-matrix';
318
+
319
+ // Parse individual transforms
320
+ const m1 = SVGFlatten.parseTransformAttribute('translate(10, 20)');
321
+ const m2 = SVGFlatten.parseTransformAttribute('rotate(45)');
322
+ const m3 = SVGFlatten.parseTransformAttribute('scale(2, 0.5)');
323
+ const m4 = SVGFlatten.parseTransformAttribute('skewX(15)');
324
+ const m5 = SVGFlatten.parseTransformAttribute('matrix(0.866, 0.5, -0.5, 0.866, 0, 0)');
325
+
326
+ // Parse chained transforms
327
+ const combined = SVGFlatten.parseTransformAttribute('translate(50,50) rotate(45) scale(2)');
328
+ ```
329
+
330
+ ### Building CTM from Nested Elements
331
+
332
+ ```js
333
+ import { Decimal, SVGFlatten } from '@emasoft/svg-matrix';
334
+
335
+ Decimal.set({ precision: 80 });
336
+
337
+ // Simulate a 6-level SVG hierarchy:
338
+ // <svg viewBox="..."> <!-- viewBox scaling -->
339
+ // <g transform="translate(-13.6,-10.2)"> <!-- g1 -->
340
+ // <g transform="translate(-1144.8,517.6)"> <!-- g2 -->
341
+ // <g transform="rotate(15)"> <!-- g3 -->
342
+ // <g transform="scale(1.2, 0.8)"> <!-- g4 -->
343
+ // <path transform="matrix(...)"/> <!-- element -->
344
+
345
+ const transformStack = [
346
+ 'scale(1.5)', // viewBox scaling
347
+ 'translate(-13.613145,-10.209854)', // g1
348
+ 'translate(-1144.8563,517.64642)', // g2
349
+ 'rotate(15)', // g3
350
+ 'scale(1.2, 0.8)', // g4
351
+ 'matrix(0.71577068,0,0,1.3970955,0,0)' // element
352
+ ];
353
+
354
+ // Build combined CTM
355
+ const ctm = SVGFlatten.buildCTM(transformStack);
356
+
357
+ // Transform a point from local to viewport coordinates
358
+ const local = { x: new Decimal('10'), y: new Decimal('10') };
359
+ const viewport = SVGFlatten.applyToPoint(ctm, local.x, local.y);
360
+
361
+ // Transform back to local coordinates
362
+ const inverseCTM = ctm.inverse();
363
+ const recovered = SVGFlatten.applyToPoint(inverseCTM, viewport.x, viewport.y);
364
+
365
+ // Verify precision
366
+ const errorX = recovered.x.minus(local.x).abs();
367
+ const errorY = recovered.y.minus(local.y).abs();
368
+ console.log('Round-trip error X:', errorX.toString()); // 0
369
+ console.log('Round-trip error Y:', errorY.toString()); // ~2e-79
370
+ ```
371
+
372
+ ### Transforming Path Data
373
+
374
+ ```js
375
+ import { SVGFlatten } from '@emasoft/svg-matrix';
376
+
377
+ const pathD = 'M 100 100 L 200 100 L 200 200 L 100 200 Z';
378
+ const ctm = SVGFlatten.parseTransformAttribute('translate(50, 50) scale(2)');
379
+ const transformed = SVGFlatten.transformPathData(pathD, ctm);
380
+
381
+ console.log(transformed);
382
+ // M 250.000000 250.000000 L 450.000000 250.000000 L 450.000000 450.000000 L 250.000000 450.000000 Z
383
+ ```
384
+
385
+ ### Flattening All Transforms
386
+
387
+ To flatten an SVG (remove all transform attributes and apply them directly to coordinates):
388
+
389
+ ```js
390
+ import { SVGFlatten } from '@emasoft/svg-matrix';
391
+
392
+ // 1. For each element, collect transforms from root to element
393
+ // 2. Build CTM: const ctm = SVGFlatten.buildCTM(transformStack);
394
+ // 3. Transform path data: const newD = SVGFlatten.transformPathData(d, ctm);
395
+ // 4. Remove transform attribute, update path d attribute
396
+ // 5. Convert CTM back to SVG: SVGFlatten.toSVGMatrix(ctm, 6)
397
+ ```
398
+
399
+ ### CDN Usage
400
+
401
+ ```html
402
+ <script type="module">
403
+ import { Decimal, SVGFlatten } from 'https://esm.sh/@emasoft/svg-matrix';
404
+
405
+ Decimal.set({ precision: 80 });
406
+
407
+ const ctm = SVGFlatten.parseTransformAttribute('rotate(45, 100, 100)');
408
+ const point = SVGFlatten.applyToPoint(ctm, 50, 50);
409
+ console.log('Transformed:', point.x.toFixed(6), point.y.toFixed(6));
410
+ </script>
22
411
  ```
23
412
 
24
- See test/examples.js for more use cases.
413
+ ## License
25
414
 
415
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emasoft/svg-matrix",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Arbitrary-precision matrix, vector and affine transformation library for JavaScript using decimal.js",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -22,11 +22,25 @@
22
22
  "affine",
23
23
  "transform",
24
24
  "svg",
25
- "geometry"
25
+ "geometry",
26
+ "esm",
27
+ "browser",
28
+ "cdn",
29
+ "2d",
30
+ "3d",
31
+ "rotation",
32
+ "translation",
33
+ "homogeneous"
26
34
  ],
35
+ "exports": {
36
+ ".": {
37
+ "import": "./src/index.js",
38
+ "default": "./src/index.js"
39
+ }
40
+ },
27
41
  "author": "Emasoft",
28
42
  "license": "MIT",
29
43
  "dependencies": {
30
44
  "decimal.js": "^10.6.0"
31
45
  }
32
- }
46
+ }
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg id="pure_smill_no_javascript" version="1.1" x="0px" y="0px" width="1037.2269" height="1486.5736" viewBox="0 0 1037.227 2892.792" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
3
+ <defs id="defs82" />
4
+ <defs id="defs83" />
5
+ <g id="g37" transform="translate(-13.613145,-10.209854)">
6
+ <rect style="fill:#ffffff;stroke-width:16.1377" id="rect46" width="2018.3876" height="2892.792" x="-476.96716" y="10.209854" />
7
+ <g id="g1" transform="translate(-1144.8563,517.64642)">
8
+ <path id="rect1851" style="fill:none;stroke:#fe0000;stroke-width:14.5557;stroke-dasharray:87.3339, 14.5557;stroke-dashoffset:0;stroke-opacity:1" d="m 1318.7684,284.08405 c 307.4737,-77.43295 477.4693,-79.6744 779.5799,0 132.9776,50.26731 130.7718,132.64482 0,168.79753 -297.0165,89.1289 -485.8097,78.65553 -779.5799,0 -143.454,-38.49011 -151.4589,-124.05689 0,-168.79753 z" />
9
+ </g>
10
+ <g id="g6" transform="translate(13.613181,10.209854)">
11
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:94.4263px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#808000;stroke-width:16.0447" x="535.36902" y="880.21216" id="text2"><tspan id="tspan2" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:94.4263px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#808000;stroke-width:16.0447" x="535.36902" y="880.21216">100% PURE SMIL</tspan></text>
12
+ </g>
13
+ <g id="g7" transform="translate(13.613181,10.209854)">
14
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:51.2678px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#808000;stroke-width:8.7113" x="550.46289" y="939.87573" id="text3"><tspan id="tspan3" style="font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;font-size:51.2678px;font-family:Futura;-inkscape-font-specification:'Futura, Medium Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#808000;stroke-width:8.7113" x="550.46289" y="939.87573">No javascript or css needed!</tspan></text>
15
+ </g>
16
+ <text xml:space="preserve" style="font-style:italic;font-weight:600;font-size:85.6631px;font-family:'EB Garamond', serif;-inkscape-font-specification:'EB Garamond, serif, Semi-Bold Italic';writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="388.92661" y="1477.7195" id="text37" text-anchor="middle"><tspan id="tspan1" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:85.6631px;font-family:Futura;-inkscape-font-specification:'Futura, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="388.92661" y="1477.7195">100% PURE SMIL</tspan></text>
17
+ <text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'.New York';-inkscape-font-specification:'.New York, Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="363.31311" y="1603.9994" id="text39" text-anchor="middle"><tspan id="tspan38" style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'.New York';-inkscape-font-specification:'.New York, Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="363.31311" y="1603.9994">No javascript or css needed!</tspan></text>
18
+ <text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="678.02161" y="1757.4683" id="text40" transform="scale(0.71577068,1.3970955)" text-anchor="middle"><tspan id="tspan39" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.6396" x="678.02161" y="1757.4683">No javascript or css needed!</tspan></text>
19
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Luminari;-inkscape-font-specification:'Luminari, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="404.79761" y="2284.7117" id="text41" text-anchor="middle"><tspan id="tspan40" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Luminari;-inkscape-font-specification:'Luminari, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="404.79761" y="2284.7117">100% PURE SMIL</tspan></text>
20
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:85.6631px;font-family:'American Typewriter';-inkscape-font-specification:'American Typewriter, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="341.14975" y="1755.0848" id="text42" text-anchor="middle"><tspan id="tspan41" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:85.6631px;font-family:'American Typewriter';-inkscape-font-specification:'American Typewriter, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="341.14975" y="1755.0848">100% PURE SMIL</tspan></text>
21
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:85.6631px;font-family:'Comic Sans MS';-inkscape-font-specification:'Comic Sans MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="419.90002" y="1326.3029" id="text43" text-anchor="middle"><tspan id="tspan42" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:85.6631px;font-family:'Comic Sans MS';-inkscape-font-specification:'Comic Sans MS, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="419.90002" y="1326.3029">100% PURE SMIL</tspan></text>
22
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:'.SF Arabic Rounded';-inkscape-font-specification:'.SF Arabic Rounded, @opsz=80,wght=510';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'opsz' 80, 'wght' 510;writing-mode:lr-tb;direction:ltr;text-anchor:middle;white-space:pre;inline-size:1228.52;display:inline;fill:#000080;stroke-width:26.6984" x="1381.6643" y="1890.0889" id="text44" text-anchor="middle" transform="matrix(1.3203255,0,0,1.3203255,-1375.0262,-560.41607)"><tspan x="1381.6643" y="1890.0889" id="tspan27"><tspan style="text-align:end;text-anchor:end" id="tspan24">منتررف؛</tspan><tspan dx="212.47826" style="text-align:end;text-anchor:end" id="tspan25">٦٥</tspan><tspan dx="714.30957 -42.915234" style="text-align:end;text-anchor:end" id="tspan26">غفبممهت ورعبب</tspan><tspan y="1890.0889" id="tspan29"> </tspan></tspan><tspan x="1381.6643" y="1997.1678" id="tspan45"><tspan style="text-align:end;text-anchor:end" id="tspan30">٣٤٥٨</tspan><tspan dx="538.61511 0 0 0 0 25.01298 0 14.890675 -39.903576" style="text-align:end;text-anchor:end" id="tspan32">حخهـعنٌففڤك</tspan><tspan dx="296.26553" style="text-align:end;text-anchor:end" id="tspan33">٦</tspan><tspan dx="132.55197" style="text-align:end;text-anchor:end" id="tspan34">#</tspan><tspan dx="-47.641735" style="text-align:end;text-anchor:end" id="tspan35">٤</tspan><tspan dx="514.77338" style="text-align:end;text-anchor:end" id="tspan43">وحكهههـا؛جن</tspan></tspan></text>
23
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:67.9909px;font-family:'GohuFont 14 Nerd Font';-inkscape-font-specification:'GohuFont 14 Nerd Font, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.1905" x="604.13745" y="1147.0764" id="text45" text-anchor="middle"><tspan id="tspan44" style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:67.9909px;font-family:'GohuFont 14 Nerd Font';-inkscape-font-specification:'GohuFont 14 Nerd Font, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.1905" x="604.13745" y="1147.0764">100% PURE SMIL تاكهعغفبقڤذطسببى٦٥!§|</tspan></text>
24
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:Phosphate;-inkscape-font-specification:'Phosphate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="536.83356" y="1861.4491" id="text47" transform="scale(0.71577068,1.3970955)" text-anchor="middle"><tspan id="tspan47" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:Phosphate;-inkscape-font-specification:'Phosphate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.6396" x="536.83356" y="1861.4491">No javascript or css needed!</tspan></text>
25
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:'ProFont IIx Nerd Font';-inkscape-font-specification:'ProFont IIx Nerd Font, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="747.38995" y="525.20264" id="text48" transform="matrix(0.71322166,-0.06035344,0.11780243,1.3921201,0,0)" text-anchor="middle"><tspan id="tspan48" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:69.4323px;font-family:'ProFont IIx Nerd Font';-inkscape-font-specification:'ProFont IIx Nerd Font, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:21.6396" x="747.39001" y="525.20264">No javascript or css needed!</tspan></text>
26
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Bodoni Ornaments';-inkscape-font-specification:'Bodoni Ornaments, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="472.37082" y="2838.6682" id="text49" text-anchor="middle"><tspan id="tspan49" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Bodoni Ornaments';-inkscape-font-specification:'Bodoni Ornaments, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="472.37082" y="2838.6682">No javascript or css needed!</tspan></text>
27
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="533.84888" y="530.25562" id="text50" text-anchor="middle"><tspan id="tspan50" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="533.84888" y="530.25562">No javascript or css needed!</tspan></text>
28
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Zapfino;-inkscape-font-specification:'Zapfino, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="584.37799" y="397.6167" id="text51" text-anchor="middle"><tspan id="tspan51" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Zapfino;-inkscape-font-specification:'Zapfino, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="584.37799" y="397.6167">No javascript or css needed!</tspan></text>
29
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Webdings;-inkscape-font-specification:'Webdings, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="449.30762" y="120.5267" id="text52" text-anchor="middle"><tspan id="tspan52" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Webdings;-inkscape-font-specification:'Webdings, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="449.30762" y="120.5267">No javascript or css needed!</tspan></text>
30
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Copperplate;-inkscape-font-specification:'Copperplate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:19.8645" x="609.64258" y="246.02931" id="text53" text-anchor="middle"><tspan id="tspan53" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:Copperplate;-inkscape-font-specification:'Copperplate, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645" x="609.64258" y="246.02931">No javascript or css needed!</tspan></text>
31
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Luminari;-inkscape-font-specification:'Luminari, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:26.6984" x="450.42053" y="2729.5894" id="text54" text-anchor="middle"><tspan id="tspan54" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:85.6631px;font-family:Sans;-inkscape-font-specification:'Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:26.6984" x="450.42053" y="2729.5894">100% غعخيقفٌع٩ْخنتلو،حجةضصشيذزظطققثًار،منتزقُڤخهـرزلڤ</tspan></text>
32
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:302.923px;font-family:'.SF Arabic Rounded';-inkscape-font-specification:'.SF Arabic Rounded, @opsz=80,wght=510';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'opsz' 80, 'wght' 510;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#808000;stroke-width:51.4717" x="-101.66634" y="477.18921" id="text4"><tspan id="tspan4" style="stroke-width:51.4717" x="-101.66634" y="477.18921">兛</tspan><tspan style="stroke-width:51.4717" x="-101.66634" y="864.82745" id="tspan5">瓩</tspan><tspan style="stroke-width:51.4717" x="-101.66634" y="1252.4657" id="tspan6">☞</tspan></text>
33
+ <path style="font-variation-settings:'opsz' 80, 'wght' 510;fill:none;stroke:#e40000;stroke-width:17.0854;stroke-dasharray:none;stroke-opacity:0.648148" d="m 1417.5151,346.27451 c -172.195,68.09973 -181.5149,120.68753 -227.2008,324.94298 -10.7474,48.04981 -1.555,122.34751 21.0816,166.07303 l 3.347,6.46516 c 40.3542,77.94932 296.6243,309.72422 275.2567,92.27938" id="path7" />
34
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;text-anchor:middle;white-space:pre;fill:#000080;stroke-width:19.8645" id="text7" text-anchor="middle" transform="matrix(0.89589712,0,0,0.89589712,151.55716,65.666192)"><textPath xlink:href="#path7" startOffset="50%" id="textPath7"><tspan id="tspan7" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:63.7367px;font-family:'Academy Engraved LET';-inkscape-font-specification:'Academy Engraved LET, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000080;stroke-width:19.8645">No javascript or css needed!</tspan></textPath></text>
35
+ <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:268.424px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:2.43157;stroke-dasharray:none;stroke-opacity:0.648148" x="-50.072258" y="1466.8563" id="text8" transform="scale(0.86535508,1.155595)"><tspan id="tspan8" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:268.424px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:2.43157;stroke-dasharray:none" x="-50.072266" y="1466.8563">Λοπ</tspan></text>
36
+ <text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:300;font-stretch:normal;font-size:92.6956px;font-family:Superclarendon;-inkscape-font-specification:'Superclarendon, Light Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:0.839701;stroke-dasharray:none;stroke-opacity:0.648148" x="-41.03904" y="1797.0054" id="text9"><tspan id="tspan9" style="font-style:italic;font-variant:normal;font-weight:300;font-stretch:normal;font-size:92.6956px;font-family:Superclarendon;-inkscape-font-specification:'Superclarendon, Light Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#6d2eb8;fill-opacity:0.574074;stroke:none;stroke-width:0.839701;stroke-dasharray:none" x="-41.039047" y="1797.0054">lkœtrëå</tspan></text>
37
+ <text xml:space="preserve" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-decoration:underline;text-decoration-line:underline;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000080;stroke-width:21.6396" x="1786.3558" y="997.44519" id="text22" transform="scale(0.71577068,1.3970955)" text-anchor="middle" text-decoration="underline"><tspan id="tspan23" x="1785.8699" y="997.44519" style="text-align:end;text-anchor:end"><tspan id="tspan22" style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;text-anchor:end;fill:#000080;stroke-width:21.6396" x="1785.8699" y="997.44519">No javascript</tspan></tspan><tspan x="1785.8699" y="997.44519" id="tspan28"><tspan id="tspan36" style="text-align:end;text-anchor:end"><tspan style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:69.4323px;font-family:'Hurmit Nerd Font';-inkscape-font-specification:'Hurmit Nerd Font, Bold Italic';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;text-anchor:end;fill:#000080;stroke-width:21.6396" x="1785.8699" y="997.44519" id="tspan31"> </tspan></tspan></tspan><tspan x="1785.8699" y="1084.2356" id="tspan37">no css needed!</tspan></text>
38
+ </g>
39
+ </svg>
package/src/index.js CHANGED
@@ -1,7 +1,32 @@
1
+ /**
2
+ * @emasoft/svg-matrix - Arbitrary-precision matrix, vector and affine transformation library.
3
+ *
4
+ * This library provides Decimal-backed Matrix and Vector classes along with
5
+ * 2D (3x3) and 3D (4x4) transform helpers for geometry operations requiring high precision.
6
+ *
7
+ * @module @emasoft/svg-matrix
8
+ *
9
+ * @example
10
+ * import { Decimal, Matrix, Vector, Transforms2D, Transforms3D } from '@emasoft/svg-matrix';
11
+ *
12
+ * // Set precision for all operations
13
+ * Decimal.set({ precision: 80 });
14
+ *
15
+ * // Create and compose 2D transforms
16
+ * const M = Transforms2D.translation(2, 3)
17
+ * .mul(Transforms2D.rotate(Math.PI / 4))
18
+ * .mul(Transforms2D.scale(1.5));
19
+ *
20
+ * // Apply to a point
21
+ * const [x, y] = Transforms2D.applyTransform(M, 1, 0);
22
+ * console.log('Transformed:', x.toString(), y.toString());
23
+ */
24
+
1
25
  import Decimal from 'decimal.js';
2
26
  import { Matrix } from './matrix.js';
3
27
  import { Vector } from './vector.js';
4
28
  import * as Transforms2D from './transforms2d.js';
5
29
  import * as Transforms3D from './transforms3d.js';
30
+ import * as SVGFlatten from './svg-flatten.js';
6
31
 
7
- export { Decimal, Matrix, Vector, Transforms2D, Transforms3D };
32
+ export { Decimal, Matrix, Vector, Transforms2D, Transforms3D, SVGFlatten };