@thednp/dommatrix 3.0.6 → 3.1.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.
- package/AGENTS.md +16 -2
- package/CHANGELOG.md +43 -0
- package/README.md +16 -2
- package/dist/dommatrix.cjs +305 -110
- package/dist/dommatrix.cjs.map +1 -1
- package/dist/dommatrix.d.ts +39 -4
- package/dist/dommatrix.js +305 -110
- package/dist/dommatrix.js.map +1 -1
- package/dist/dommatrix.mjs +305 -110
- package/dist/dommatrix.mjs.map +1 -1
- package/package.json +4 -1
package/AGENTS.md
CHANGED
|
@@ -29,6 +29,9 @@ pnpm lint:ts # deno lint src
|
|
|
29
29
|
pnpm check:ts # tsc --noEmit
|
|
30
30
|
pnpm fix:ts # deno lint src --fix
|
|
31
31
|
pnpm format # deno fmt src
|
|
32
|
+
pnpm bench # vitest browser bench vs test/fixtures/index-3.0.x.ts (no coverage)
|
|
33
|
+
pnpm bench:native # vitest browser bench vs native DOMMatrix (no coverage)
|
|
34
|
+
pnpm bench:docs # run both bench suites (2x), write test/fixtures/bench-results.json, regenerate the BENCHMARK.md tables and the README ## Benchmarks summary
|
|
32
35
|
```
|
|
33
36
|
|
|
34
37
|
Always run `pnpm lint` and `pnpm test` after making changes.
|
|
@@ -38,9 +41,15 @@ Deno equivalents: `deno task test`, `deno task lint`, `deno task check`, `deno t
|
|
|
38
41
|
## Project Structure
|
|
39
42
|
|
|
40
43
|
- `src/index.ts` — the entire library (single file, ~1200 lines). The `CSSMatrix` class plus module-level helper functions (`Translate`, `Rotate`, `fromString`, etc.). Heavily documented with JSDoc.
|
|
44
|
+
- `test/fixtures/index-3.0.x.ts` — snapshot of the pre-3.1.0 implementation used as the benchmark baseline by `test/dommatrix.bench.test.ts`. Excluded from coverage (see `vitest.config.mts`) and from JSR publish (only the `publish.include` files ship). Included in the `tsconfig.json` `include` so `pnpm check:ts` covers it.
|
|
41
45
|
- `src/types.ts` — exported types (`JSONMatrix`, `Matrix`, `Matrix3d`, `PointTuple`)
|
|
42
46
|
- `test/dommatrix.test.ts` — the full test suite (Vitest, browser mode)
|
|
43
|
-
- `test/
|
|
47
|
+
- `test/dommatrix.bench.test.ts` — benchmark vs the `test/fixtures/index-3.0.x.ts` snapshot: parity suite (every op must match the backup within `1e-9`, runs in `pnpm test` and gates CI) + interleaved perf suite (auto-skipped under coverage)
|
|
48
|
+
- `test/native.bench.test.ts` — benchmark vs native `DOMMatrix`: parity suite (22 ops at `1e-9`, runs in `pnpm test`) + interleaved perf suite
|
|
49
|
+
- `test/fixtures/bench-results.json` — last measured results, written by `scripts/update-benchmark.js`; single source of truth for the `BENCHMARK.md` tables and the README `## Benchmarks` summary
|
|
50
|
+
- `scripts/update-benchmark.js` — runs both bench suites (2x, ~1 min), parses the `afterAll` tables from vitest stdout, writes the fixture, rewrites the two table blocks of `BENCHMARK.md` (between the `<!-- b1 -->`/`<!-- /b1 -->` and `<!-- b2 -->`/`<!-- /b2 -->` markers, plus the `<!-- b-updated -->` date stamp) and regenerates the README `## Benchmarks` summary
|
|
51
|
+
- `BENCHMARK.md` — the full benchmark report (static methodology intro, `<!-- b1 -->`/`<!-- b2 -->`-marked table blocks, static conclusion); only the marked blocks are regenerated by `pnpm bench:docs`
|
|
52
|
+
- `test/fixtures/` — test helpers, sample data, and the bench-results fixture
|
|
44
53
|
- `docs/` — GitHub Pages demo; `docs/dommatrix.js` is a build artifact copied from `dist/`
|
|
45
54
|
- `dist/` — build output, committed to the repo; regenerate with `pnpm build`, never edit by hand
|
|
46
55
|
- `experiments/` — archived Cypress experiments (not part of the build)
|
|
@@ -72,7 +81,7 @@ Deno equivalents: `deno task test`, `deno task lint`, `deno task check`, `deno t
|
|
|
72
81
|
1. Bump `version` in `package.json` **and** in `deno.json`
|
|
73
82
|
2. Add an entry to `CHANGELOG.md` (Keep a Changelog style, date-stamped)
|
|
74
83
|
3. Run `pnpm build && pnpm lint && pnpm test` and `deno publish --dry-run --allow-dirty`
|
|
75
|
-
4. Commit, then tag with the **bare version number** (no `v` prefix — existing tags are `1.0.0` ... `3.0
|
|
84
|
+
4. Commit, then tag with the **bare version number** (no `v` prefix — existing tags are `1.0.0` ... `3.1.0`)
|
|
76
85
|
|
|
77
86
|
The GitHub Actions `publish.yml` workflow publishes to both npm and JSR on GitHub Release (JSR via OIDC when enabled on the scope, otherwise the `JSR_TOKEN` secret).
|
|
78
87
|
|
|
@@ -83,5 +92,10 @@ Note: `prepublishOnly` runs `pnpm up --latest` (updates all deps), `pnpm format`
|
|
|
83
92
|
- The old `vite.config.ts` was replaced by `tsdown.config.mts` in 3.0.5 — `tsdown.config.mts` relies on: object-form `entry` for the chunk name (`dommatrix`), an `outputOptions` override for UMD (it must spread defaults, otherwise `sourcemap` is silently dropped), and `outExtensions` to keep the `.d.ts` filename. The `.mts` extension (not `.ts`) prevents Node's `MODULE_TYPELESS_PACKAGE_JSON` ESM-reparse warning — `package.json` deliberately has no `"type": "module"` because that would break Node `require()` of the UMD `dist/dommatrix.js`
|
|
84
93
|
- With `deno.json` present, `deno lint` enforces `verbatim-module-syntax` — type-only imports (like `import type CSSMatrix from "."` in `src/types.ts`) must use `import type`
|
|
85
94
|
- Vitest runs only in browser mode; any Node-only concern (globals, `require()`, `process`) needs the stubbed-global test pattern
|
|
95
|
+
- **Browser `console.table` is NOT forwarded to the terminal** — both bench suites accumulate rows on `globalThis` (`__CSSMATRIX_BENCH__`, `__CSSMATRIX_NATIVE_BENCH__`, inspectable in `pnpm test-ui` devtools) and print a pad-aligned `console.log` table in `afterAll`. `console.log` in `afterAll` *does* forward (but only with the verbose reporter — see next bullet).
|
|
96
|
+
- **The `BENCHMARK.md` tables are generated** by `pnpm bench:docs` (`scripts/update-benchmark.js`) from `test/fixtures/bench-results.json` — do not hand-edit the blocks between the `<!-- b1 -->`/`<!-- /b1 -->` and `<!-- b2 -->`/`<!-- /b2 -->` markers (the tables and their interpretation only), nor the `<!-- b-updated -->`/`<!-- /b-updated -->` date stamp; the intro and the closing conclusion are otherwise static. The script also regenerates the short README `## Benchmarks` summary — a "X–Yx faster" report with a last-updated line, linking to `BENCHMARK.md` — by writing between the `<!-- b-summary -->`/`<!-- /b-summary -->` markers of the section bounded by the `## Benchmarks` and `## Demo` headings (the script fails if that boundary is not found). It spawns vitest with `--reporter=verbose` (the default reporter does not forward browser `console.log`), parses the two `afterAll` tables from stdout, runs each suite twice and reports medians. Grouping thresholds: vs-3.0.x buckets at 6x / 2x / 1.12x (ratio >= 6 “Large”, >= 2 “Moderate”, >= 1.12 “Mild”, else “At parity”); native is split three-way at ±5% (the measured noise floor).
|
|
97
|
+
- **Bench measurements must run without coverage**: istanbul instruments `src/index.ts` but not `test/fixtures/index-3.0.x.ts`, so under coverage the current file measures 30-60% slower than an identical backup. The suites skip timing at runtime when `typeof globalThis["__VITEST_COVERAGE__"] === "object"` (the key only appears after instrumented code executes) — parity assertions still run in `pnpm test`.
|
|
98
|
+
- **Interleaved sampling**: `bench(a, b, iterations)` warms up both implementations, then takes 2 alternating samples each and reports medians. Sequential per-implementation measurement biases toward the first implementation (~20-30%) because the second's allocations raise GC pressure. Identical files must measure ~0.92-1.09x.
|
|
99
|
+
- Native DOMMatrix quirks that shaped `test/native.bench.test.ts`: Chrome lacks `DOMMatrix.fromArray` (use `DOMMatrix.fromMatrix(values)`); native has no `skew()`/`skewSelf()` (only `skewX`/`skewY`); `rotateAxisAngle(x, y, z, angle)` takes the angle last; `DOMPoint` exposes `x/y/z/w` as prototype getters so `Object.keys()` is empty — extract values into a plain object before comparing; the bench test needs a long timeout (120s) because 23 interleaved cases take ~15s.
|
|
86
100
|
- `rotateAxisAngle`/`rotateAxisAngleSelf` throw only when any of the 4 values is non-finite; zero-length vector returns a copy (or `this` for the `Self` variant)
|
|
87
101
|
- `deno lint` runs on `src/` only — the `tsconfig.json` `include` is `["src/*"]`, `noEmit: true`
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.1.1] - 2026-08-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `pnpm bench:docs` (`scripts/update-benchmark.js`): runs both bench suites twice, parses the printed tables, writes `test/fixtures/bench-results.json`, and regenerates the `BENCHMARK.md` tables and the README `## Benchmarks` summary from it — no more hand-transcribing benchmark numbers.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- The full benchmark report moved out of the README into a dedicated `BENCHMARK.md` (static methodology intro and conclusion, with the two result tables wrapped in `<!-- b1 -->` / `<!-- /b1 -->` and `<!-- b2 -->` / `<!-- /b2 -->` markers). The README `## Benchmarks` section is now a short summary — a one-line "X–Yx faster than the previous release / than native" range plus a link to `BENCHMARK.md` — so it keeps the attention on the big picture instead of the per-operation numbers.
|
|
17
|
+
- `setMatrixValue()` now **mutates the matrix in place and returns `this`**, matching the native `DOMMatrix.setMatrixValue()` (previously it returned a new matrix and left the original untouched). The `fromArray()` / `fromMatrix()` value writers now accept an optional target instance, so the array / object paths of `setMatrixValue()` write straight into the existing instance instead of allocating a new one. Both benchmark suites gained `setMatrixValue()` operations to cover the new path: array and transform-list inputs against the 3.0.x snapshot, and a parity-checked transform-list case against native (the native parity suite now covers 22 operations).
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- The native benchmark's `transformPoint` case measured asymmetric work: the shim side constructed the matrix from a transform string on every iteration while the native side reused a pre-built `DOMMatrix`. Both sides now pre-build the matrix, and the corrected measurement is ~11x shim-faster on `transformPoint` (previously reported as ~0.36x native-faster, see the 3.1.0 entry above); `test/fixtures/bench-results.json`, the `BENCHMARK.md` tables and the README `## Benchmarks` summary were regenerated with `pnpm bench:docs`.
|
|
22
|
+
|
|
23
|
+
[3.1.1]: https://github.com/thednp/dommatrix/releases/tag/3.1.1
|
|
24
|
+
|
|
25
|
+
## [3.1.0] - 2026-08-04
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- A benchmark suite in `test/dommatrix.bench.test.ts` comparing the current implementation against a `test/fixtures/index-3.0.x.ts` snapshot of the previous release: a parity suite (every operation must produce output identical to the backup, within `1e-9`) and a performance suite with interleaved, median-of-2 sampling per operation. Measurements are skipped automatically under coverage (istanbul instrumentation distorts timings); run `pnpm bench`.
|
|
30
|
+
- A native comparison suite in `test/native.bench.test.ts` comparing the current implementation against the browser's native `DOMMatrix`: parity at `1e-9` for 21 operations plus interleaved performance measurements; run `pnpm bench:native`.
|
|
31
|
+
- `pnpm bench` and `pnpm bench:native` scripts. Both suites store their result tables on `globalThis.__CSSMATRIX_BENCH__` / `__CSSMATRIX_NATIVE_BENCH__` for inspection in `pnpm test-ui` devtools, and print a combined table to the terminal (browser `console.table` output is not forwarded by Vitest).
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Major performance rework of the internal hot paths, all parity-verified against the previous release and against native `DOMMatrix`:
|
|
36
|
+
- `new CSSMatrix(init)` now fast-paths string / array / typed-array / object initializers instead of round-tripping through `setMatrixValue()`, and construction is funneled through a new internal `fromValues()` factory that writes all 22 aliases in one pass (a single hidden class keeps the constructor monomorphic).
|
|
37
|
+
- `CSSMatrix.fromString()` parses transform lists with a single regex iteration instead of split/filter/forEach, with equivalent strict validation of non-transform garbage.
|
|
38
|
+
- `CSSMatrix.fromArray()` and `CSSMatrix.fromMatrix()` validate and destructure input directly, no intermediate `Array` copy.
|
|
39
|
+
- `multiply()`/`multiplySelf()` share a new `multiplyInto()` kernel with a single 64-multiplication pass; `multiplySelf()` writes into `this` instead of allocating and spreading a result object.
|
|
40
|
+
- `translate()`, `translateSelf()`, `scale()`, `scaleSelf()`, `skew()`, `skewSelf()` (plus `skewX()`/`skewY()` delegating to `skew()`) use specialized pre-multiply math instead of general matrix multiplication.
|
|
41
|
+
- `toJSON()` builds the result object with explicit property writes instead of spreading `this`; `toFloat32Array()`/`toFloat64Array()` build typed arrays directly, skipping the intermediate `toArray()` allocation.
|
|
42
|
+
- Measured performance deltas (vs the `3.0.x` snapshot, Chromium, `pnpm bench`; ops/s ratios are noise-floor-corrected via interleaved sampling): `multiplySelf` ~17–18x, `scale` ~13x, `skew` ~6–14x, `translate` ~6.5–13x, `multiply` ~7x, `fromMatrix` ~7–7.6x, `rotate` ~5–5.6x, `rotateAxisAngle` ~4.1–4.5x, `toJSON` ~9.7–10.1x, `new CSSMatrix(transform list)` ~1.9–2.4x; unchanged code paths (`new CSSMatrix()`, `fromArray`, `transformPoint`, `toString`, `is2D`/`isIdentity`) measure ~0.96–1.1x.
|
|
43
|
+
- vs native `DOMMatrix` (`pnpm bench:native`, Chromium): the shim is faster on construction and mutation-heavy operations (e.g. `multiplySelf` ~48x, `translateSelf` ~28x, `scaleSelf` ~36x, `multiply` ~4x — largely native's Web IDL per-property access and `toJSON()` overhead) and on point transforms (`transformPoint` ~11x), while native wins only the serialization case: `toString` ~0.84x (shim/native ratios); `toFloat32Array` is at parity.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- `CSSMatrix.toArray()` remained coverage-uncovered after the typed-array paths stopped using it; the `is2D` branch is now exercised by tests again (coverage back to 100%).
|
|
48
|
+
|
|
49
|
+
[3.1.0]: https://github.com/thednp/dommatrix/releases/tag/3.1.0
|
|
50
|
+
|
|
8
51
|
## [3.0.6] - 2026-08-04
|
|
9
52
|
- The `README.md` now documents installing from JSR (`jsr add @thednp/dommatrix`).
|
|
10
53
|
|
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ A TypeScript sourced [DOMMatrix](https://developer.mozilla.org/en-US/docs/Web/AP
|
|
|
12
12
|
## Table of Contents
|
|
13
13
|
|
|
14
14
|
- [Features](#features)
|
|
15
|
+
- [Benchmarks](#benchmarks)
|
|
15
16
|
- [Demo](#demo)
|
|
16
17
|
- [Installation](#installation)
|
|
17
18
|
- [Quick Start](#quick-start)
|
|
@@ -32,6 +33,18 @@ A TypeScript sourced [DOMMatrix](https://developer.mozilla.org/en-US/docs/Web/AP
|
|
|
32
33
|
- **TypeScript** — bundled type definitions, including the `Matrix`, `Matrix3d`, `JSONMatrix` and `PointTuple` types
|
|
33
34
|
- **Verified against native** — every method is tested side-by-side with the native `DOMMatrix` in real browsers, with **100% test coverage**
|
|
34
35
|
|
|
36
|
+
## Benchmarks
|
|
37
|
+
|
|
38
|
+
<!-- b-summary -->
|
|
39
|
+
|
|
40
|
+
`CSSMatrix` is **1.2x–91x faster** than the previous 3.0.x release series and **1.8x–162x faster** than the native `DOMMatrix` — except `toString()`, which native does ~1.2x faster.
|
|
41
|
+
|
|
42
|
+
Every operation's result matches the previous release series and the native `DOMMatrix` to within `1e-9` (output is indistinguishable at the 9th decimal place). Full methodology, per-operation results and interpretation: [BENCHMARK](BENCHMARK.md).
|
|
43
|
+
|
|
44
|
+
Last updated: **2026-08-05**.
|
|
45
|
+
|
|
46
|
+
<!-- /b-summary -->
|
|
47
|
+
|
|
35
48
|
## Demo
|
|
36
49
|
|
|
37
50
|
See DOMMatrix shim in action, [click me](https://thednp.github.io/dommatrix) and start transforming.
|
|
@@ -151,7 +164,7 @@ For the complete JavaScript API, check the [JavaScript API](https://github.com/t
|
|
|
151
164
|
|
|
152
165
|
| Method | Description |
|
|
153
166
|
| --- | --- |
|
|
154
|
-
| `setMatrixValue(init)` |
|
|
167
|
+
| `setMatrixValue(init)` | Replaces the matrix values from the given string / array / object, mutates in place and returns `this` |
|
|
155
168
|
| `translate(x, y?, z?)` / `translateSelf(x, y?, z?)` | Applies a translation (CSS `translate3d()`) |
|
|
156
169
|
| `rotate(rx?, ry?, rz?)` / `rotateSelf(rx?, ry?, rz?)` | Applies a rotation; a single value rotates about the z-axis (CSS `rotate()`) |
|
|
157
170
|
| `rotateAxisAngle(x, y, z, angle)` / `rotateAxisAngleSelf(...)` | Applies a rotation about a vector (CSS `rotate3d()`) |
|
|
@@ -187,7 +200,7 @@ The shim mirrors the native **DOMMatrix** API surface closely — the same `m11`
|
|
|
187
200
|
| `transformOrigin` argument | Not supported | Supported (`new DOMMatrix(init, transformOrigin)`) |
|
|
188
201
|
| `is2D` / `isIdentity` | Computed getters — always reflect the current values | `is2D` is a flag fixed at construction and can report stale results (e.g. after `rotateAxisAngle()`) |
|
|
189
202
|
| `transformPoint()` | Accepts a `DOMPoint` **or** a plain `{ x, y, z, w }` tuple; returns the same type it received | Accepts `DOMPointInit`, always returns a `DOMPoint` |
|
|
190
|
-
| `setMatrixValue()` |
|
|
203
|
+
| `setMatrixValue()` | Mutates in place and returns `this`; accepts any of the shim's input types (string, array / typed array, `DOMMatrix`, plain object) | Mutates in place and returns `this`; accepts `DOMMatrixInit` only |
|
|
191
204
|
| `toArray()` | Plain `Array` of 6/16 values, alongside `toFloat32Array()` / `toFloat64Array()` | `toFloat32Array()` / `toFloat64Array()` only |
|
|
192
205
|
| `toJSON()` | `{ a-f, m11-m44, is2D, isIdentity }` | Same shape |
|
|
193
206
|
| TypeScript | Ships bundled type definitions, zero runtime dependencies | WebIDL-generated typings |
|
|
@@ -204,6 +217,7 @@ DOMMatrix shim is meant to be a light pocket tool for many things like [svg-path
|
|
|
204
217
|
|
|
205
218
|
- **changed** how the constructor determines if the matrix is 2D, based on a [more accurate method](https://github.com/jsidea/jsidea/blob/2b4486c131d5cca2334293936fa13454b34fcdef/ts/jsidea/geom/Matrix3D.ts#L788) which is actually checking the designated values of the 3D space; in contrast, the old *CSSMatrix* constructor sets the `afine` property at initialization only and based on the number of arguments or the type of the input CSS transform syntax;
|
|
206
219
|
- **fixed** the `translate()`, `scale()` and `rotate()` instance methods to work with one axis transformation, also inline with **DOMMatrix**;
|
|
220
|
+
- **added** the `*Self` instance methods — `translateSelf()`, `scaleSelf()`, `rotateSelf()`, `rotateAxisAngleSelf()`, `skewXSelf()`, `skewYSelf()`, `skewSelf()` and `multiplySelf()` — the mutating counterparts of the immutable methods above, inline with the native **DOMMatrix** API;
|
|
207
221
|
- **changed** `toString()` instance method to utilize the new method `toArray()` described below;
|
|
208
222
|
- **changed** `setMatrixValue()` instance method to do all the heavy duty work with parameters;
|
|
209
223
|
- **added** `is2D` (*getter*) property;
|