diff --git a/CHANGELOG.md b/CHANGELOG.md index aeddc57..33e7e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,61 +4,43 @@ ### Added -- Automerge-backed Rust document engine with validated atomic transactions, history, undo/redo, - causal heads, sync, deterministic repair, and native file recovery. -- Shared document model, generated TypeScript contracts, semantic metadata, ordered layers, - bindings, built-in shapes and stencils, and deterministic SVG/PNG rendering. -- CLI support for file and live-session inspection, queries, validation, structured mutations, - dry runs, rendering, schemas, and machine-readable output. -- Authenticated desktop IPC with direct live mutation and editor control. -- Rust-owned desktop sessions and browser WASM sessions covering create, open, mutate, persist, - reopen, undo/redo, projection, reconciliation, SVG import, and SVG rendering. -- Static SVG import and export with native primitives and paths, nested transforms, inherited - paint, retained source assets, and opaque fallback content for unsupported visuals. -- Native path geometry, rendering, hit testing, compound fills, and shared Rust/TypeScript fixtures. -- Hierarchical vector editing with nested selection, world-space transforms, reparenting, direct - anchor and handle editing, path topology operations, selection cycling, duplicate-and-connect, - shape conversion, and a searchable command palette. -- Selection refinement with object, equal-gap, handle, and grid snapping guides, modifier-aware - movement and drawing constraints, Alt-drag duplication, hover feedback, transformed handles, - edge scrolling, zoom-to-selection, and persisted grid preferences. -- Deterministic align, distribute, stack, grid, tidy, tree, flow, and radial layout operations, - with locked anchors and preserved connector and relationship references. -- Editable cards, ordered presentation frames, reusable image assets with captions, masks, color - sampling, and native URL, file, and page references. -- Semantic names, roles, tags, descriptions, sources, structured metadata, and typed relationships - across the model, editor, CLI, conversion, layout, inspection, merge, and export paths. -- Titled frames with child containment, move-with-contents behavior, nested selection, frame export, - binding-aware arrows, curved, elbow, and obstacle-aware routing, bend controls, labels, automatic - endpoint updates, and binding-preserving copy and persistence. -- Visual agent proposal review with object and relationship previews, partial acceptance, rejection, - stale-head handling, and distinct added, changed, moved, and removed states. -- Permissioned local MCP access to files and desktop sessions, with scoped reads and mutations, - dry runs, SVG import, layout, causal heads, and reviewed proposals. -- A responsive, keyboard-accessible board browser with sorting, storage and save details, workspace - switching, duplication, guarded board changes, actionable errors, and user-focused inspection. -- Excalidraw and Obsidian Canvas import/export, offline peer sync, and a bundled CLI and MCP agent - skill with file, proposal, and stale-head examples. +- Automerge-backed documents with validated atomic transactions, history, undo and redo, causal + heads, peer sync, deterministic repair, file locking, and recovery. +- Shared Rust document sessions for desktop, browser WebAssembly, CLI, and MCP, with generated + TypeScript contracts and a common editor projection. +- Native shapes, paths, groups, frames, cards, images, layers, assets, semantic metadata, + relationships, built-in stencils, and deterministic layout operations. +- Canvas editing with snapping, constraints, nested selection, path anchors and handles, connection + routing, duplicate-and-connect, typography controls, and a searchable command palette. +- Static SVG import and export with native geometry, hierarchy, transforms, compound fills, + embedded images, retained source assets, and warnings for omitted features. +- Excalidraw and Obsidian Canvas import and export, plus deterministic SVG and PNG rendering. +- CLI workflows for inspection, queries, validation, structured mutations, dry runs, rendering, + schemas, live desktop sessions, and machine-readable output. +- Permissioned local MCP access with scoped reads and mutations, SVG import, layout, causal heads, + and visual proposal review with partial acceptance. +- A responsive board browser with local persistence, workspace switching, sorting, duplication, + guarded board changes, storage details, and actionable errors. +- Shared performance fixtures and native, process, renderer-traversal, browser-interaction, and heap + measurements with recorded methodology, diagnostic traces, and regression ceilings. ### Changed -- Consolidated the editor into shared UI, runtime, DOM input, renderer, and core packages used by - desktop and web. -- Moved canonical browser document state and committed geometry operations to Rust while retaining - low-latency interaction previews in TypeScript. -- Unified the document model and SVG pipeline across desktop, web, WASM, CLI, and MCP. -- Standardized editor control states, sizing, pointer targets, and viewport-aware menu and popover - behavior, with Storybook and end-to-end coverage. -- Made transaction origin provenance-only in the document engine. CLI queries and mutations can - access invisible-layer and `agent_editable: false` records while causal checks, validation, - atomic commit, and ordinary shape and layer locks continue to apply. -- Removed Review/Direct session authorization and proposal commands from the general CLI. - Structured live mutations and `app apply` now commit after validation. +- Consolidated the web and desktop editors into shared UI, runtime, DOM input, renderer, and core + packages. +- Moved canonical browser state and committed geometry operations to Rust while keeping interaction + previews in TypeScript. +- Unified SVG parsing, transactions, and rendering across desktop, web, CLI, and MCP. +- Made transaction origin provenance-only. Validation, causal checks, record versions, and shape and + layer locks continue to govern mutations. +- Made general CLI live mutations commit directly after validation; reviewed and permissioned model + access remains in MCP. +- Cached validated Automerge projections until a local or remote change invalidates them, reducing + the reference flat 10,000-shape load from about 6.75 seconds to about 3.77 seconds on Apple M1. ### Fixed - Rejected malformed documents and transactions before canonical state changes. -- Repaired merge damage deterministically, including missing parents, duplicate child references, - broken bindings, and pages without layers. -- Corrected cursor mapping, nested-transform hit testing, path preview bounds, pointer capture, and - persistence recovery behavior. +- Repaired merge damage involving parents, child references, bindings, and missing page layers. +- Corrected cursor mapping, nested-transform hit testing, path preview bounds, pointer capture, + persistence recovery, menu placement, and browser heap-workload synchronization. diff --git a/ROADMAP.md b/ROADMAP.md index 1fb7a75..862832f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,21 +14,21 @@ each workflow. ### SVG round-trip -Inkfinite has one validated Rust SVG pipeline across desktop, web, and CLI. It -maps supported geometry into native shapes, preserves hierarchy, transforms, -and compound fills, retains source assets, and reports unsupported content. +Inkfinite has one validated Rust SVG pipeline across desktop, web, CLI, and +MCP. It maps supported geometry and embedded images into native shapes, +preserves hierarchy, transforms, and compound fills, retains source assets, and +reports unsupported content. Web SVG files, dropped files, and pasted markup +commit to the active document through the Rust browser session. -The native transaction already creates a root container and separate records -for supported SVG descendants. The remaining editor work must expose those -children through normal nested selection and ungrouping. Web SVG files and -pasted markup should add content to the active document by default, matching -desktop and CLI behavior. Creating a document from SVG should become a separate -explicit action. +The native transaction creates a root container and separate records for +supported SVG descendants. The remaining editor work must expose those children +through normal nested selection and ungrouping. Creating a document from SVG +should be a separate explicit action. The remaining work proves complete document workflows: save and reopen, edit and export, undo and redo, CRDT merge, and CLI access. Interchange work should favor deterministic native representation where Inkfinite understands the -content and stable visual fallback where it does not. +content and a static visual fallback where it does not. See [SVG import](apps/web/src/content/docs/development/svg-import.md) and [native path geometry](apps/web/src/content/docs/development/native-path-geometry.md). @@ -60,43 +60,6 @@ design, brainstorming, project planning, moodboards, research maps, and wireframes. They should be standard documents that users can inspect, edit, export, and repurpose, not substitutes for missing editor behavior. -### Performance profiling - -Performance characterization is part of the initial web release path. Replace -July 2026 prototype results with repeatable measurements across shared fixture -sizes and representative document structures. - -Use Criterion for native algorithms, `samply` for confirmed Rust hotspots, -`hyperfine` and coarse `tracing` spans for complete CLI, IPC, and MCP paths, -and Playwright with Chrome DevTools Protocol for actual browser frames and -memory. The native and process harnesses now cover validation, transactions, -merge, queries, layout, SVG, complete CLI commands, and MCP startup over the -shared corpus. Keep the no-op Canvas harness only as a renderer traversal -benchmark; it does not measure rasterization, compositing, text, GPU work, or -browser GC. - -The browser command in `@inkfinite/perf` drives the production web editor -against the shared corpus. It records Chrome frame, paint, raster, -compositor, long-task, GC, heap, JS-to-WASM, and projection/store measurements -for load and representative editing gestures. It also checks heap retention -through sustained editing and active-document replacement. Compact summaries -and gzipped diagnostic traces are written under -`fixtures/native/performance/` without enabling Playwright interaction -tracing. - -The August 2026 native, process, renderer-traversal, and browser baselines now -record machine-specific regression ceilings. Routine process and browser runs -use the flat 1,000-shape fixture; full size and profile sweeps are explicit. -Exact Criterion filters are anchored so a 1,000-shape investigation does not -also run the 10,000-shape case. - -Document loading is the first confirmed scaling concern: the flat 10,000-shape -Criterion case takes about 6.8 seconds per load on the reference Apple M1. The -10,000-shape browser heap-retention edit sequence also needs a reliable -completion path before it can serve as a baseline. Profile those paths before -adding indexes, caches, incremental materialization, alternate rendering, or -specialized allocation tooling. - ## Later Potential later work includes advanced vector operations, additional diff --git a/TODO.md b/TODO.md index 4710aa2..3292fd3 100644 --- a/TODO.md +++ b/TODO.md @@ -6,8 +6,6 @@ Run representative native and fallback SVG fixtures through each complete document workflow. Compare normalized structure where representation matters and rendered output where visual fidelity matters. -- [ ] Make the TypeScript browser adapter import SVG files and pasted markup - through the active Rust document session, page, and layer by default - [ ] Offer creation of a new document from SVG as a separate editor action - [ ] Verify and fix TypeScript editor traversal of imported root containers so existing child records can be selected, edited, reparented, and deleted independently @@ -18,7 +16,8 @@ and rendered output where visual fidelity matters. - [ ] Verify native vectors export without rasterization - [ ] Verify nested transforms export deterministically - [ ] Verify compound fill rules survive import and export -- [ ] Verify opaque fallback content remains visually stable +- [ ] Add sanitized static fallback content for unsupported visuals and verify + that it remains visually stable - [ ] Add deterministic round-trip fixtures for these workflows ## Richer interoperability and embeds @@ -53,66 +52,6 @@ and rendered output where visual fidelity matters. - [ ] Verify every starter through open, edit, save, reopen, inspect, and export - [ ] Add end-to-end tests for opening and editing each starter -## Performance profiling - -### Corpus and harnesses - -- [x] Build shared 100, 1,000, 5,000, and 10,000-shape fixtures for flat, - vector-heavy, deeply nested, imported-SVG, connection-heavy, and - semantic/binding-heavy documents -- [x] Replace the stale Node capture with a traversal-only benchmark against - the current editor renderer; keep its no-op canvas scope explicit -- [x] Add Criterion benchmarks for document load/save/materialization, - transactions, queries, SVG, layout, and renderer algorithms -- [x] Add a profiling Cargo profile with release optimizations and debug symbols -- [x] Record reference hardware, tool versions, fixture seeds, warmups, and - sampling methodology - -### Native and process measurements - -- [x] Benchmark validation, commit, undo/redo, merge, query, layout, and SVG - operations across fixture sizes -- [x] Use `samply` to attribute native CPU hotspots identified by benchmarks -- [x] Use `hyperfine` to measure complete CLI inspect, query, validate, render, - and mutate commands plus MCP startup -- [x] Add coarse `tracing` spans for document, IPC, and MCP operations so - end-to-end latency can be attributed without instrumenting hot geometry - loops - -### Browser measurements - -- [x] Add Playwright and CDP workloads for load, pan, zoom, box selection, - single- and multi-object drag, vector editing, connected-shape movement, - and nested selection -- [x] Capture real Chrome frame, paint, raster, compositor, long-task, GC, and - memory data instead of treating the no-op canvas benchmark as browser - rendering performance -- [x] Measure JS-to-WASM document operations and projection/store updates with - browser performance marks -- [x] Test heap retention after opening a 10,000-shape board, sustained editing, - and replacing the active document -- [x] Save compact summaries and diagnostic traces for representative browser - workloads without enabling full Playwright tracing during measurement - -### Baselines and optimization - -- [x] Refresh the July 2026 baseline and set regression budgets from current - native, process, and browser measurements -- [x] Record dominant costs and use Criterion deltas, Chrome traces, and - `samply` profiles to investigate regressions -- [x] Evaluate spatial indexes, path/render caches, incremental materialization, - alternate renderers, or allocation profilers only when a measured - bottleneck supports the change - -### Performance follow-up - -- [ ] Investigate native document load scaling: the flat 10,000-shape Criterion - case takes about 6.8 seconds per load on the reference Apple M1 -- [ ] Make the 10,000-shape browser heap-retention edit sequence finish reliably - before using it as a regression baseline -- [ ] Profile the confirmed load and mutation costs before choosing indexes, - caches, incremental materialization, or allocation changes - ## Backlog - [ ] Add boolean paths, gradient editing, clip/mask/filter editing, diff --git a/apps/web/src/content/docs/development/architecture.md b/apps/web/src/content/docs/development/architecture.md index 3071ad3..f9ebea7 100644 --- a/apps/web/src/content/docs/development/architecture.md +++ b/apps/web/src/content/docs/development/architecture.md @@ -98,6 +98,8 @@ geometry guide](/docs/development/native-path-geometry/) documents the path repr SVG interoperability and vector editing. The [SVG import guide](/docs/development/svg-import/) documents the parser's native mappings, transform rules, styles, text behavior, and asset handling. The [testing guide](/docs/development/testing/) documents shared fixtures and focused verification. +[Performance corpus and profiling](/docs/development/performance-corpus/) describes the native, +process, renderer, and browser measurement layers. ## Edit flow diff --git a/apps/web/src/content/docs/development/building-from-source.md b/apps/web/src/content/docs/development/building-from-source.md index 964eee2..006d069 100644 --- a/apps/web/src/content/docs/development/building-from-source.md +++ b/apps/web/src/content/docs/development/building-from-source.md @@ -70,4 +70,6 @@ pnpm check pnpm lint ``` -See [Testing](/docs/development/testing/) for focused package and Playwright commands. +See [Testing](/docs/development/testing/) for focused package and Playwright commands. See +[Performance corpus and profiling](/docs/development/performance-corpus/) for native, process, +renderer, and browser measurements. diff --git a/apps/web/src/content/docs/development/performance-corpus.md b/apps/web/src/content/docs/development/performance-corpus.md index 2809865..8d2b065 100644 --- a/apps/web/src/content/docs/development/performance-corpus.md +++ b/apps/web/src/content/docs/development/performance-corpus.md @@ -1,92 +1,95 @@ --- title: Performance corpus and profiling -description: 'How Inkfinite measures document, process, renderer, and browser performance against shared fixtures.' +description: 'How Inkfinite measures document, process, renderer, and browser performance with shared fixtures.' section: Development group: Development order: 24 --- -Inkfinite measures performance against a shared, deterministic document corpus. -The same document structures drive native benchmarks, complete command -measurements, renderer traversal, and browser interactions. This makes a result -more useful than a standalone timing: it identifies the document shape, scale, -operation, runtime, and machine that produced it. +Inkfinite measures performance with a shared, deterministic document corpus. +Native benchmarks, process measurements, renderer traversal, and browser +workloads use equivalent documents generated from the same profile, size, and +seed. Each result identifies the document shape, scale, operation, runtime, and +machine behind the timing. ## Corpus design -`fixtures/native/performance/corpus.json` defines one seed and six document -profiles at 100, 1,000, 5,000, and 10,000 shapes: +`fixtures/native/performance/corpus.json` defines a seed and six profiles. +Each profile is available at 100, 1,000, 5,000, and 10,000 shapes: -| Profile | What it stresses | +| Profile | Primary workload | | ------------------------ | ----------------------------------------------------- | | `flat` | Root-level shapes and general document overhead | | `vector-heavy` | Native paths and geometry traversal | | `deeply-nested` | Containers, transforms, and hierarchical selection | -| `imported-svg` | Native path records produced by the SVG pipeline | +| `imported-svg` | Native path records produced by the SVG import path | | `connection-heavy` | Arrows and endpoint bindings | | `semantic-binding-heavy` | Metadata, semantic queries, and relationship bindings | The manifest is checked in instead of thousands of generated documents. Rust -and TypeScript materialize equivalent fixtures from the profile, size, and -seed. A fixture change is therefore reviewable, while every measurement still -uses the current document model. +and TypeScript materialize equivalent fixtures from the profile, size, and seed. +A fixture change is therefore reviewable, while every measurement still uses the +current document model. A performance fixture should represent a real workload. Add a profile only when an existing structure cannot expose the cost under investigation. Keep seeds -stable when comparing results, and record a new baseline when fixture semantics +stable when comparing results. Record a new baseline when fixture semantics change. ## Measurement layers -No single harness describes application performance. Inkfinite separates four +No single harness measures all of application performance. Inkfinite uses four measurement layers: -1. **Native algorithms.** Criterion measures document load, save, +1. **Native algorithms.** Criterion measures document load and save, materialization, validation, transactions, undo and redo, merge, queries, - layout, SVG import and render, and scene rendering. + layout, SVG import and rendering, and scene rendering. 2. **Complete processes.** Hyperfine measures CLI startup and full `inspect`, `query`, `validate`, `render`, and mutation commands, plus MCP startup. 3. **Renderer traversal.** A Node harness runs the production editor renderer against a no-op Canvas context. It isolates scene traversal, culling, geometry dispatch, and renderer cache work. It does not measure pixels. -4. **Browser behavior.** Playwright and Chrome DevTools Protocol drive the +4. **Browser behavior.** Playwright and the Chrome DevTools Protocol drive the production web editor and collect frame, paint, raster, compositor, long-task, garbage-collection, heap, JS-to-WASM, and projection timings. The browser workloads cover load, pan, zoom, box selection, object dragging, vector editing, connected-shape movement, and nested selection. A separate -10,000-shape workload checks heap retention after sustained editing and active +10,000-shape workload measures heap retention after sustained editing and active document replacement. ## Running measurements -The private `@inkfinite/perf` package provides the TypeScript CLI. Root commands -build the required packages before starting a measurement: +The private `@inkfinite/perf` package provides the TypeScript CLI. Run these +commands from the repository root. Each root command builds the packages it +needs before starting the measurement: ```sh -# Renderer traversal across the shared corpus +# Measure renderer traversal across the shared corpus pnpm performance:capture -# Complete CLI and MCP timings for the flat 1,000-shape fixture +# Measure complete CLI and MCP timings for the flat 1,000-shape fixture pnpm performance:process -# Representative browser interactions for the flat 1,000-shape fixture +# Measure representative browser interactions for the flat 1,000-shape fixture pnpm performance:browser -# The slower 10,000-shape browser memory workload +# Run the slower 10,000-shape browser memory workload pnpm performance:browser -- --memory -# One focused native CPU profile +# Record one focused native CPU profile pnpm performance:profile -- --filter 'transactions/commit/semantic-binding-heavy/100$' ``` -Use `node packages/perf/dist/cli.mjs --help` after running -`pnpm perf:build` to inspect filters and expansion options. The browser command -uses a representative 1,000-shape interaction run by default. Process -measurements use the same size. Request `--all-sizes` or `--all-profiles` only -for a baseline refresh or a scale-specific investigation. Browser heap -retention is also opt-in with `--memory` because its 10,000-shape edit sequence -is much slower than the interaction baseline. +After running `pnpm perf:build`, use +`node packages/perf/dist/cli.mjs --help` to inspect filters and +expansion options. Process and browser measurements use the flat 1,000-shape +fixture by default. Use `--all-sizes` or `--all-profiles` only for a baseline +refresh or a scale-specific investigation. Browser heap retention is opt-in +with `--memory` because its 10,000-shape edit sequence is much slower than the +interaction baseline. The sequence waits for each edit's WebAssembly operation +and rendered frames before starting the next edit. Document replacement can +take up to two minutes at this size. Run one Criterion benchmark when recording with Samply. End exact Criterion filters with `$`: without it, a filter ending in `/1000` also matches `/10000`. @@ -95,33 +98,49 @@ much longer without producing better evidence. ## Reading results -Compact summaries live under `fixtures/native/performance/`. Browser captures -retain one gzipped Chrome trace for the first measured sample of each workload. -The summaries record fixture inputs, warmups, sample counts, tool versions, and -hardware alongside the measurements. Each measured timing also records a -machine-specific regression ceiling 20% above the selected baseline statistic. -Refresh that ceiling when the fixture, machine, or measurement method changes. +Compact summaries are stored under `fixtures/native/performance/`. Browser +captures retain one gzipped Chrome trace for the first measured sample of each +workload. The summaries record fixture inputs, warmups, sample counts, tool +versions, and hardware alongside the measurements. Each measured timing also +records a machine-specific regression ceiling 20% above the selected baseline +statistic. Refresh that ceiling when the fixture, machine, or measurement method +changes. Compare results only when the fixture, operation, build profile, and hardware -are compatible. Treat small changes near timer noise as inconclusive. Browser -traces explain frame and memory behavior; Criterion deltas explain native hot -paths; Samply attributes CPU time after a benchmark identifies a regression. - -A traversal result is not a browser frame budget. The no-op Canvas harness -excludes rasterization, text shaping, paint, compositing, GPU work, and browser -garbage collection. Likewise, an algorithm benchmark does not include CLI -startup, filesystem access, IPC, or serialization around that algorithm. +are compatible. Treat small changes near timer noise as inconclusive. Use +browser traces to explain frame and memory behavior, Criterion deltas to +identify native hot paths, and Samply to attribute CPU time after a benchmark +identifies a regression. + +Do not use a renderer-traversal result as a browser frame budget. The no-op +Canvas harness excludes rasterization, text shaping, paint, compositing, GPU +work, and browser garbage collection. An algorithm benchmark also excludes CLI +startup, filesystem access, IPC, and serialization around that algorithm. + +## Findings from August 2026 + +Focused load and commit profiles showed repeated materialization of an unchanged +Automerge projection. The native adapter now caches the validated projection +and clears it after every local or remote change. On the reference Apple M1, +the flat 10,000-shape Criterion load fell from about 6.75 seconds to about 3.77 +seconds. A commit on the same fixture still takes about 3.59 seconds because the +current transaction path reconciles the full document. + +The first completed 10,000-shape browser memory baseline took 150 seconds for +20 edits. The JavaScript heap was 310 MB above the pre-load reading after those +edits and 286 MB above it after active-document replacement. Use this capture to +investigate retained editor and WebAssembly state; it is not a memory target. ## Setting budgets and optimizing -Set a regression budget only after repeated current measurements establish a -stable baseline. Record the dominant cost and choose the harness closest to the +Set a regression budget only after repeated measurements establish a stable +baseline. Record the dominant cost and choose the harness closest to the user-visible behavior. Keep the budget wide enough for expected machine noise but narrow enough to catch a meaningful regression. -Optimize the measured path rather than adding infrastructure speculatively. A -connection-heavy traversal regression, for example, can justify indexing -bindings once per render pass. A slow query may justify an index only after the -query benchmark and an end-to-end command measurement identify the same cost. -Re-run the focused measurement after the change, then run the representative -baseline to check that the optimization did not move work into another layer. +Optimize the measured path instead of adding infrastructure speculatively. A +connection-heavy traversal regression can justify indexing bindings once per +render pass. A slow query may justify an index only after the query benchmark +and an end-to-end command measurement identify the same cost. Re-run the focused +measurement after the change, then run the representative baseline to check that +the optimization did not move work into another layer. diff --git a/apps/web/src/content/docs/development/svg-import.md b/apps/web/src/content/docs/development/svg-import.md index 0773a6f..86bbb73 100644 --- a/apps/web/src/content/docs/development/svg-import.md +++ b/apps/web/src/content/docs/development/svg-import.md @@ -39,9 +39,8 @@ create the import transaction. `source_asset` is the exact UTF-8 input as an `image/svg+xml` asset with a content-addressed ID. `assets` contains the embedded raster assets referenced -by image nodes. The source asset is retained even when the native tree omits -unsupported content, so a later transaction can re-import it or attach an -opaque fallback when that shape kind exists. +by image nodes. The source asset remains available for provenance and re-import +even when the native tree omits unsupported content. ## Native mappings @@ -122,8 +121,8 @@ External URLs and unsupported media types are skipped with warnings. The parser does not fetch resources. `SvgImage` nodes retain the source element's position, size, transform, -opacity, and asset ID. The current native shape registry has no image kind, so -these nodes remain in the import result until image shape support is added. +opacity, and asset ID. The SVG transaction maps each node to a native `image` +shape that references the extracted asset. ## Unsupported content and security @@ -131,10 +130,8 @@ The importer is a static parser. Named unsupported visual features are omitted from the normalized native tree and reported through typed `SvgImportWarning::UnsupportedFeature` values. Other unsupported elements use `SvgImportWarning::UnsupportedElement`. Their bytes remain in -`source_asset`. The importer does not create a live opaque fallback because the -native document model does not yet have an SVG-backed shape. A future fallback -must render only a sanitized, static projection of the retained source and keep -the imported subtree movable as one object. +`source_asset`. The importer does not create a live fallback for omitted +content. Desktop imports use the native Tauri dialog plugin to select a path, then Rust reads, parses, and commits the file through the active session. The browser adapter diff --git a/apps/web/src/content/docs/development/testing.md b/apps/web/src/content/docs/development/testing.md index 039ca37..432e7bc 100644 --- a/apps/web/src/content/docs/development/testing.md +++ b/apps/web/src/content/docs/development/testing.md @@ -6,12 +6,12 @@ group: Development order: 23 --- -Inkfinite keeps fast correctness checks close to the code they protect. Rust and -Vitest suites cover the document model, interchange boundaries, persistence, -and component behavior. Playwright covers editor workflows that need the full -web app. +Inkfinite keeps correctness checks near the code they protect. Rust tests and +Vitest suites cover the document model, interchange boundaries, persistence, and +component behavior. Playwright covers editor workflows that require the full web +app. -Run the complete unit and integration suite from the repository root: +Run the complete unit and integration test suite from the repository root: ```sh pnpm test @@ -19,10 +19,10 @@ pnpm test ## Component states -Storybook stories in `packages/ui/src/` cover shared controls and complete editor states in light and -dark themes. Include hover, pressed, selected, disabled, busy, and focus-visible states when they -apply to a component. Menus and popovers should also show dismissal, focus restoration, and -viewport-edge placement. +Storybook stories in `packages/ui/src/` show shared controls and complete editor +states in light and dark themes. Include the states that apply to each component: hover, +pressed, selected, disabled, busy, and focus-visible. Menus and popovers should +also show dismissal, focus restoration, and placement at viewport edges. ```sh pnpm dev:ui @@ -32,14 +32,13 @@ pnpm --filter @inkfinite/ui storybook:build ## Editor end-to-end tests `apps/web/e2e/` contains behavioral and visual Playwright tests. The shared -`InkfiniteEditor` fixture provides a small set of canvas operations such as -choosing tools, dragging, drawing rectangles, and selecting objects. Tests -should use accessible locators for controls and keep coordinate-based input -inside these canvas operations. +`InkfiniteEditor` fixture provides canvas operations such as choosing tools, +dragging, drawing rectangles, and selecting objects. Use accessible locators for +controls and keep coordinate-based input inside these canvas operations. -Behavioral tests assert what the editor does. Visual tests use the `@visual` tag -and Playwright's `toHaveScreenshot()` matcher to compare the rendered result -with checked-in baselines. +Behavioral tests assert editor behavior. Visual tests use the `@visual` tag and +Playwright's `toHaveScreenshot()` matcher to compare the rendered result with +checked-in baselines. ```sh # Run behavioral and visual editor tests @@ -55,20 +54,21 @@ pnpm test:visual:update pnpm test:e2e:ui ``` -The Playwright runner starts the web app, fixes the viewport and theme, waits -for fonts, hides screenshot carets, and retains traces on failures. It runs the -editor tests serially because simultaneous editor startup makes the development -server and WebAssembly initialization unreliable. +The Playwright setup starts the web app, sets the viewport, waits for fonts, +hides screenshot carets, and retains traces on failures. Tests choose the theme +through the shared fixture. The suite runs editor tests serially because +simultaneous editor startup makes the development server and WebAssembly +initialization unreliable. Review every changed baseline at its captured size before accepting it. Keep the browser channel, fonts, operating system, and headless mode consistent when -creating authoritative baselines because those inputs can change rasterization. -Playwright writes actual, expected, and diff images under `apps/web/test-results/` -when a comparison fails. +creating authoritative baselines; these inputs can change rasterization. +Playwright writes actual, expected, and diff images under +`apps/web/test-results/` when a comparison fails. -Standalone scripts remain appropriate for profiling and publication assets. -UI validation belongs in the Playwright suite rather than a script that starts -Vite, launches a browser, and writes passive screenshots. +Use the Playwright suite for UI validation. Use standalone scripts for profiling +and publication assets, not a script that starts Vite, launches a browser, and +writes screenshots without assertions. ## SVG import fixture corpus @@ -78,9 +78,9 @@ Simple Icons, Skill Icons, and Devicon Plain Iconify sets. The corpus also covers nested group transforms, compound even-odd paths, unsupported features and active content, and malformed XML, numbers, paths, and transforms. -The fixture tests check native node counts, source retention, `currentColor`, -path validation, fill rules, warning coverage, and typed failures. Add a -minimized fixture when a real SVG exposes an importer regression. +The tests check native node counts, source retention, `currentColor`, path +validation, fill rules, warning coverage, and typed failures. Add a minimized +fixture when a real SVG exposes an importer regression. Run the focused suite with: @@ -88,5 +88,5 @@ Run the focused suite with: cargo test -p inkfinite-core --test svg_import_fixtures ``` -The source and licenses for the Iconify-derived inputs are listed in the -repository's `fixtures/svg-import/README.md`. +The repository lists the sources and licenses for the Iconify-derived inputs in +`fixtures/svg-import/README.md`. diff --git a/apps/web/src/content/docs/guide/import-and-export.md b/apps/web/src/content/docs/guide/import-and-export.md index e691d12..7a723c5 100644 --- a/apps/web/src/content/docs/guide/import-and-export.md +++ b/apps/web/src/content/docs/guide/import-and-export.md @@ -29,9 +29,9 @@ Choose **Import**, paste content, or drop a supported file on the canvas. Import Obsidian Canvas file creates an Inkfinite document and leaves the source unchanged. SVG import maps supported static elements to native shapes and assets. -An import report lists omitted content, conversions, and fallback content. Keep the source until you -have checked the imported board. Unsupported SVG visuals may be retained as opaque fallback content -rather than editable geometry. +An import report lists conversions, warnings, and omitted content. Keep the source until you have +checked the imported board. Inkfinite retains the original SVG as a source asset, but unsupported +visuals do not appear on the canvas. ## Export a board diff --git a/apps/web/src/content/docs/guide/vector-editing.md b/apps/web/src/content/docs/guide/vector-editing.md index 83eb9d8..deeb76c 100644 --- a/apps/web/src/content/docs/guide/vector-editing.md +++ b/apps/web/src/content/docs/guide/vector-editing.md @@ -29,8 +29,8 @@ closing segment. Split creates a new anchor on a segment. Join connects compatib ## Imported SVG paths SVG paths and supported vector primitives become native Inkfinite geometry during import. Their -anchors and segments can then be edited with Direct Select. Unsupported visual content may remain -as opaque fallback content and cannot expose native anchors. +anchors and segments can then be edited with Direct Select. Inkfinite reports and omits unsupported +visual content. Read [Import and export](/docs/guide/import-and-export/) for the supported workflow. Maintainers can read [Native path geometry](/docs/development/native-path-geometry/) for the stored representation diff --git a/apps/web/src/content/docs/reference/interoperability.md b/apps/web/src/content/docs/reference/interoperability.md index 7192587..a25bab2 100644 --- a/apps/web/src/content/docs/reference/interoperability.md +++ b/apps/web/src/content/docs/reference/interoperability.md @@ -11,7 +11,7 @@ order: 16 | Format | Import | Export | Editability | Main limits | | -------------------------- | ----------- | ------ | ------------------------------------ | ------------------------------------------------------- | | `.inkfinite` | Yes | Yes | Native | Use desktop or CLI for files | -| SVG | Yes | Yes | Supported geometry is native | Unsupported visuals may use fallback content | +| SVG | Yes | Yes | Supported geometry is native | Unsupported visuals are omitted with warnings | | PNG | As an image | Yes | Raster | No individual vector objects | | Excalidraw v2 | Yes | Yes | Supported objects are mapped | Rough styles, some shapes, and exact metrics differ | | Obsidian / JSON Canvas 1.0 | Yes | Yes | Supported nodes and edges are mapped | General drawing shapes and rotation are not represented | @@ -29,8 +29,9 @@ JSON Canvas conversion supports text, file, link, and group nodes plus edges bet format cannot represent Inkfinite's general drawing primitives, freehand strokes, layers, rotation, or free-floating arrows. -SVG import maps the supported static subset to native shapes. SVG export produces vector output for -the current page or selection. PNG captures the current viewport. +SVG import maps the supported static subset and embedded raster images to native shapes and retains +the original SVG as a source asset. It omits unsupported visuals with warnings. SVG export produces +vector output for the current page or selection. PNG captures the current viewport. Read [Import and export](/docs/guide/import-and-export/) for the editor workflow and [File format](/docs/reference/file-format/) for native storage details. diff --git a/crates/inkfinite-core/src/crdt/mod.rs b/crates/inkfinite-core/src/crdt/mod.rs index 1a6031b..1c8379b 100644 --- a/crates/inkfinite-core/src/crdt/mod.rs +++ b/crates/inkfinite-core/src/crdt/mod.rs @@ -88,7 +88,7 @@ impl From for CrdtError { } } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] struct StoredSnapshot { format: FormatId, format_version: u32, @@ -100,11 +100,17 @@ struct StoredSnapshot { pub struct AutomergeDocument { document: AutoCommit, actor_id: ActorId, + // Invalidated whenever Automerge adopts or commits a change. + cached_snapshot: Option, } impl Clone for AutomergeDocument { fn clone(&self) -> Self { - Self { document: self.document.clone(), actor_id: self.actor_id.clone() } + Self { + document: self.document.clone(), + actor_id: self.actor_id.clone(), + cached_snapshot: self.cached_snapshot.clone(), + } } } @@ -135,13 +141,15 @@ impl AutomergeDocument { document_id: current.document_id, document: document.clone(), }; - let value = serde_json::to_value(stored)?; + let value = serde_json::to_value(&stored)?; + self.cached_snapshot = None; reconcile_root(&mut self.document, &value)?; let hash = self .document .commit_with(CommitOptions::default().with_message(message)) .ok_or(CrdtError::EmptyChange)?; let patch_count = self.document.diff_incremental().len(); + self.cached_snapshot = Some(stored); Ok(ChangeOutcome { heads: hashes(self.document.get_heads()), change: ChangeHash::new(hash.to_string()), @@ -149,9 +157,14 @@ impl AutomergeDocument { }) } - fn stored_snapshot(&self) -> Result { + fn stored_snapshot(&mut self) -> Result { + if let Some(snapshot) = &self.cached_snapshot { + return Ok(snapshot.clone()); + } let value = serde_json::to_value(AutoSerde::from(&self.document))?; - Ok(serde_json::from_value(value)?) + let snapshot: StoredSnapshot = serde_json::from_value(value)?; + self.cached_snapshot = Some(snapshot.clone()); + Ok(snapshot) } } @@ -229,16 +242,16 @@ impl CrdtDocument for AutomergeDocument { document_id, document, }; - insert_root(&mut automerge, &serde_json::to_value(stored)?)?; + insert_root(&mut automerge, &serde_json::to_value(&stored)?)?; automerge.commit_with(CommitOptions::default().with_message("create document")); automerge.update_diff_cursor(); - Ok(Self { document: automerge, actor_id }) + Ok(Self { document: automerge, actor_id, cached_snapshot: Some(stored) }) } fn load(bytes: &[u8], actor_id: ActorId) -> Result { let mut document = AutoCommit::load(bytes)?.with_actor(automerge_actor(&actor_id)); document.update_diff_cursor(); - let loaded = Self { document, actor_id }; + let mut loaded = Self { document, actor_id, cached_snapshot: None }; loaded.stored_snapshot()?; Ok(loaded) } @@ -248,7 +261,9 @@ impl CrdtDocument for AutomergeDocument { } fn snapshot(&mut self) -> Result { - self.document.commit(); + if self.document.commit().is_some() { + self.cached_snapshot = None; + } let stored = self.stored_snapshot()?; Ok(DocumentSnapshot { format: stored.format, @@ -287,6 +302,7 @@ impl CrdtDocument for AutomergeDocument { .map(|change| ChangeHash::new(change.hash().to_string())) .collect(); self.document.apply_changes(decoded)?; + self.cached_snapshot = None; let heads = self.heads(); Ok(MergeOutcome { heads, adopted_changes }) } @@ -370,6 +386,7 @@ impl AutomergeSyncSession { .document .sync() .receive_sync_message(&mut self.state, message)?; + document.cached_snapshot = None; let after_heads = document.document.get_heads(); let document_advanced = after_heads.iter().any(|head| !before_heads.contains(head)); Ok(!has_unavailable_head || document_advanced) diff --git a/fixtures/native/performance/README.md b/fixtures/native/performance/README.md index 3cc33ee..cf8045f 100644 --- a/fixtures/native/performance/README.md +++ b/fixtures/native/performance/README.md @@ -84,11 +84,16 @@ selected document profile are recorded as skipped. Chrome DevTools Protocol collects frame, paint, raster, compositor, long-task, GC, and heap data. Browser performance marks measure document-engine worker requests and editor projection/store updates. For a 10,000-shape selection, the -memory workload opens the board, performs sustained edits, and replaces the -active board before collecting heap measurements. +memory workload opens the board, performs 20 alternating drags, and replaces +the active board before collecting heap measurements. It waits for each +WebAssembly operation and rendered frames before starting the next drag, then +allows up to two minutes for document replacement. The summary is written to -`fixtures/native/performance/browser-budget.json`. The first measured sample +`fixtures/native/performance/browser-budget.json`. The August 2026 reference +capture completed the edit sequence in 150 seconds. JavaScript heap use was 310 +MB above the pre-load reading after editing and 286 MB above it after document +replacement; use these values to investigate retention, not as target limits. The first measured sample for each workload also writes a gzipped diagnostic trace to `fixtures/native/performance/browser-traces/`. Use `--all-profiles`, `--all-sizes`, `--samples`, `--warmups`, and `--no-traces` to control the diff --git a/fixtures/native/performance/browser-budget.json b/fixtures/native/performance/browser-budget.json index 7f78300..5c9630b 100644 --- a/fixtures/native/performance/browser-budget.json +++ b/fixtures/native/performance/browser-budget.json @@ -1,2071 +1,2204 @@ { - "schemaVersion": 1, - "capturedAt": "2026-08-23T21:45:18.668Z", - "fixture": { - "path": "fixtures/native/performance/corpus.json", - "seed": 439041101, - "profiles": [ - "flat" - ], - "sizes": [ - 1000 - ], - "viewport": { - "width": 1280, - "height": 720 - }, - "camera": { - "x": 3200, - "y": 3200, - "zoom": 1 - } - }, - "hardware": { - "platform": "darwin", - "osRelease": "25.5.0", - "cpu": "Apple M1", - "logicalCpuCount": 8, - "totalMemoryBytes": 8589934592, - "freeMemoryBytesAtCapture": 112050176 - }, - "runtime": { - "node": "v26.7.0", - "chrome": "Google Chrome 152.0.7977.54", - "playwright": "Version 1.61.1" - }, - "sampling": { - "warmups": 1, - "samples": 3, - "statistic": "median of post-warmup browser samples", - "clock": "browser performance.now() marks", - "traces": "Chrome DevTools Protocol tracing for the first measured sample" - }, - "scope": { - "browser": "Chrome channel with deviceScaleFactor 1", - "workloads": [ - "load", - "pan", - "zoom", - "box-selection", - "single-drag", - "multi-drag", - "vector-edit", - "connected-drag", - "nested-selection" - ], - "measured": [ - "load", - "pan", - "zoom", - "box selection", - "single-object drag", - "multi-object drag", - "vector editing", - "connected-shape movement", - "nested selection", - "Chrome frames, paint, raster, compositor, long tasks, GC, and memory", - "JS-to-WASM requests and editor projection/store marks" - ], - "excluded": [ - "full Playwright tracing", - "network timing after the editor is ready" - ] - }, - "measurements": [ - { - "profile": "flat", - "size": 1000, - "workload": "load", - "status": "measured", - "sampling": { - "warmups": 1, - "samples": 3 - }, - "summary": { - "count": 3, - "medianMs": 1912, - "p95Ms": 2197, - "minimumMs": 1864, - "maximumMs": 2197, - "metrics": { - "median": { - "Timestamp": 1.9112730000633746, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": -4, - "Frames": -1, - "JSEventListeners": -50, - "LayoutObjects": -437, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": -904, - "Resources": -364, - "ContextLifecycleStateObservers": -14, - "V8PerContextDatas": -2, - "WorkerGlobalScopes": 1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -2, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 2, - "LayoutCount": 10, - "RecalcStyleCount": 9, - "LayoutDuration": 0.0047459999999999725, - "RecalcStyleDuration": 0.0036220000000000002, - "DevToolsCommandDuration": 0.006097000000000005, - "ScriptDuration": 0.024207999999999993, - "V8CompileDuration": 0.000014999999999999985, - "TaskDuration": 0.2462550000000001, - "TaskOtherDuration": 0.20642899999999997, - "ThreadTime": 0.25466900000000003, - "ProcessTime": 2.1968250000000005, - "JSHeapUsedSize": 3134660, - "JSHeapTotalSize": 9715712, - "FirstMeaningfulPaint": 1189903.785901, - "DomContentLoaded": 0.18987899995408952, - "NavigationStart": 0.2066979999653995 - } - }, - "regressionBudget": { - "statistic": "p95 milliseconds", - "maximum": 2636.4, - "tolerancePercent": 20 - } - }, - "samples": [ - { - "wallClockMs": 2197, - "metrics": { - "Timestamp": 2.2340269999112934, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": -4, - "Frames": -1, - "JSEventListeners": -50, - "LayoutObjects": -437, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": -904, - "Resources": -364, - "ContextLifecycleStateObservers": -14, - "V8PerContextDatas": -2, - "WorkerGlobalScopes": 1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -2, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 2, - "LayoutCount": 10, - "RecalcStyleCount": 12, - "LayoutDuration": 0.005255999999999983, - "RecalcStyleDuration": 0.004593, - "DevToolsCommandDuration": 0.006097000000000005, - "ScriptDuration": 0.024207999999999993, - "V8CompileDuration": 0.000014999999999999985, - "TaskDuration": 0.25242300000000006, - "TaskOtherDuration": 0.212254, - "ThreadTime": 0.255451, - "ProcessTime": 2.1968250000000005, - "JSHeapUsedSize": 3134660, - "JSHeapTotalSize": 9715712, - "FirstMeaningfulPaint": 1189901.349116, - "DomContentLoaded": 0.22517400002107024, - "NavigationStart": 0.2391540000680834 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:load:1", - "startTime": 7.700000047683716, - "duration": 1882.4000000953674 - }, - "wasm": [ - { - "name": "inkfinite:wasm:create_document:1", - "startTime": 218.20000004768372, - "duration": 1592.2999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:projection:1", - "startTime": 108.60000014305115, - "duration": 3.8999998569488525 - }, - { - "name": "inkfinite:editor:projection:2", - "startTime": 1864.4000000953674, - "duration": 1.7000000476837158 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 116.5, - "duration": 103 - } - ], - "gc": [] - }, - "trace": { - "eventCount": 11182, - "frameAndPaint": { - "frames": { - "count": 490, - "eventCount": 490, - "timedEventCount": 0, - "instantEventCount": 222, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "paint": { - "count": 374, - "eventCount": 374, - "timedEventCount": 331, - "instantEventCount": 43, - "medianMs": 0.001, - "p95Ms": 0.041, - "maximumMs": 2.48, - "totalMs": 7.457000000000017 - }, - "raster": { - "count": 0, - "eventCount": 0, - "timedEventCount": 0, - "instantEventCount": 0, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "compositor": { - "count": 135, - "eventCount": 135, - "timedEventCount": 38, - "instantEventCount": 7, - "medianMs": 0.027, - "p95Ms": 0.301, - "maximumMs": 0.409, - "totalMs": 1.7889999999999997 - }, - "layout": { - "count": 37, - "eventCount": 37, - "timedEventCount": 37, - "instantEventCount": 0, - "medianMs": 0.027, - "p95Ms": 2.046, - "maximumMs": 3.264, - "totalMs": 9.661999999999995 - } - }, - "longTaskCount": 0, - "longTaskTotalMs": 0, - "gcCount": 393, - "gcTotalMs": 75.80700000000003, - "unclassifiedEventCount": 4986 - }, - "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-load-1.json.gz" - }, - { - "wallClockMs": 1864, - "metrics": { - "Timestamp": 1.8640169999562204, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 4, - "Frames": 1, - "JSEventListeners": 1199, - "LayoutObjects": 225, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 999, - "Resources": 89, - "ContextLifecycleStateObservers": 17, - "V8PerContextDatas": 2, - "WorkerGlobalScopes": 1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 6, - "AdSubframes": 0, - "DetachedScriptStates": 2, - "ArrayBufferContents": 4, - "LayoutCount": 10, - "RecalcStyleCount": 9, - "LayoutDuration": 0.004588999999999954, - "RecalcStyleDuration": 0.0033170000000000005, - "DevToolsCommandDuration": 0.005877000000000007, - "ScriptDuration": 0.023478, - "V8CompileDuration": 0.000009000000000000002, - "TaskDuration": 0.218167, - "TaskOtherDuration": 0.18089699999999997, - "ThreadTime": 0.22682000000000002, - "ProcessTime": 2.1352349999999998, - "JSHeapUsedSize": 5969244, - "JSHeapTotalSize": 11272192, - "FirstMeaningfulPaint": 1189903.785901, - "DomContentLoaded": 0.1867159998510033, - "NavigationStart": 0.2066979999653995 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:load:2", - "startTime": 5.099999904632568, - "duration": 1857.5999999046326 - }, - "wasm": [ - { - "name": "inkfinite:wasm:create_document:1", - "startTime": 198.39999985694885, - "duration": 1589.7999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:projection:1", - "startTime": 89.69999980926514, - "duration": 3.9000000953674316 - }, - { - "name": "inkfinite:editor:projection:2", - "startTime": 1841.5999999046326, - "duration": 1.5 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 94.5, - "duration": 105 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - }, - { - "wallClockMs": 1912, - "metrics": { - "Timestamp": 1.9112730000633746, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": -12, - "Frames": -3, - "JSEventListeners": -1309, - "LayoutObjects": -1099, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": -2807, - "Resources": -614, - "ContextLifecycleStateObservers": -45, - "V8PerContextDatas": -6, - "WorkerGlobalScopes": 1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -10, - "AdSubframes": 0, - "DetachedScriptStates": -2, - "ArrayBufferContents": -3, - "LayoutCount": 10, - "RecalcStyleCount": 9, - "LayoutDuration": 0.0047459999999999725, - "RecalcStyleDuration": 0.0036220000000000002, - "DevToolsCommandDuration": 0.006587999999999997, - "ScriptDuration": 0.02484900000000001, - "V8CompileDuration": 0.000021000000000000023, - "TaskDuration": 0.2462550000000001, - "TaskOtherDuration": 0.20642899999999997, - "ThreadTime": 0.25466900000000003, - "ProcessTime": 2.213591000000001, - "JSHeapUsedSize": -4041840, - "JSHeapTotalSize": -1032192, - "FirstMeaningfulPaint": 1189905.890753, - "DomContentLoaded": 0.18987899995408952, - "NavigationStart": 0.20448399987071753 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:load:3", - "startTime": 8.700000047683716, - "duration": 1900.5999999046326 - }, - "wasm": [ - { - "name": "inkfinite:wasm:create_document:1", - "startTime": 233.59999990463257, - "duration": 1603.7999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:projection:1", - "startTime": 118.39999985694885, - "duration": 3.8000001907348633 - }, - { - "name": "inkfinite:editor:projection:2", - "startTime": 1890.7999999523163, - "duration": 1.4000000953674316 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 123.39999985694885, - "duration": 111 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - } - ] - }, - { - "profile": "flat", - "size": 1000, - "workload": "pan", - "status": "measured", - "sampling": { - "warmups": 1, - "samples": 3 - }, - "summary": { - "count": 3, - "medianMs": 349.59999990463257, - "p95Ms": 350, - "minimumMs": 346.39999985694885, - "maximumMs": 350, - "metrics": { - "median": { - "Timestamp": 0.3518460001796484, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 48, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 18, - "RecalcStyleCount": 4, - "LayoutDuration": 0.0020519999999999428, - "RecalcStyleDuration": 0.00021100000000001673, - "DevToolsCommandDuration": 0.004844000000000015, - "ScriptDuration": 0.04653200000000002, - "V8CompileDuration": 0, - "TaskDuration": 0.07137499999999974, - "TaskOtherDuration": 0.015744000000000202, - "ThreadTime": 0.07152800000000026, - "ProcessTime": 0.11858299999999744, - "JSHeapUsedSize": 4590480, - "JSHeapTotalSize": 786432, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - } - }, - "regressionBudget": { - "statistic": "p95 milliseconds", - "maximum": 420, - "tolerancePercent": 20 - } - }, - "samples": [ - { - "wallClockMs": 346.39999985694885, - "metrics": { - "Timestamp": 0.49370200000703335, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 48, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 18, - "RecalcStyleCount": 4, - "LayoutDuration": 0.0022079999999999878, - "RecalcStyleDuration": 0.00019899999999999085, - "DevToolsCommandDuration": 0.004844000000000015, - "ScriptDuration": 0.04620399999999997, - "V8CompileDuration": 0, - "TaskDuration": 0.0734079999999997, - "TaskOtherDuration": 0.01995300000000011, - "ThreadTime": 0.07297200000000004, - "ProcessTime": 0.11990899999999982, - "JSHeapUsedSize": 4590480, - "JSHeapTotalSize": 524288, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-pan:4", - "startTime": 1857.4000000953674, - "duration": 346.39999985694885 - }, - "wasm": [], - "projection": [], - "longTasks": [], - "gc": [] - }, - "trace": { - "eventCount": 7357, - "frameAndPaint": { - "frames": { - "count": 105, - "eventCount": 105, - "timedEventCount": 0, - "instantEventCount": 61, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "paint": { - "count": 197, - "eventCount": 197, - "timedEventCount": 181, - "instantEventCount": 16, - "medianMs": 0.003, - "p95Ms": 0.11, - "maximumMs": 1.013, - "totalMs": 5.778999999999995 - }, - "raster": { - "count": 0, - "eventCount": 0, - "timedEventCount": 0, - "instantEventCount": 0, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "compositor": { - "count": 133, - "eventCount": 133, - "timedEventCount": 38, - "instantEventCount": 19, - "medianMs": 0.026, - "p95Ms": 0.079, - "maximumMs": 0.106, - "totalMs": 1.1630000000000003 - }, - "layout": { - "count": 29, - "eventCount": 29, - "timedEventCount": 29, - "instantEventCount": 0, - "medianMs": 0.108, - "p95Ms": 0.15, - "maximumMs": 0.153, - "totalMs": 2.3310000000000004 - } - }, - "longTaskCount": 0, - "longTaskTotalMs": 0, - "gcCount": 83, - "gcTotalMs": 31.28600000000001, - "unclassifiedEventCount": 5425 - }, - "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-pan-1.json.gz" - }, - { - "wallClockMs": 350, - "metrics": { - "Timestamp": 0.3518460001796484, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 48, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 18, - "RecalcStyleCount": 4, - "LayoutDuration": 0.0020140000000000158, - "RecalcStyleDuration": 0.00026199999999999835, - "DevToolsCommandDuration": 0.004906999999999995, - "ScriptDuration": 0.04653200000000002, - "V8CompileDuration": 0, - "TaskDuration": 0.06945900000000016, - "TaskOtherDuration": 0.015744000000000202, - "ThreadTime": 0.06933200000000017, - "ProcessTime": 0.11691100000000176, - "JSHeapUsedSize": 5608260, - "JSHeapTotalSize": 1310720, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-pan:5", - "startTime": 2021.0999999046326, - "duration": 350 - }, - "wasm": [], - "projection": [], - "longTasks": [], - "gc": [] - }, - "trace": null, - "tracePath": null - }, - { - "wallClockMs": 349.59999990463257, - "metrics": { - "Timestamp": 0.3507479999680072, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 48, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 18, - "RecalcStyleCount": 4, - "LayoutDuration": 0.0020519999999999428, - "RecalcStyleDuration": 0.00021100000000001673, - "DevToolsCommandDuration": 0.004576999999999998, - "ScriptDuration": 0.05049699999999996, - "V8CompileDuration": 0, - "TaskDuration": 0.07137499999999974, - "TaskOtherDuration": 0.014038000000000217, - "ThreadTime": 0.07152800000000026, - "ProcessTime": 0.11858299999999744, - "JSHeapUsedSize": 4421932, - "JSHeapTotalSize": 786432, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-pan:6", - "startTime": 1886.5, - "duration": 349.59999990463257 - }, - "wasm": [], - "projection": [], - "longTasks": [], - "gc": [] - }, - "trace": null, - "tracePath": null - } - ] - }, - { - "profile": "flat", - "size": 1000, - "workload": "zoom", - "status": "measured", - "sampling": { - "warmups": 1, - "samples": 3 - }, - "summary": { - "count": 3, - "medianMs": 348.59999990463257, - "p95Ms": 349.90000009536743, - "minimumMs": 347.89999985694885, - "maximumMs": 349.90000009536743, - "metrics": { - "median": { - "Timestamp": 0.3511439999565482, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 0, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 8, - "RecalcStyleCount": 0, - "LayoutDuration": 0.0011210000000000386, - "RecalcStyleDuration": 0, - "DevToolsCommandDuration": 0.0012220000000000009, - "ScriptDuration": 0.032222000000000084, - "V8CompileDuration": 0, - "TaskDuration": 0.04500800000000016, - "TaskOtherDuration": 0.009771000000000196, - "ThreadTime": 0.045428000000000246, - "ProcessTime": 0.07441499999999834, - "JSHeapUsedSize": 5182024, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - } - }, - "regressionBudget": { - "statistic": "p95 milliseconds", - "maximum": 419.8800001144409, - "tolerancePercent": 20 - } - }, - "samples": [ - { - "wallClockMs": 347.89999985694885, - "metrics": { - "Timestamp": 0.47418899997137487, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 0, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 8, - "RecalcStyleCount": 0, - "LayoutDuration": 0.0011210000000000386, - "RecalcStyleDuration": 0, - "DevToolsCommandDuration": 0.0012220000000000009, - "ScriptDuration": 0.02946000000000004, - "V8CompileDuration": 0, - "TaskDuration": 0.04567399999999999, - "TaskOtherDuration": 0.013870999999999967, - "ThreadTime": 0.046159999999999535, - "ProcessTime": 0.0764099999999992, - "JSHeapUsedSize": 5189436, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-zoom:7", - "startTime": 1864.4000000953674, - "duration": 347.89999985694885 - }, - "wasm": [], - "projection": [], - "longTasks": [], - "gc": [] - }, - "trace": { - "eventCount": 4573, - "frameAndPaint": { - "frames": { - "count": 100, - "eventCount": 100, - "timedEventCount": 0, - "instantEventCount": 52, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "paint": { - "count": 186, - "eventCount": 186, - "timedEventCount": 169, - "instantEventCount": 17, - "medianMs": 0.003, - "p95Ms": 0.106, - "maximumMs": 1.073, - "totalMs": 4.345999999999988 - }, - "raster": { - "count": 0, - "eventCount": 0, - "timedEventCount": 0, - "instantEventCount": 0, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "compositor": { - "count": 80, - "eventCount": 80, - "timedEventCount": 24, - "instantEventCount": 10, - "medianMs": 0.03, - "p95Ms": 0.053, - "maximumMs": 0.082, - "totalMs": 0.7650000000000003 - }, - "layout": { - "count": 15, - "eventCount": 15, - "timedEventCount": 15, - "instantEventCount": 0, - "medianMs": 0.11, - "p95Ms": 0.155, - "maximumMs": 0.155, - "totalMs": 1.117 - } - }, - "longTaskCount": 0, - "longTaskTotalMs": 0, - "gcCount": 45, - "gcTotalMs": 17.21999999999999, - "unclassifiedEventCount": 3108 - }, - "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-zoom-1.json.gz" - }, - { - "wallClockMs": 349.90000009536743, - "metrics": { - "Timestamp": 0.3511439999565482, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 0, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 8, - "RecalcStyleCount": 0, - "LayoutDuration": 0.0011019999999999364, - "RecalcStyleDuration": 0, - "DevToolsCommandDuration": 0.0012309999999999821, - "ScriptDuration": 0.032222000000000084, - "V8CompileDuration": 0, - "TaskDuration": 0.044325999999999866, - "TaskOtherDuration": 0.009771000000000196, - "ThreadTime": 0.04459700000000044, - "ProcessTime": 0.07353999999999772, - "JSHeapUsedSize": 5182024, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-zoom:8", - "startTime": 1896.2000000476837, - "duration": 349.90000009536743 - }, - "wasm": [], - "projection": [], - "longTasks": [], - "gc": [] - }, - "trace": null, - "tracePath": null - }, - { - "wallClockMs": 348.59999990463257, - "metrics": { - "Timestamp": 0.3499759999103844, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 0, - "LayoutObjects": 0, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 0, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 8, - "RecalcStyleCount": 0, - "LayoutDuration": 0.0011219999999999564, - "RecalcStyleDuration": 0, - "DevToolsCommandDuration": 0.0011749999999999816, - "ScriptDuration": 0.03322400000000003, - "V8CompileDuration": 0, - "TaskDuration": 0.04500800000000016, - "TaskOtherDuration": 0.009487000000000023, - "ThreadTime": 0.045428000000000246, - "ProcessTime": 0.07441499999999834, - "JSHeapUsedSize": 5136488, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-zoom:9", - "startTime": 1887.4000000953674, - "duration": 348.59999990463257 - }, - "wasm": [], - "projection": [], - "longTasks": [], - "gc": [] - }, - "trace": null, - "tracePath": null - } - ] - }, - { - "profile": "flat", - "size": 1000, - "workload": "box-selection", - "status": "measured", - "sampling": { - "warmups": 1, - "samples": 3 - }, - "summary": { - "count": 3, - "medianMs": 432.7000000476837, - "p95Ms": 433.90000009536743, - "minimumMs": 430.7000000476837, - "maximumMs": 433.90000009536743, - "metrics": { - "median": { - "Timestamp": 0.43486299994401634, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 89, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 371, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 23, - "RecalcStyleCount": 26, - "LayoutDuration": 0.004434999999999967, - "RecalcStyleDuration": 0.002942, - "DevToolsCommandDuration": 0.005765999999999993, - "ScriptDuration": 0.04557800000000001, - "V8CompileDuration": 0, - "TaskDuration": 0.11900399999999944, - "TaskOtherDuration": 0.059345000000000425, - "ThreadTime": 0.1191639999999996, - "ProcessTime": 0.269436000000006, - "JSHeapUsedSize": 18566788, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - } - }, - "regressionBudget": { - "statistic": "p95 milliseconds", - "maximum": 520.6800001144409, - "tolerancePercent": 20 - } - }, - "samples": [ - { - "wallClockMs": 430.7000000476837, - "metrics": { - "Timestamp": 0.5876879999414086, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 89, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 371, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 23, - "RecalcStyleCount": 26, - "LayoutDuration": 0.004477999999999982, - "RecalcStyleDuration": 0.002942, - "DevToolsCommandDuration": 0.005657000000000023, - "ScriptDuration": 0.044857000000000036, - "V8CompileDuration": 0, - "TaskDuration": 0.11900399999999944, - "TaskOtherDuration": 0.06106999999999996, - "ThreadTime": 0.1191639999999996, - "ProcessTime": 0.4149940000000001, - "JSHeapUsedSize": 18566788, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-box-selection:10", - "startTime": 1878.5999999046326, - "duration": 430.7000000476837 - }, - "wasm": [], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 2199.2999999523163, - "duration": 22 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 2194.7000000476837, - "duration": 69 - } - ], - "gc": [] - }, - "trace": { - "eventCount": 8700, - "frameAndPaint": { - "frames": { - "count": 129, - "eventCount": 129, - "timedEventCount": 0, - "instantEventCount": 69, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "paint": { - "count": 379, - "eventCount": 379, - "timedEventCount": 364, - "instantEventCount": 15, - "medianMs": 0.007, - "p95Ms": 0.133, - "maximumMs": 1.282, - "totalMs": 12.716999999999981 - }, - "raster": { - "count": 0, - "eventCount": 0, - "timedEventCount": 0, - "instantEventCount": 0, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "compositor": { - "count": 145, - "eventCount": 145, - "timedEventCount": 42, - "instantEventCount": 19, - "medianMs": 0.037, - "p95Ms": 0.073, - "maximumMs": 0.102, - "totalMs": 1.6520000000000004 - }, - "layout": { - "count": 59, - "eventCount": 59, - "timedEventCount": 59, - "instantEventCount": 0, - "medianMs": 0.085, - "p95Ms": 0.161, - "maximumMs": 1.805, - "totalMs": 7.356 - } - }, - "longTaskCount": 0, - "longTaskTotalMs": 0, - "gcCount": 125, - "gcTotalMs": 38.550000000000004, - "unclassifiedEventCount": 6265 - }, - "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-box-selection-1.json.gz" - }, - { - "wallClockMs": 433.90000009536743, - "metrics": { - "Timestamp": 0.43486299994401634, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 89, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 371, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": -1, - "LayoutCount": 23, - "RecalcStyleCount": 26, - "LayoutDuration": 0.004302000000000028, - "RecalcStyleDuration": 0.002912999999999999, - "DevToolsCommandDuration": 0.005765999999999993, - "ScriptDuration": 0.04557800000000001, - "V8CompileDuration": 0, - "TaskDuration": 0.11052399999999984, - "TaskOtherDuration": 0.05196500000000004, - "ThreadTime": 0.11090899999999948, - "ProcessTime": 0.24233300000000213, - "JSHeapUsedSize": 18571112, - "JSHeapTotalSize": 262144, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-box-selection:11", - "startTime": 1887.9000000953674, - "duration": 433.90000009536743 - }, - "wasm": [], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 2211.5, - "duration": 22.700000047683716 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 2206.7000000476837, - "duration": 70 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - }, - { - "wallClockMs": 432.7000000476837, - "metrics": { - "Timestamp": 0.43343400000594556, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": -1046, - "LayoutObjects": 88, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 341, - "Resources": -10, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": -4, - "ArrayBufferContents": -3, - "LayoutCount": 23, - "RecalcStyleCount": 26, - "LayoutDuration": 0.004434999999999967, - "RecalcStyleDuration": 0.0030050000000000354, - "DevToolsCommandDuration": 0.00592400000000004, - "ScriptDuration": 0.04718200000000006, - "V8CompileDuration": 0, - "TaskDuration": 0.11989099999999997, - "TaskOtherDuration": 0.059345000000000425, - "ThreadTime": 0.12008799999999997, - "ProcessTime": 0.269436000000006, - "JSHeapUsedSize": -10327900, - "JSHeapTotalSize": -1048576, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-box-selection:12", - "startTime": 1875.2999999523163, - "duration": 432.7000000476837 - }, - "wasm": [], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 2198.0999999046326, - "duration": 23.200000047683716 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 2192.7999999523163, - "duration": 72 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - } - ] - }, - { - "profile": "flat", - "size": 1000, - "workload": "single-drag", - "status": "measured", - "sampling": { - "warmups": 1, - "samples": 3 - }, - "summary": { - "count": 3, - "medianMs": 494.80000019073486, - "p95Ms": 498.5, - "minimumMs": 488, - "maximumMs": 498.5, - "metrics": { - "median": { - "Timestamp": 0.4959269999526441, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 72, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 312, - "Resources": -6, - "ContextLifecycleStateObservers": -1, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": -1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -2, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 0, - "LayoutCount": 22, - "RecalcStyleCount": 11, - "LayoutDuration": 0.003054999999999919, - "RecalcStyleDuration": 0.0012360000000000149, - "DevToolsCommandDuration": 0.00550700000000004, - "ScriptDuration": 0.08662499999999995, - "V8CompileDuration": 0, - "TaskDuration": 0.1880740000000003, - "TaskOtherDuration": 0.08881200000000078, - "ThreadTime": 0.18690400000000018, - "ProcessTime": 0.7619319999999945, - "JSHeapUsedSize": 10091788, - "JSHeapTotalSize": 1048576, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - } - }, - "regressionBudget": { - "statistic": "p95 milliseconds", - "maximum": 598.1999999999999, - "tolerancePercent": 20 - } - }, - "samples": [ - { - "wallClockMs": 498.5, - "metrics": { - "Timestamp": 0.6642720000818372, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 72, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 312, - "Resources": -6, - "ContextLifecycleStateObservers": -1, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": -1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -2, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 0, - "LayoutCount": 22, - "RecalcStyleCount": 11, - "LayoutDuration": 0.0033840000000000536, - "RecalcStyleDuration": 0.0012560000000000349, - "DevToolsCommandDuration": 0.00550700000000004, - "ScriptDuration": 0.08911499999999983, - "V8CompileDuration": 0, - "TaskDuration": 0.1880740000000003, - "TaskOtherDuration": 0.08881200000000078, - "ThreadTime": 0.18690400000000018, - "ProcessTime": 0.9076310000000021, - "JSHeapUsedSize": 27352596, - "JSHeapTotalSize": 1835008, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-single-drag:13", - "startTime": 1798.7999999523163, - "duration": 498.5 - }, - "wasm": [ - { - "name": "inkfinite:wasm:document_state:2", - "startTime": 1861.2000000476837, - "duration": 428.2999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 1847.7999999523163, - "duration": 12.900000095367432 - }, - { - "name": "inkfinite:editor:store-commit:4", - "startTime": 2168.2999999523163, - "duration": 12.5 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 1840.5, - "duration": 54 - } - ], - "gc": [] - }, - "trace": { - "eventCount": 10212, - "frameAndPaint": { - "frames": { - "count": 180, - "eventCount": 180, - "timedEventCount": 0, - "instantEventCount": 76, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "paint": { - "count": 242, - "eventCount": 242, - "timedEventCount": 221, - "instantEventCount": 21, - "medianMs": 0.003, - "p95Ms": 0.101, - "maximumMs": 1.11, - "totalMs": 6.9329999999999865 - }, - "raster": { - "count": 0, - "eventCount": 0, - "timedEventCount": 0, - "instantEventCount": 0, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "compositor": { - "count": 188, - "eventCount": 188, - "timedEventCount": 44, - "instantEventCount": 20, - "medianMs": 0.025, - "p95Ms": 0.051, - "maximumMs": 0.105, - "totalMs": 1.256 - }, - "layout": { - "count": 42, - "eventCount": 42, - "timedEventCount": 42, - "instantEventCount": 0, - "medianMs": 0.095, - "p95Ms": 0.154, - "maximumMs": 1.302, - "totalMs": 4.578 - } - }, - "longTaskCount": 0, - "longTaskTotalMs": 0, - "gcCount": 317, - "gcTotalMs": 83.04700000000008, - "unclassifiedEventCount": 6906 - }, - "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-single-drag-1.json.gz" - }, - { - "wallClockMs": 494.80000019073486, - "metrics": { - "Timestamp": 0.4959269999526441, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": -10, - "Frames": -2, - "JSEventListeners": -2361, - "LayoutObjects": -662, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": -3094, - "Resources": -543, - "ContextLifecycleStateObservers": -45, - "V8PerContextDatas": -4, - "WorkerGlobalScopes": -1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -12, - "AdSubframes": 0, - "DetachedScriptStates": -6, - "ArrayBufferContents": -6, - "LayoutCount": 22, - "RecalcStyleCount": 11, - "LayoutDuration": 0.003054999999999919, - "RecalcStyleDuration": 0.0012360000000000149, - "DevToolsCommandDuration": 0.005607999999999946, - "ScriptDuration": 0.08554700000000004, - "V8CompileDuration": 0, - "TaskDuration": 0.1957500000000003, - "TaskOtherDuration": 0.1003039999999995, - "ThreadTime": 0.19467200000000062, - "ProcessTime": 0.7619319999999945, - "JSHeapUsedSize": -25200052, - "JSHeapTotalSize": 1048576, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-single-drag:14", - "startTime": 1816.7999999523163, - "duration": 494.80000019073486 - }, - "wasm": [ - { - "name": "inkfinite:wasm:document_state:2", - "startTime": 1872, - "duration": 430.7999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 1860.2999999523163, - "duration": 11.300000190734863 - }, - { - "name": "inkfinite:editor:store-commit:4", - "startTime": 2182.2000000476837, - "duration": 10.599999904632568 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 1853.2000000476837, - "duration": 51 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - }, - { - "wallClockMs": 488, - "metrics": { - "Timestamp": 0.4886819999665022, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 72, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 312, - "Resources": -6, - "ContextLifecycleStateObservers": -1, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": -1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -2, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 1, - "LayoutCount": 22, - "RecalcStyleCount": 11, - "LayoutDuration": 0.0029839999999999867, - "RecalcStyleDuration": 0.0011849999999999916, - "DevToolsCommandDuration": 0.005263000000000018, - "ScriptDuration": 0.08662499999999995, - "V8CompileDuration": 0, - "TaskDuration": 0.17598699999999923, - "TaskOtherDuration": 0.07993000000000006, - "ThreadTime": 0.17528200000000105, - "ProcessTime": 0.7302389999999974, - "JSHeapUsedSize": 10091788, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-single-drag:15", - "startTime": 1796.2999999523163, - "duration": 488 - }, - "wasm": [ - { - "name": "inkfinite:wasm:document_state:2", - "startTime": 1856.2999999523163, - "duration": 425.7999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 1842.7999999523163, - "duration": 13.099999904632568 - }, - { - "name": "inkfinite:editor:store-commit:4", - "startTime": 2166.7999999523163, - "duration": 10.599999904632568 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 1836.1999998092651, - "duration": 51 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - } - ] - }, - { - "profile": "flat", - "size": 1000, - "workload": "multi-drag", - "status": "measured", - "sampling": { - "warmups": 1, - "samples": 3 - }, - "summary": { - "count": 3, - "medianMs": 549.7999999523163, - "p95Ms": 550.2000000476837, - "minimumMs": 547.8000001907349, - "maximumMs": 550.2000000476837, - "metrics": { - "median": { - "Timestamp": 0.5506150000728667, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 88, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 365, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 0, - "LayoutCount": 25, - "RecalcStyleCount": 14, - "LayoutDuration": 0.003631000000000162, - "RecalcStyleDuration": 0.0018129999999999535, - "DevToolsCommandDuration": 0.005794000000000077, - "ScriptDuration": 0.10488300000000006, - "V8CompileDuration": 0, - "TaskDuration": 0.2399199999999997, - "TaskOtherDuration": 0.1208670000000005, - "ThreadTime": 0.2363710000000001, - "ProcessTime": 0.8291139999999899, - "JSHeapUsedSize": 30430124, - "JSHeapTotalSize": 262144, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - } - }, - "regressionBudget": { - "statistic": "p95 milliseconds", - "maximum": 660.2400000572204, - "tolerancePercent": 20 - } - }, - "samples": [ - { - "wallClockMs": 550.2000000476837, - "metrics": { - "Timestamp": 0.7338600000366569, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": -10, - "Frames": -2, - "JSEventListeners": -2361, - "LayoutObjects": -662, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": -3098, - "Resources": -543, - "ContextLifecycleStateObservers": -45, - "V8PerContextDatas": -4, - "WorkerGlobalScopes": -1, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": -12, - "AdSubframes": 0, - "DetachedScriptStates": -6, - "ArrayBufferContents": -7, - "LayoutCount": 25, - "RecalcStyleCount": 14, - "LayoutDuration": 0.003631000000000162, - "RecalcStyleDuration": 0.0017940000000000178, - "DevToolsCommandDuration": 0.005543000000000076, - "ScriptDuration": 0.09677200000000008, - "V8CompileDuration": 0, - "TaskDuration": 0.2480639999999994, - "TaskOtherDuration": 0.14032399999999967, - "ThreadTime": 0.2470219999999994, - "ProcessTime": 1.08587, - "JSHeapUsedSize": -30702672, - "JSHeapTotalSize": 4194304, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-multi-drag:16", - "startTime": 1801.7999999523163, - "duration": 550.2000000476837 - }, - "wasm": [ - { - "name": "inkfinite:wasm:document_state:2", - "startTime": 1859.7999999523163, - "duration": 430.90000009536743 - } - ], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 1848.7000000476837, - "duration": 10.700000047683716 - }, - { - "name": "inkfinite:editor:store-commit:4", - "startTime": 1905.2000000476837, - "duration": 10.599999904632568 - }, - { - "name": "inkfinite:editor:store-commit:5", - "startTime": 2236, - "duration": 10.700000047683716 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 1839.7999999523163, - "duration": 52 - } - ], - "gc": [] - }, - "trace": { - "eventCount": 11794, - "frameAndPaint": { - "frames": { - "count": 162, - "eventCount": 162, - "timedEventCount": 0, - "instantEventCount": 82, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "paint": { - "count": 288, - "eventCount": 288, - "timedEventCount": 259, - "instantEventCount": 29, - "medianMs": 0.004, - "p95Ms": 0.103, - "maximumMs": 1.144, - "totalMs": 8.383999999999999 - }, - "raster": { - "count": 0, - "eventCount": 0, - "timedEventCount": 0, - "instantEventCount": 0, - "medianMs": null, - "p95Ms": null, - "maximumMs": null, - "totalMs": 0 - }, - "compositor": { - "count": 172, - "eventCount": 172, - "timedEventCount": 48, - "instantEventCount": 22, - "medianMs": 0.025, - "p95Ms": 0.063, - "maximumMs": 0.113, - "totalMs": 1.405 - }, - "layout": { - "count": 49, - "eventCount": 49, - "timedEventCount": 49, - "instantEventCount": 0, - "medianMs": 0.088, - "p95Ms": 0.353, - "maximumMs": 1.153, - "totalMs": 5.365000000000001 - } - }, - "longTaskCount": 0, - "longTaskTotalMs": 0, - "gcCount": 628, - "gcTotalMs": 131.4750000000003, - "unclassifiedEventCount": 7958 - }, - "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-multi-drag-1.json.gz" - }, - { - "wallClockMs": 547.8000001907349, - "metrics": { - "Timestamp": 0.5491530001163483, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 88, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 365, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 1, - "LayoutCount": 25, - "RecalcStyleCount": 14, - "LayoutDuration": 0.0038759999999999906, - "RecalcStyleDuration": 0.0024769999999999515, - "DevToolsCommandDuration": 0.007817000000000074, - "ScriptDuration": 0.10488300000000006, - "V8CompileDuration": 0, - "TaskDuration": 0.2399199999999997, - "TaskOtherDuration": 0.1208670000000005, - "ThreadTime": 0.2363710000000001, - "ProcessTime": 0.8291139999999899, - "JSHeapUsedSize": 30430124, - "JSHeapTotalSize": 0, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-multi-drag:17", - "startTime": 1999, - "duration": 547.8000001907349 - }, - "wasm": [ - { - "name": "inkfinite:wasm:document_state:2", - "startTime": 2060.300000190735, - "duration": 428.7999999523163 - } - ], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 2047.2000000476837, - "duration": 12.700000047683716 - }, - { - "name": "inkfinite:editor:store-commit:4", - "startTime": 2110.600000143051, - "duration": 10.899999856948853 - }, - { - "name": "inkfinite:editor:store-commit:5", - "startTime": 2431.4000000953674, - "duration": 10.900000095367432 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 2037.6000001430511, - "duration": 60 - }, - { - "name": "self", - "startTime": 2102.100000143051, - "duration": 50 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - }, - { - "wallClockMs": 549.7999999523163, - "metrics": { - "Timestamp": 0.5506150000728667, - "AudioHandlers": 0, - "AudioWorkletProcessors": 0, - "Documents": 0, - "Frames": 0, - "JSEventListeners": 49, - "LayoutObjects": 88, - "MediaKeySessions": 0, - "MediaKeys": 0, - "Nodes": 365, - "Resources": 0, - "ContextLifecycleStateObservers": 0, - "V8PerContextDatas": 0, - "WorkerGlobalScopes": 0, - "UACSSResources": 0, - "RTCPeerConnections": 0, - "ResourceFetchers": 0, - "AdSubframes": 0, - "DetachedScriptStates": 0, - "ArrayBufferContents": 0, - "LayoutCount": 25, - "RecalcStyleCount": 14, - "LayoutDuration": 0.0036129999999998663, - "RecalcStyleDuration": 0.0018129999999999535, - "DevToolsCommandDuration": 0.005794000000000077, - "ScriptDuration": 0.10535799999999984, - "V8CompileDuration": 0, - "TaskDuration": 0.23163499999999893, - "TaskOtherDuration": 0.1150569999999993, - "ThreadTime": 0.23059999999999903, - "ProcessTime": 0.8185580000000101, - "JSHeapUsedSize": 30743396, - "JSHeapTotalSize": 262144, - "FirstMeaningfulPaint": 0, - "DomContentLoaded": 0, - "NavigationStart": 0 - }, - "performance": { - "benchmark": { - "name": "inkfinite:benchmark:flat-1000-multi-drag:18", - "startTime": 1829.0999999046326, - "duration": 549.7999999523163 - }, - "wasm": [ - { - "name": "inkfinite:wasm:document_state:2", - "startTime": 1890.7999999523163, - "duration": 429.2000000476837 - } - ], - "projection": [ - { - "name": "inkfinite:editor:store-commit:3", - "startTime": 1876.5, - "duration": 13.899999856948853 - }, - { - "name": "inkfinite:editor:store-commit:4", - "startTime": 1933.2000000476837, - "duration": 11.799999952316284 - }, - { - "name": "inkfinite:editor:store-commit:5", - "startTime": 2265.0999999046326, - "duration": 12.5 - } - ], - "longTasks": [ - { - "name": "self", - "startTime": 1868.3999998569489, - "duration": 54 - } - ], - "gc": [] - }, - "trace": null, - "tracePath": null - } - ] - }, - { - "profile": "flat", - "size": 1000, - "workload": "vector-edit", - "status": "skipped", - "reason": "Requires the native path profile." - }, - { - "profile": "flat", - "size": 1000, - "workload": "connected-drag", - "status": "skipped", - "reason": "Requires the connection-heavy profile." - }, - { - "profile": "flat", - "size": 1000, - "workload": "nested-selection", - "status": "skipped", - "reason": "Requires the deeply-nested profile." - } - ], - "memory": [] + "schemaVersion": 1, + "capturedAt": "2026-08-24T01:20:47.949Z", + "fixture": { + "path": "fixtures/native/performance/corpus.json", + "seed": 439041101, + "profiles": [ + "flat" + ], + "sizes": [ + 1000 + ], + "viewport": { + "width": 1280, + "height": 720 + }, + "camera": { + "x": 3200, + "y": 3200, + "zoom": 1 + } + }, + "hardware": { + "platform": "darwin", + "osRelease": "25.5.0", + "cpu": "Apple M1", + "logicalCpuCount": 8, + "totalMemoryBytes": 8589934592, + "freeMemoryBytesAtCapture": 71680000 + }, + "runtime": { + "node": "v26.7.0", + "chrome": "Google Chrome 152.0.7977.54", + "playwright": "Version 1.61.1" + }, + "sampling": { + "warmups": 1, + "samples": 3, + "statistic": "median of post-warmup browser samples", + "clock": "browser performance.now() marks", + "traces": "Chrome DevTools Protocol tracing for the first measured sample" + }, + "scope": { + "browser": "Chrome channel with deviceScaleFactor 1", + "workloads": [ + "load", + "pan", + "zoom", + "box-selection", + "single-drag", + "multi-drag", + "vector-edit", + "connected-drag", + "nested-selection" + ], + "measured": [ + "load", + "pan", + "zoom", + "box selection", + "single-object drag", + "multi-object drag", + "vector editing", + "connected-shape movement", + "nested selection", + "Chrome frames, paint, raster, compositor, long tasks, GC, and memory", + "JS-to-WASM requests and editor projection/store marks" + ], + "excluded": [ + "full Playwright tracing", + "network timing after the editor is ready" + ] + }, + "measurements": [ + { + "profile": "flat", + "size": 1000, + "workload": "load", + "status": "measured", + "sampling": { + "warmups": 1, + "samples": 3 + }, + "summary": { + "count": 3, + "medianMs": 1491, + "p95Ms": 1846, + "regressionBudget": { + "statistic": "p95 milliseconds", + "maximum": 2215.2, + "tolerancePercent": 20 + }, + "minimumMs": 1484, + "maximumMs": 1846, + "metrics": { + "median": { + "Timestamp": 1.4903460000641644, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": -4, + "Frames": -1, + "JSEventListeners": -55, + "LayoutObjects": -437, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": -904, + "Resources": -369, + "ContextLifecycleStateObservers": -14, + "V8PerContextDatas": -2, + "WorkerGlobalScopes": 1, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": -2, + "AdSubframes": 0, + "DetachedScriptStates": -2, + "ArrayBufferContents": 1, + "LayoutCount": 10, + "RecalcStyleCount": 10, + "LayoutDuration": 0.0048829999999999985, + "RecalcStyleDuration": 0.003577999999999998, + "DevToolsCommandDuration": 0.006084999999999993, + "ScriptDuration": 0.026494000000000004, + "V8CompileDuration": 0.000010999999999999996, + "TaskDuration": 0.24100200000000016, + "TaskOtherDuration": 0.199739, + "ThreadTime": 0.24856100000000003, + "ProcessTime": 1.7623759999999997, + "JSHeapUsedSize": 4432404, + "JSHeapTotalSize": 7094272, + "FirstMeaningfulPaint": 1199207.533451, + "DomContentLoaded": 0.21978499996475875, + "NavigationStart": 0.233183000003919 + } + } + }, + "samples": [ + { + "wallClockMs": 1846, + "metrics": { + "Timestamp": 1.8859129999764264, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": -39, + "Frames": -3, + "JSEventListeners": -1186, + "LayoutObjects": -925, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": -1976, + "Resources": -521, + "ContextLifecycleStateObservers": -65, + "V8PerContextDatas": -6, + "WorkerGlobalScopes": 1, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": -37, + "AdSubframes": 0, + "DetachedScriptStates": -6, + "ArrayBufferContents": -3, + "LayoutCount": 10, + "RecalcStyleCount": 12, + "LayoutDuration": 0.004785999999999999, + "RecalcStyleDuration": 0.004247000000000001, + "DevToolsCommandDuration": 0.006045999999999996, + "ScriptDuration": 0.025009000000000003, + "V8CompileDuration": 0.00001299999999999999, + "TaskDuration": 0.25831100000000007, + "TaskOtherDuration": 0.21821000000000007, + "ThreadTime": 0.261814, + "ProcessTime": 1.822947, + "JSHeapUsedSize": -7587660, + "JSHeapTotalSize": 540672, + "FirstMeaningfulPaint": 1199205.410269, + "DomContentLoaded": 0.23995300009846687, + "NavigationStart": 0.2523340000770986 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:load:1", + "startTime": 12.699999809265137, + "duration": 1548.6000001430511 + }, + "wasm": [ + { + "name": "inkfinite:wasm:create_document:1", + "startTime": 217, + "duration": 1267 + } + ], + "projection": [ + { + "name": "inkfinite:editor:projection:1", + "startTime": 106, + "duration": 3.6999998092651367 + }, + { + "name": "inkfinite:editor:projection:2", + "startTime": 1537.8999998569489, + "duration": 2.700000047683716 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 113.59999990463257, + "duration": 104 + } + ], + "gc": [] + }, + "trace": { + "eventCount": 11009, + "frameAndPaint": { + "frames": { + "count": 397, + "eventCount": 397, + "timedEventCount": 0, + "instantEventCount": 183, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "paint": { + "count": 352, + "eventCount": 352, + "timedEventCount": 321, + "instantEventCount": 31, + "medianMs": 0.002, + "p95Ms": 0.037, + "maximumMs": 2.502, + "totalMs": 7.33900000000001 + }, + "raster": { + "count": 0, + "eventCount": 0, + "timedEventCount": 0, + "instantEventCount": 0, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "compositor": { + "count": 111, + "eventCount": 111, + "timedEventCount": 30, + "instantEventCount": 7, + "medianMs": 0.038, + "p95Ms": 0.254, + "maximumMs": 0.77, + "totalMs": 1.9929999999999994 + }, + "layout": { + "count": 36, + "eventCount": 36, + "timedEventCount": 36, + "instantEventCount": 0, + "medianMs": 0.027, + "p95Ms": 2.076, + "maximumMs": 2.912, + "totalMs": 8.715999999999998 + } + }, + "longTaskCount": 0, + "longTaskTotalMs": 0, + "gcCount": 650, + "gcTotalMs": 101.66000000000021, + "unclassifiedEventCount": 5121 + }, + "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-load-1.json.gz" + }, + { + "wallClockMs": 1484, + "metrics": { + "Timestamp": 1.483792999992147, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": -4, + "Frames": -1, + "JSEventListeners": 986, + "LayoutObjects": -437, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": -904, + "Resources": -359, + "ContextLifecycleStateObservers": -14, + "V8PerContextDatas": -2, + "WorkerGlobalScopes": 1, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": -2, + "AdSubframes": 0, + "DetachedScriptStates": 2, + "ArrayBufferContents": 2, + "LayoutCount": 10, + "RecalcStyleCount": 9, + "LayoutDuration": 0.004905999999999994, + "RecalcStyleDuration": 0.0034029999999999963, + "DevToolsCommandDuration": 0.006094999999999989, + "ScriptDuration": 0.028957999999999998, + "V8CompileDuration": 0.000010999999999999996, + "TaskDuration": 0.24100200000000016, + "TaskOtherDuration": 0.19762900000000005, + "ThreadTime": 0.24856100000000003, + "ProcessTime": 1.7548659999999998, + "JSHeapUsedSize": 4432404, + "JSHeapTotalSize": 7094272, + "FirstMeaningfulPaint": 1199207.533451, + "DomContentLoaded": 0.21978499996475875, + "NavigationStart": 0.233183000003919 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:load:2", + "startTime": 7, + "duration": 1475 + }, + "wasm": [ + { + "name": "inkfinite:wasm:create_document:1", + "startTime": 210.89999985694885, + "duration": 1210.1000001430511 + } + ], + "projection": [ + { + "name": "inkfinite:editor:projection:1", + "startTime": 96.89999985694885, + "duration": 4.1000001430511475 + }, + { + "name": "inkfinite:editor:projection:2", + "startTime": 1474.7000000476837, + "duration": 1.5 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 104.29999995231628, + "duration": 108 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + }, + { + "wallClockMs": 1491, + "metrics": { + "Timestamp": 1.4903460000641644, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": -4, + "Frames": -1, + "JSEventListeners": -55, + "LayoutObjects": -437, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": -904, + "Resources": -369, + "ContextLifecycleStateObservers": -14, + "V8PerContextDatas": -2, + "WorkerGlobalScopes": 1, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": -2, + "AdSubframes": 0, + "DetachedScriptStates": -2, + "ArrayBufferContents": 1, + "LayoutCount": 10, + "RecalcStyleCount": 10, + "LayoutDuration": 0.0048829999999999985, + "RecalcStyleDuration": 0.003577999999999998, + "DevToolsCommandDuration": 0.006084999999999993, + "ScriptDuration": 0.026494000000000004, + "V8CompileDuration": 0.000009000000000000029, + "TaskDuration": 0.240788, + "TaskOtherDuration": 0.199739, + "ThreadTime": 0.246494, + "ProcessTime": 1.7623759999999997, + "JSHeapUsedSize": 7167468, + "JSHeapTotalSize": 11534336, + "FirstMeaningfulPaint": 1199209.204696, + "DomContentLoaded": 0.17299799993634224, + "NavigationStart": 0.19221500004641712 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:load:3", + "startTime": 6.200000047683716, + "duration": 1482.2999999523163 + }, + "wasm": [ + { + "name": "inkfinite:wasm:create_document:1", + "startTime": 206.20000004768372, + "duration": 1214.7000000476837 + } + ], + "projection": [ + { + "name": "inkfinite:editor:projection:1", + "startTime": 97.59999990463257, + "duration": 3.9000000953674316 + }, + { + "name": "inkfinite:editor:projection:2", + "startTime": 1475.4000000953674, + "duration": 1.3999998569488525 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 102.59999990463257, + "duration": 105 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + } + ] + }, + { + "profile": "flat", + "size": 1000, + "workload": "pan", + "status": "measured", + "sampling": { + "warmups": 1, + "samples": 3 + }, + "summary": { + "count": 3, + "medianMs": 348, + "p95Ms": 348.39999985694885, + "regressionBudget": { + "statistic": "p95 milliseconds", + "maximum": 418.0799998283386, + "tolerancePercent": 20 + }, + "minimumMs": 345.19999980926514, + "maximumMs": 348.39999985694885, + "metrics": { + "median": { + "Timestamp": 0.35040999995544553, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 48, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 18, + "RecalcStyleCount": 4, + "LayoutDuration": 0.002151000000000014, + "RecalcStyleDuration": 0.00023400000000001198, + "DevToolsCommandDuration": 0.0049859999999999904, + "ScriptDuration": 0.04433900000000002, + "V8CompileDuration": 0, + "TaskDuration": 0.06731100000000012, + "TaskOtherDuration": 0.016602999999999923, + "ThreadTime": 0.06682600000000027, + "ProcessTime": 0.11427699999999952, + "JSHeapUsedSize": 4583384, + "JSHeapTotalSize": 1310720, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + } + } + }, + "samples": [ + { + "wallClockMs": 345.19999980926514, + "metrics": { + "Timestamp": 0.49402600014582276, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 48, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 18, + "RecalcStyleCount": 4, + "LayoutDuration": 0.002151000000000014, + "RecalcStyleDuration": 0.00021399999999999197, + "DevToolsCommandDuration": 0.005763999999999991, + "ScriptDuration": 0.04874400000000001, + "V8CompileDuration": 0, + "TaskDuration": 0.08063299999999973, + "TaskOtherDuration": 0.023760000000000003, + "ThreadTime": 0.08041000000000009, + "ProcessTime": 0.13658200000000065, + "JSHeapUsedSize": 4583384, + "JSHeapTotalSize": 786432, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-pan:4", + "startTime": 1565.3000001907349, + "duration": 345.19999980926514 + }, + "wasm": [], + "projection": [], + "longTasks": [], + "gc": [] + }, + "trace": { + "eventCount": 7143, + "frameAndPaint": { + "frames": { + "count": 106, + "eventCount": 106, + "timedEventCount": 0, + "instantEventCount": 60, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "paint": { + "count": 195, + "eventCount": 195, + "timedEventCount": 176, + "instantEventCount": 19, + "medianMs": 0.006, + "p95Ms": 0.115, + "maximumMs": 1.42, + "totalMs": 6.349999999999992 + }, + "raster": { + "count": 0, + "eventCount": 0, + "timedEventCount": 0, + "instantEventCount": 0, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "compositor": { + "count": 136, + "eventCount": 136, + "timedEventCount": 40, + "instantEventCount": 18, + "medianMs": 0.027, + "p95Ms": 0.056, + "maximumMs": 0.13, + "totalMs": 1.3319999999999996 + }, + "layout": { + "count": 29, + "eventCount": 29, + "timedEventCount": 29, + "instantEventCount": 0, + "medianMs": 0.101, + "p95Ms": 0.132, + "maximumMs": 0.144, + "totalMs": 2.3020000000000005 + } + }, + "longTaskCount": 0, + "longTaskTotalMs": 0, + "gcCount": 84, + "gcTotalMs": 42.059999999999995, + "unclassifiedEventCount": 5280 + }, + "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-pan-1.json.gz" + }, + { + "wallClockMs": 348, + "metrics": { + "Timestamp": 0.34925700002349913, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 48, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 18, + "RecalcStyleCount": 4, + "LayoutDuration": 0.0021070000000000255, + "RecalcStyleDuration": 0.00023400000000001198, + "DevToolsCommandDuration": 0.0049859999999999904, + "ScriptDuration": 0.04433900000000002, + "V8CompileDuration": 0, + "TaskDuration": 0.06649700000000003, + "TaskOtherDuration": 0.014830999999999817, + "ThreadTime": 0.06682600000000027, + "ProcessTime": 0.11427699999999952, + "JSHeapUsedSize": 4487340, + "JSHeapTotalSize": 1310720, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-pan:5", + "startTime": 1528.3999998569489, + "duration": 348 + }, + "wasm": [], + "projection": [], + "longTasks": [], + "gc": [] + }, + "trace": null, + "tracePath": null + }, + { + "wallClockMs": 348.39999985694885, + "metrics": { + "Timestamp": 0.35040999995544553, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 48, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 18, + "RecalcStyleCount": 4, + "LayoutDuration": 0.0022130000000000205, + "RecalcStyleDuration": 0.00026199999999999835, + "DevToolsCommandDuration": 0.004960999999999993, + "ScriptDuration": 0.04327199999999998, + "V8CompileDuration": 0, + "TaskDuration": 0.06731100000000012, + "TaskOtherDuration": 0.016602999999999923, + "ThreadTime": 0.06679900000000005, + "ProcessTime": 0.11064799999999764, + "JSHeapUsedSize": 5778844, + "JSHeapTotalSize": 1310720, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-pan:6", + "startTime": 1512.7000000476837, + "duration": 348.39999985694885 + }, + "wasm": [], + "projection": [], + "longTasks": [], + "gc": [] + }, + "trace": null, + "tracePath": null + } + ] + }, + { + "profile": "flat", + "size": 1000, + "workload": "zoom", + "status": "measured", + "sampling": { + "warmups": 1, + "samples": 3 + }, + "summary": { + "count": 3, + "medianMs": 347.7999999523163, + "p95Ms": 753.5, + "regressionBudget": { + "statistic": "p95 milliseconds", + "maximum": 904.1999999999999, + "tolerancePercent": 20 + }, + "minimumMs": 345, + "maximumMs": 753.5, + "metrics": { + "median": { + "Timestamp": 0.5608390001580119, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 0, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 8, + "RecalcStyleCount": 0, + "LayoutDuration": 0.001399000000000039, + "RecalcStyleDuration": 0, + "DevToolsCommandDuration": 0.0030789999999999984, + "ScriptDuration": 0.038825, + "V8CompileDuration": 0, + "TaskDuration": 0.06823699999999988, + "TaskOtherDuration": 0.020207000000000086, + "ThreadTime": 0.05630999999999986, + "ProcessTime": 0.09309199999999862, + "JSHeapUsedSize": 5140776, + "JSHeapTotalSize": 0, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + } + } + }, + "samples": [ + { + "wallClockMs": 345, + "metrics": { + "Timestamp": 0.5608390001580119, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 0, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 8, + "RecalcStyleCount": 0, + "LayoutDuration": 0.001399000000000039, + "RecalcStyleDuration": 0, + "DevToolsCommandDuration": 0.0030789999999999984, + "ScriptDuration": 0.038825, + "V8CompileDuration": 0, + "TaskDuration": 0.06823699999999988, + "TaskOtherDuration": 0.02493400000000001, + "ThreadTime": 0.05630999999999986, + "ProcessTime": 0.09309199999999862, + "JSHeapUsedSize": 5140776, + "JSHeapTotalSize": 0, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-zoom:7", + "startTime": 1851.5999999046326, + "duration": 345 + }, + "wasm": [], + "projection": [], + "longTasks": [], + "gc": [] + }, + "trace": { + "eventCount": 4822, + "frameAndPaint": { + "frames": { + "count": 101, + "eventCount": 101, + "timedEventCount": 0, + "instantEventCount": 53, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "paint": { + "count": 198, + "eventCount": 198, + "timedEventCount": 187, + "instantEventCount": 11, + "medianMs": 0.003, + "p95Ms": 0.116, + "maximumMs": 1.829, + "totalMs": 5.942999999999998 + }, + "raster": { + "count": 0, + "eventCount": 0, + "timedEventCount": 0, + "instantEventCount": 0, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "compositor": { + "count": 87, + "eventCount": 87, + "timedEventCount": 26, + "instantEventCount": 11, + "medianMs": 0.033, + "p95Ms": 0.162, + "maximumMs": 0.185, + "totalMs": 1.3270000000000002 + }, + "layout": { + "count": 15, + "eventCount": 15, + "timedEventCount": 15, + "instantEventCount": 0, + "medianMs": 0.11, + "p95Ms": 0.258, + "maximumMs": 0.258, + "totalMs": 1.3960000000000001 + } + }, + "longTaskCount": 0, + "longTaskTotalMs": 0, + "gcCount": 57, + "gcTotalMs": 27.15999999999999, + "unclassifiedEventCount": 3269 + }, + "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-zoom-1.json.gz" + }, + { + "wallClockMs": 347.7999999523163, + "metrics": { + "Timestamp": 0.3505790000781417, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 0, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 8, + "RecalcStyleCount": 0, + "LayoutDuration": 0.0011430000000000051, + "RecalcStyleDuration": 0, + "DevToolsCommandDuration": 0.0021769999999999845, + "ScriptDuration": 0.032590999999999926, + "V8CompileDuration": 0, + "TaskDuration": 0.04562400000000011, + "TaskOtherDuration": 0.009713000000000083, + "ThreadTime": 0.042318000000000744, + "ProcessTime": 0.06954300000000302, + "JSHeapUsedSize": 4594868, + "JSHeapTotalSize": -507904, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-zoom:8", + "startTime": 1964.6000001430511, + "duration": 347.7999999523163 + }, + "wasm": [], + "projection": [], + "longTasks": [], + "gc": [] + }, + "trace": null, + "tracePath": null + }, + { + "wallClockMs": 753.5, + "metrics": { + "Timestamp": 0.758828999940306, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 0, + "LayoutObjects": 0, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 0, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": -1, + "LayoutCount": 9, + "RecalcStyleCount": 0, + "LayoutDuration": 0.0020649999999999835, + "RecalcStyleDuration": 0, + "DevToolsCommandDuration": 0.004525000000000001, + "ScriptDuration": 0.04361700000000002, + "V8CompileDuration": 0, + "TaskDuration": 0.07041400000000042, + "TaskOtherDuration": 0.020207000000000086, + "ThreadTime": 0.06806000000000001, + "ProcessTime": 0.10997400000000113, + "JSHeapUsedSize": 10000940, + "JSHeapTotalSize": 3932160, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-zoom:9", + "startTime": 1812.2999999523163, + "duration": 753.5 + }, + "wasm": [], + "projection": [], + "longTasks": [], + "gc": [] + }, + "trace": null, + "tracePath": null + } + ] + }, + { + "profile": "flat", + "size": 1000, + "workload": "box-selection", + "status": "measured", + "sampling": { + "warmups": 1, + "samples": 3 + }, + "summary": { + "count": 3, + "medianMs": 462.09999990463257, + "p95Ms": 480.69999980926514, + "regressionBudget": { + "statistic": "p95 milliseconds", + "maximum": 576.8399997711182, + "tolerancePercent": 20 + }, + "minimumMs": 448.39999985694885, + "maximumMs": 480.69999980926514, + "metrics": { + "median": { + "Timestamp": 0.48346200003288686, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 89, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 371, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 0, + "LayoutCount": 23, + "RecalcStyleCount": 26, + "LayoutDuration": 0.004630999999999941, + "RecalcStyleDuration": 0.003155000000000019, + "DevToolsCommandDuration": 0.007676999999999989, + "ScriptDuration": 0.05143000000000009, + "V8CompileDuration": 0, + "TaskDuration": 0.13526799999999994, + "TaskOtherDuration": 0.06899699999999953, + "ThreadTime": 0.13092599999999965, + "ProcessTime": 0.23538800000000393, + "JSHeapUsedSize": -3491580, + "JSHeapTotalSize": 4603904, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + } + } + }, + "samples": [ + { + "wallClockMs": 462.09999990463257, + "metrics": { + "Timestamp": 0.6417040000669658, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 89, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 371, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 1, + "LayoutCount": 23, + "RecalcStyleCount": 26, + "LayoutDuration": 0.004630999999999941, + "RecalcStyleDuration": 0.003155000000000019, + "DevToolsCommandDuration": 0.007054999999999978, + "ScriptDuration": 0.05143000000000009, + "V8CompileDuration": 0, + "TaskDuration": 0.13526799999999994, + "TaskOtherDuration": 0.06899699999999953, + "ThreadTime": 0.13092599999999965, + "ProcessTime": 0.23538800000000393, + "JSHeapUsedSize": 20146680, + "JSHeapTotalSize": 6815744, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-box-selection:10", + "startTime": 1615.6000001430511, + "duration": 462.09999990463257 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1972.4000000953674, + "duration": 47.5 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1950.2999999523163, + "duration": 17.200000047683716 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1945.6000001430511, + "duration": 66 + } + ], + "gc": [] + }, + "trace": { + "eventCount": 9015, + "frameAndPaint": { + "frames": { + "count": 135, + "eventCount": 135, + "timedEventCount": 0, + "instantEventCount": 73, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "paint": { + "count": 391, + "eventCount": 391, + "timedEventCount": 373, + "instantEventCount": 18, + "medianMs": 0.008, + "p95Ms": 0.143, + "maximumMs": 2.026, + "totalMs": 15.130999999999979 + }, + "raster": { + "count": 0, + "eventCount": 0, + "timedEventCount": 0, + "instantEventCount": 0, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "compositor": { + "count": 154, + "eventCount": 154, + "timedEventCount": 44, + "instantEventCount": 20, + "medianMs": 0.037, + "p95Ms": 0.157, + "maximumMs": 0.183, + "totalMs": 2.2819999999999996 + }, + "layout": { + "count": 59, + "eventCount": 59, + "timedEventCount": 59, + "instantEventCount": 0, + "medianMs": 0.09, + "p95Ms": 0.199, + "maximumMs": 1.783, + "totalMs": 7.757 + } + }, + "longTaskCount": 0, + "longTaskTotalMs": 0, + "gcCount": 129, + "gcTotalMs": 55.077000000000005, + "unclassifiedEventCount": 6455 + }, + "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-box-selection-1.json.gz" + }, + { + "wallClockMs": 448.39999985694885, + "metrics": { + "Timestamp": 0.45013000001199543, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 89, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 371, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 0, + "LayoutCount": 23, + "RecalcStyleCount": 26, + "LayoutDuration": 0.004114000000000062, + "RecalcStyleDuration": 0.003063000000000038, + "DevToolsCommandDuration": 0.007676999999999989, + "ScriptDuration": 0.044737999999999944, + "V8CompileDuration": 0, + "TaskDuration": 0.11234699999999975, + "TaskOtherDuration": 0.05275500000000033, + "ThreadTime": 0.11273100000000014, + "ProcessTime": 0.20750900000000172, + "JSHeapUsedSize": -3491580, + "JSHeapTotalSize": 1572864, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-box-selection:11", + "startTime": 1575.3000001907349, + "duration": 448.39999985694885 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1918.2000000476837, + "duration": 41 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1896.3000001907349, + "duration": 17.899999856948853 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1892.2000000476837, + "duration": 60 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + }, + { + "wallClockMs": 480.69999980926514, + "metrics": { + "Timestamp": 0.48346200003288686, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": -8, + "Frames": -2, + "JSEventListeners": -2322, + "LayoutObjects": -663, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": -1933, + "Resources": -468, + "ContextLifecycleStateObservers": -31, + "V8PerContextDatas": -4, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": -8, + "AdSubframes": 0, + "DetachedScriptStates": -8, + "ArrayBufferContents": -8, + "LayoutCount": 24, + "RecalcStyleCount": 26, + "LayoutDuration": 0.00551299999999999, + "RecalcStyleDuration": 0.003997000000000028, + "DevToolsCommandDuration": 0.009135000000000004, + "ScriptDuration": 0.05582600000000015, + "V8CompileDuration": 0, + "TaskDuration": 0.18098100000000006, + "TaskOtherDuration": 0.1065100000000001, + "ThreadTime": 0.17666500000000163, + "ProcessTime": 0.33938500000000005, + "JSHeapUsedSize": -35742728, + "JSHeapTotalSize": 4603904, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-box-selection:12", + "startTime": 2143.2000000476837, + "duration": 480.69999980926514 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 2520.2000000476837, + "duration": 43.299999952316284 + } + ], + "projection": [ + { + "name": "inkfinite:editor:projection:2", + "startTime": 2165.7000000476837, + "duration": 3.1999998092651367 + }, + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 2496.2000000476837, + "duration": 18.5 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 2492.0999999046326, + "duration": 64 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + } + ] + }, + { + "profile": "flat", + "size": 1000, + "workload": "single-drag", + "status": "measured", + "sampling": { + "warmups": 1, + "samples": 3 + }, + "summary": { + "count": 3, + "medianMs": 533.3999998569489, + "p95Ms": 555.9000000953674, + "regressionBudget": { + "statistic": "p95 milliseconds", + "maximum": 667.0800001144408, + "tolerancePercent": 20 + }, + "minimumMs": 499.69999980926514, + "maximumMs": 555.9000000953674, + "metrics": { + "median": { + "Timestamp": 0.5630810000002384, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 72, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 312, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 1, + "LayoutCount": 23, + "RecalcStyleCount": 11, + "LayoutDuration": 0.0049600000000000755, + "RecalcStyleDuration": 0.0016680000000000028, + "DevToolsCommandDuration": 0.009329000000000032, + "ScriptDuration": 0.11255799999999994, + "V8CompileDuration": 0, + "TaskDuration": 0.2722699999999989, + "TaskOtherDuration": 0.14240499999999923, + "ThreadTime": 0.2507780000000004, + "ProcessTime": 0.6481309999999993, + "JSHeapUsedSize": 10998020, + "JSHeapTotalSize": 0, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + } + } + }, + "samples": [ + { + "wallClockMs": 533.3999998569489, + "metrics": { + "Timestamp": 0.7461580000817776, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 72, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 312, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 1, + "LayoutCount": 23, + "RecalcStyleCount": 12, + "LayoutDuration": 0.0049600000000000755, + "RecalcStyleDuration": 0.002574999999999994, + "DevToolsCommandDuration": 0.009772000000000003, + "ScriptDuration": 0.11255799999999994, + "V8CompileDuration": 0, + "TaskDuration": 0.2722699999999989, + "TaskOtherDuration": 0.14240499999999923, + "ThreadTime": 0.2507780000000004, + "ProcessTime": 0.7282590000000013, + "JSHeapUsedSize": 10998020, + "JSHeapTotalSize": 7618560, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-single-drag:13", + "startTime": 1547.5, + "duration": 533.3999998569489 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1651.7999999523163, + "duration": 70.09999990463257 + }, + { + "name": "inkfinite:wasm:document_state:3", + "startTime": 1983.5999999046326, + "duration": 46.10000014305115 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1636.7000000476837, + "duration": 14.599999904632568 + }, + { + "name": "inkfinite:editor:store-commit:4", + "startTime": 1969.0999999046326, + "duration": 14 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1635.5, + "duration": 59 + }, + { + "name": "self", + "startTime": 1967.7999999523163, + "duration": 55 + } + ], + "gc": [] + }, + "trace": { + "eventCount": 11183, + "frameAndPaint": { + "frames": { + "count": 193, + "eventCount": 193, + "timedEventCount": 0, + "instantEventCount": 83, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "paint": { + "count": 265, + "eventCount": 265, + "timedEventCount": 248, + "instantEventCount": 17, + "medianMs": 0.005, + "p95Ms": 0.124, + "maximumMs": 1.977, + "totalMs": 11.221000000000009 + }, + "raster": { + "count": 0, + "eventCount": 0, + "timedEventCount": 0, + "instantEventCount": 0, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "compositor": { + "count": 202, + "eventCount": 202, + "timedEventCount": 48, + "instantEventCount": 22, + "medianMs": 0.031, + "p95Ms": 0.191, + "maximumMs": 0.395, + "totalMs": 2.5279999999999982 + }, + "layout": { + "count": 44, + "eventCount": 44, + "timedEventCount": 44, + "instantEventCount": 0, + "medianMs": 0.112, + "p95Ms": 0.89, + "maximumMs": 1.994, + "totalMs": 7.440000000000002 + } + }, + "longTaskCount": 0, + "longTaskTotalMs": 0, + "gcCount": 342, + "gcTotalMs": 295.2149999999998, + "unclassifiedEventCount": 7795 + }, + "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-single-drag-1.json.gz" + }, + { + "wallClockMs": 555.9000000953674, + "metrics": { + "Timestamp": 0.5630810000002384, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": -7, + "Frames": 0, + "JSEventListeners": -2511, + "LayoutObjects": -571, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": -2034, + "Resources": -250, + "ContextLifecycleStateObservers": -28, + "V8PerContextDatas": -6, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": -5, + "AdSubframes": 0, + "DetachedScriptStates": -1, + "ArrayBufferContents": -5, + "LayoutCount": 23, + "RecalcStyleCount": 11, + "LayoutDuration": 0.005468999999999946, + "RecalcStyleDuration": 0.0015979999999999883, + "DevToolsCommandDuration": 0.009329000000000032, + "ScriptDuration": 0.13133699999999982, + "V8CompileDuration": 0, + "TaskDuration": 0.31769099999999995, + "TaskOtherDuration": 0.1699579999999994, + "ThreadTime": 0.2903570000000002, + "ProcessTime": 0.6481309999999993, + "JSHeapUsedSize": -49818144, + "JSHeapTotalSize": -2080768, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-single-drag:14", + "startTime": 1628.5999999046326, + "duration": 555.9000000953674 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1703.5999999046326, + "duration": 50.700000047683716 + }, + { + "name": "inkfinite:wasm:document_state:3", + "startTime": 2047.2999999523163, + "duration": 49.200000047683716 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1688, + "duration": 14.899999856948853 + }, + { + "name": "inkfinite:editor:store-commit:4", + "startTime": 2031, + "duration": 15.799999952316284 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1668.1999998092651, + "duration": 74 + }, + { + "name": "self", + "startTime": 2029.5999999046326, + "duration": 57 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + }, + { + "wallClockMs": 499.69999980926514, + "metrics": { + "Timestamp": 0.5006099999882281, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 72, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 312, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 2, + "LayoutCount": 22, + "RecalcStyleCount": 11, + "LayoutDuration": 0.003964999999999996, + "RecalcStyleDuration": 0.0016680000000000028, + "DevToolsCommandDuration": 0.006171999999999955, + "ScriptDuration": 0.11020199999999991, + "V8CompileDuration": 0, + "TaskDuration": 0.2167349999999999, + "TaskOtherDuration": 0.09472799999999992, + "ThreadTime": 0.21502100000000013, + "ProcessTime": 0.4621229999999983, + "JSHeapUsedSize": 33251916, + "JSHeapTotalSize": 0, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-single-drag:15", + "startTime": 1604.2000000476837, + "duration": 499.69999980926514 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1671.8999998569489, + "duration": 56.30000019073486 + }, + { + "name": "inkfinite:wasm:document_state:3", + "startTime": 2004.7000000476837, + "duration": 41 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1657.5, + "duration": 13.899999856948853 + }, + { + "name": "inkfinite:editor:store-commit:4", + "startTime": 1991.2000000476837, + "duration": 13.099999904632568 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1646.2999999523163, + "duration": 65 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + } + ] + }, + { + "profile": "flat", + "size": 1000, + "workload": "multi-drag", + "status": "measured", + "sampling": { + "warmups": 1, + "samples": 3 + }, + "summary": { + "count": 3, + "medianMs": 552.2999999523163, + "p95Ms": 628.4000000953674, + "regressionBudget": { + "statistic": "p95 milliseconds", + "maximum": 754.0800001144408, + "tolerancePercent": 20 + }, + "minimumMs": 547, + "maximumMs": 628.4000000953674, + "metrics": { + "median": { + "Timestamp": 0.629731000168249, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 88, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 365, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 2, + "LayoutCount": 25, + "RecalcStyleCount": 14, + "LayoutDuration": 0.004335000000000089, + "RecalcStyleDuration": 0.0022340000000000138, + "DevToolsCommandDuration": 0.007140000000000035, + "ScriptDuration": 0.1280129999999997, + "V8CompileDuration": 0, + "TaskDuration": 0.2787550000000003, + "TaskOtherDuration": 0.1364749999999999, + "ThreadTime": 0.2769390000000005, + "ProcessTime": 0.5950539999999975, + "JSHeapUsedSize": 13165784, + "JSHeapTotalSize": 4194304, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + } + } + }, + "samples": [ + { + "wallClockMs": 547, + "metrics": { + "Timestamp": 0.7445970000699162, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 88, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 365, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 2, + "LayoutCount": 25, + "RecalcStyleCount": 14, + "LayoutDuration": 0.0046319999999999695, + "RecalcStyleDuration": 0.0022340000000000138, + "DevToolsCommandDuration": 0.007400999999999991, + "ScriptDuration": 0.1280129999999997, + "V8CompileDuration": 0, + "TaskDuration": 0.2787550000000003, + "TaskOtherDuration": 0.1364749999999999, + "ThreadTime": 0.2769390000000005, + "ProcessTime": 0.776448000000002, + "JSHeapUsedSize": 13165784, + "JSHeapTotalSize": 6029312, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-multi-drag:16", + "startTime": 1494.5999999046326, + "duration": 547 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1561.2000000476837, + "duration": 96 + }, + { + "name": "inkfinite:wasm:document_state:3", + "startTime": 1618.5, + "duration": 64.90000009536743 + }, + { + "name": "inkfinite:wasm:document_state:4", + "startTime": 1941.7000000476837, + "duration": 41.799999952316284 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1545.7999999523163, + "duration": 14.900000095367432 + }, + { + "name": "inkfinite:editor:store-commit:4", + "startTime": 1606, + "duration": 12.099999904632568 + }, + { + "name": "inkfinite:editor:store-commit:5", + "startTime": 1929, + "duration": 12.299999952316284 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1537.0999999046326, + "duration": 56 + }, + { + "name": "self", + "startTime": 1598.7999999523163, + "duration": 51 + } + ], + "gc": [] + }, + "trace": { + "eventCount": 11132, + "frameAndPaint": { + "frames": { + "count": 162, + "eventCount": 162, + "timedEventCount": 0, + "instantEventCount": 82, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "paint": { + "count": 290, + "eventCount": 290, + "timedEventCount": 274, + "instantEventCount": 16, + "medianMs": 0.004, + "p95Ms": 0.127, + "maximumMs": 1.452, + "totalMs": 9.478000000000003 + }, + "raster": { + "count": 0, + "eventCount": 0, + "timedEventCount": 0, + "instantEventCount": 0, + "medianMs": null, + "p95Ms": null, + "maximumMs": null, + "totalMs": 0 + }, + "compositor": { + "count": 178, + "eventCount": 178, + "timedEventCount": 50, + "instantEventCount": 22, + "medianMs": 0.029, + "p95Ms": 0.075, + "maximumMs": 0.152, + "totalMs": 1.8059999999999992 + }, + "layout": { + "count": 49, + "eventCount": 49, + "timedEventCount": 49, + "instantEventCount": 0, + "medianMs": 0.111, + "p95Ms": 0.329, + "maximumMs": 1.577, + "totalMs": 6.775999999999999 + } + }, + "longTaskCount": 0, + "longTaskTotalMs": 0, + "gcCount": 488, + "gcTotalMs": 158.80500000000018, + "unclassifiedEventCount": 7906 + }, + "tracePath": "/Users/owais/Projects/StormlightLabs/OpenSource/inkfinite/fixtures/native/performance/browser-traces/flat-1000-multi-drag-1.json.gz" + }, + { + "wallClockMs": 628.4000000953674, + "metrics": { + "Timestamp": 0.629731000168249, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 88, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 365, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 2, + "LayoutCount": 25, + "RecalcStyleCount": 14, + "LayoutDuration": 0.004335000000000089, + "RecalcStyleDuration": 0.0022699999999999942, + "DevToolsCommandDuration": 0.007140000000000035, + "ScriptDuration": 0.16598000000000024, + "V8CompileDuration": 0, + "TaskDuration": 0.32324799999999954, + "TaskOtherDuration": 0.14352300000000007, + "ThreadTime": 0.284339000000001, + "ProcessTime": 0.5950539999999975, + "JSHeapUsedSize": 15198216, + "JSHeapTotalSize": 3670016, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-multi-drag:17", + "startTime": 1579.2999999523163, + "duration": 628.4000000953674 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1673.0999999046326, + "duration": 141 + }, + { + "name": "inkfinite:wasm:document_state:3", + "startTime": 1773.0999999046326, + "duration": 45.80000019073486 + }, + { + "name": "inkfinite:wasm:document_state:4", + "startTime": 2107.4000000953674, + "duration": 39.5 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1626.4000000953674, + "duration": 46.299999952316284 + }, + { + "name": "inkfinite:editor:store-commit:4", + "startTime": 1755.7000000476837, + "duration": 17.09999990463257 + }, + { + "name": "inkfinite:editor:store-commit:5", + "startTime": 2094.5999999046326, + "duration": 12.5 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1617.7999999523163, + "duration": 103 + }, + { + "name": "self", + "startTime": 1749.4000000953674, + "duration": 57 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + }, + { + "wallClockMs": 552.2999999523163, + "metrics": { + "Timestamp": 0.5530799999833107, + "AudioHandlers": 0, + "AudioWorkletProcessors": 0, + "Documents": 0, + "Frames": 0, + "JSEventListeners": 49, + "LayoutObjects": 88, + "MediaKeySessions": 0, + "MediaKeys": 0, + "Nodes": 365, + "Resources": 0, + "ContextLifecycleStateObservers": 0, + "V8PerContextDatas": 0, + "WorkerGlobalScopes": 0, + "UACSSResources": 0, + "RTCPeerConnections": 0, + "ResourceFetchers": 0, + "AdSubframes": 0, + "DetachedScriptStates": 0, + "ArrayBufferContents": 2, + "LayoutCount": 25, + "RecalcStyleCount": 14, + "LayoutDuration": 0.004254999999999898, + "RecalcStyleDuration": 0.002206999999999959, + "DevToolsCommandDuration": 0.00628200000000001, + "ScriptDuration": 0.12266099999999991, + "V8CompileDuration": 0, + "TaskDuration": 0.25519499999999873, + "TaskOtherDuration": 0.11979000000000006, + "ThreadTime": 0.25466100000000047, + "ProcessTime": 0.547069999999998, + "JSHeapUsedSize": 13104604, + "JSHeapTotalSize": 4194304, + "FirstMeaningfulPaint": 0, + "DomContentLoaded": 0, + "NavigationStart": 0 + }, + "performance": { + "benchmark": { + "name": "inkfinite:benchmark:flat-1000-multi-drag:18", + "startTime": 1568.7000000476837, + "duration": 552.2999999523163 + }, + "wasm": [ + { + "name": "inkfinite:wasm:document_state:2", + "startTime": 1635.1000001430511, + "duration": 93.29999995231628 + }, + { + "name": "inkfinite:wasm:document_state:3", + "startTime": 1691.1000001430511, + "duration": 42.09999990463257 + }, + { + "name": "inkfinite:wasm:document_state:4", + "startTime": 2018.5, + "duration": 39.30000019073486 + } + ], + "projection": [ + { + "name": "inkfinite:editor:store-commit:3", + "startTime": 1620.9000000953674, + "duration": 13.799999952316284 + }, + { + "name": "inkfinite:editor:store-commit:4", + "startTime": 1679, + "duration": 11.800000190734863 + }, + { + "name": "inkfinite:editor:store-commit:5", + "startTime": 2005.5, + "duration": 12.700000047683716 + } + ], + "longTasks": [ + { + "name": "self", + "startTime": 1611.9000000953674, + "duration": 55 + }, + { + "name": "self", + "startTime": 1671.9000000953674, + "duration": 50 + } + ], + "gc": [] + }, + "trace": null, + "tracePath": null + } + ] + }, + { + "profile": "flat", + "size": 1000, + "workload": "vector-edit", + "status": "skipped", + "reason": "Requires the native path profile." + }, + { + "profile": "flat", + "size": 1000, + "workload": "connected-drag", + "status": "skipped", + "reason": "Requires the connection-heavy profile." + }, + { + "profile": "flat", + "size": 1000, + "workload": "nested-selection", + "status": "skipped", + "reason": "Requires the deeply-nested profile." + } + ], + "memory": [ + { + "profile": "flat", + "size": 10000, + "baseline": { + "jsHeapUsedBytes": 8900028, + "jsHeapTotalBytes": 9486336, + "performanceJsHeapUsedBytes": 8900028, + "rendererResidentSetSizeBytes": null + }, + "afterLoad": { + "jsHeapUsedBytes": 30610808, + "jsHeapTotalBytes": 32227328, + "performanceJsHeapUsedBytes": 30610808, + "rendererResidentSetSizeBytes": null, + "deltaFromBaseline": { + "jsHeapUsedBytes": 21710780, + "jsHeapTotalBytes": 22740992, + "performanceJsHeapUsedBytes": 21710780 + } + }, + "afterSustainedEditing": { + "jsHeapUsedBytes": 319019164, + "jsHeapTotalBytes": 354385920, + "performanceJsHeapUsedBytes": 319019164, + "rendererResidentSetSizeBytes": null, + "deltaFromBaseline": { + "jsHeapUsedBytes": 310119136, + "jsHeapTotalBytes": 344899584, + "performanceJsHeapUsedBytes": 310119136 + } + }, + "afterReplacement": { + "jsHeapUsedBytes": 295186188, + "jsHeapTotalBytes": 316309504, + "performanceJsHeapUsedBytes": 295186188, + "rendererResidentSetSizeBytes": null, + "deltaFromBaseline": { + "jsHeapUsedBytes": 286286160, + "jsHeapTotalBytes": 306823168, + "performanceJsHeapUsedBytes": 286286160 + } + }, + "sustainedEditingMs": 150094.09999990463 + } + ] } diff --git a/packages/perf/src/measure-browser.ts b/packages/perf/src/measure-browser.ts index 2ad47e8..3c4e4fd 100644 --- a/packages/perf/src/measure-browser.ts +++ b/packages/perf/src/measure-browser.ts @@ -145,12 +145,12 @@ function safeName(value) { } function startWebServer(port) { - const server = spawn( - 'pnpm', - ['--filter', '@inkfinite/web', 'dev:plain', '--host', '127.0.0.1', '--port', String(port)], - { cwd: root, stdio: 'ignore', env: { ...process.env, BROWSER: 'none' } } - ); - return server; + const vite = resolve(root, 'apps/web/node_modules/vite/bin/vite.js'); + return spawn(process.execPath, [vite, 'dev', '--host', '127.0.0.1', '--port', String(port), '--strictPort'], { + cwd: resolve(root, 'apps/web'), + stdio: 'ignore', + env: { ...process.env, BROWSER: 'none' } + }); } async function waitForServer(port, server) { @@ -271,7 +271,17 @@ async function prepareFixture(page, baseUrl, documents) { } async function waitForEditor(page) { - await page.locator('canvas[aria-label="Infinite canvas"]').waitFor({ state: 'visible', timeout: 60_000 }); + try { + await page.locator('canvas[aria-label="Infinite canvas"]').waitFor({ state: 'visible', timeout: 60_000 }); + } catch (error) { + const body = ( + await page + .locator('body') + .innerText() + .catch(() => '') + ).slice(0, 500); + throw new Error(`Editor canvas did not become visible at ${page.url()}. Page text: ${body}`, { cause: error }); + } await page.getByRole('button', { name: 'Shapes', exact: true }).waitFor({ state: 'visible' }); await page.waitForFunction( () => @@ -516,15 +526,26 @@ async function markEnd(page, name) { }, name); } +async function wasmMeasureCount(page) { + return page.evaluate( + () => performance.getEntriesByType('measure').filter((entry) => entry.name.startsWith('inkfinite:wasm:')).length + ); +} + +async function waitForWasmOperations(page, count, expected, timeout = 60_000) { + await page.waitForFunction( + ({ initialCount, expectedCount }) => + performance.getEntriesByType('measure').filter((entry) => entry.name.startsWith('inkfinite:wasm:')) + .length >= + initialCount + expectedCount, + { initialCount: count, expectedCount: expected }, + { timeout } + ); +} + async function measureAction(page, cdp, label, action, options) { const benchmarkName = `inkfinite:benchmark:${safeName(label)}:${options.sequence}`; - const wasmMeasureCount = options.expectedWasmOperations - ? await page.evaluate( - () => - performance.getEntriesByType('measure').filter((entry) => entry.name.startsWith('inkfinite:wasm:')) - .length - ) - : 0; + const initialWasmMeasureCount = options.expectedWasmOperations ? await wasmMeasureCount(page) : 0; const stopTrace = options.trace ? await beginTrace(cdp) : null; const before = await readMetrics(cdp); const startTime = await markStart(page, benchmarkName); @@ -533,14 +554,7 @@ async function measureAction(page, cdp, label, action, options) { await action(); await settleFrames(page, 4); if (options.expectedWasmOperations) { - await page.waitForFunction( - ({ count, expected }) => - performance.getEntriesByType('measure').filter((entry) => entry.name.startsWith('inkfinite:wasm:')) - .length >= - count + expected, - { count: wasmMeasureCount, expected: options.expectedWasmOperations }, - { timeout: 60_000 } - ); + await waitForWasmOperations(page, initialWasmMeasureCount, options.expectedWasmOperations); } } finally { await markEnd(page, benchmarkName); @@ -797,12 +811,14 @@ async function measureMemory(page, cdp, baseUrl, fixture, options, sequenceState `${fixture.profile}-${fixture.size}-sustained-editing`, async () => { const points = await canvasPoints(page); + await page.getByRole('button', { name: 'Select', exact: true }).click(); for (let index = 0; index < 20; index += 1) { - const offset = index % 2 === 0 ? 0 : 80; + const offset = index % 2 === 0 ? 0 : 40; const start = { x: points.shape.x + offset, y: points.shape.y }; - await page.getByRole('button', { name: 'Select', exact: true }).click(); - await page.mouse.click(start.x, start.y); - await drag(page, start, { x: start.x + (offset === 0 ? 80 : -80), y: start.y + 40 }); + const count = await wasmMeasureCount(page); + await drag(page, start, { x: start.x + (offset === 0 ? 40 : -40), y: start.y }); + await waitForWasmOperations(page, count, 1); + await settleFrames(page); } }, { trace: false, sequence: sequenceState.value++, expectedWasmOperations: 20 } @@ -813,21 +829,13 @@ async function measureMemory(page, cdp, baseUrl, fixture, options, sequenceState await page.getByRole('button', { name: 'Browse boards' }).click(); await browser.waitFor({ state: 'visible' }); const rows = browser.locator('[data-board-row]'); - const wasmMeasureCount = await page.evaluate( - () => performance.getEntriesByType('measure').filter((entry) => entry.name.startsWith('inkfinite:wasm:')).length - ); + const replacementWasmMeasureCount = await wasmMeasureCount(page); await rows .nth(1) .getByRole('button', { name: /^Open / }) .click(); - await browser.waitFor({ state: 'hidden' }); - await page.waitForFunction( - (count) => - performance.getEntriesByType('measure').filter((entry) => entry.name.startsWith('inkfinite:wasm:')).length > - count, - wasmMeasureCount, - { timeout: 60_000 } - ); + await browser.waitFor({ state: 'hidden', timeout: 120_000 }); + await waitForWasmOperations(page, replacementWasmMeasureCount, 1, 120_000); await settleFrames(page, 5); const afterReplacement = await readMemory(cdp); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b2c682..ba22c08 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + jsdom: 27.3.0 + importers: .: @@ -68,7 +71,7 @@ importers: version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.23.12)(yaml@2.8.2) vitest: specifier: ^4.0.15 - version: 4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@29.1.1)(tsx@4.23.12)(yaml@2.8.2) + version: 4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@27.3.0)(tsx@4.23.12)(yaml@2.8.2) apps/web: dependencies: @@ -131,7 +134,7 @@ importers: specifier: ^16.5.0 version: 16.5.0 jsdom: - specifier: ^27.3.0 + specifier: 27.3.0 version: 27.3.0 mdsvex: specifier: ^0.12.7 @@ -228,7 +231,7 @@ importers: specifier: ^27.0.0 version: 27.0.0 jsdom: - specifier: ^27.3.0 + specifier: 27.3.0 version: 27.3.0 prettier: specifier: ^3.7.4 @@ -356,7 +359,7 @@ importers: specifier: ^4.0.16 version: 4.0.16(@vitest/browser@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(tsx@4.23.12)(yaml@2.8.2))(vitest@4.0.16))(vitest@4.0.16) jsdom: - specifier: ^27.3.0 + specifier: 27.3.0 version: 27.3.0 prettier: specifier: ^3.7.4 @@ -413,21 +416,9 @@ packages: '@asamuzakjp/css-color@4.1.1': resolution: {integrity: sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==} - '@asamuzakjp/css-color@5.1.11': - resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@asamuzakjp/dom-selector@6.7.6': resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==} - '@asamuzakjp/dom-selector@7.1.1': - resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/generational-cache@1.0.1': - resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} @@ -467,10 +458,6 @@ packages: '@bomb.sh/args@0.3.1': resolution: {integrity: sha512-CwxKrfgcorUPP6KfYD59aRdBYWBTsfsxT+GmoLVnKo5Tmyoqbpo0UNcjngRMyU+6tiPbd18RuIYxhgAn44wU/Q==} - '@bramus/specificity@2.4.2': - resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} - hasBin: true - '@clack/core@0.5.0': resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} @@ -481,10 +468,6 @@ packages: resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} - '@csstools/color-helpers@6.1.0': - resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} - engines: {node: '>=20.19.0'} - '@csstools/css-calc@2.1.4': resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} engines: {node: '>=18'} @@ -492,13 +475,6 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-calc@3.2.1': - resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@3.1.0': resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} engines: {node: '>=18'} @@ -506,25 +482,12 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-color-parser@4.1.9': - resolution: {integrity: sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-parser-algorithms@3.0.5': resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} engines: {node: '>=18'} peerDependencies: '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.1.6': resolution: {integrity: sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==} peerDependencies: @@ -537,10 +500,6 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} - engines: {node: '>=20.19.0'} - '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -933,15 +892,6 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@exodus/bytes@1.15.1': - resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@noble/hashes': ^1.8.0 || ^2.0.0 - peerDependenciesMeta: - '@noble/hashes': - optional: true - '@fontsource-variable/atkinson-hyperlegible-next@5.3.0': resolution: {integrity: sha512-UnLzNUy1RWoLDfydAatP4NaRm99X/WbQEph7q/PymJnCFIOOwKOx3pBmp5ys8trO0dM+CKGuJgeZP9fAR4mQpA==} @@ -2392,10 +2342,6 @@ packages: resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} engines: {node: '>=20'} - data-urls@7.0.0: - resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2666,10 +2612,6 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -2782,15 +2724,6 @@ packages: canvas: optional: true - jsdom@29.1.1: - resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -3429,10 +3362,6 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.28.0: - resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} - engines: {node: '>=20.18.1'} - unist-util-is@4.1.0: resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} @@ -3571,7 +3500,7 @@ packages: '@vitest/browser-webdriverio': 4.0.16 '@vitest/ui': 4.0.16 happy-dom: '*' - jsdom: '*' + jsdom: 27.3.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -3612,18 +3541,10 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - whatwg-url@15.1.0: resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} engines: {node: '>=20'} - whatwg-url@16.0.1: - resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -3696,15 +3617,6 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 11.5.2 - '@asamuzakjp/css-color@5.1.11': - dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - '@asamuzakjp/dom-selector@6.7.6': dependencies: '@asamuzakjp/nwsapi': 2.3.9 @@ -3713,18 +3625,6 @@ snapshots: is-potential-custom-element-name: 1.0.1 lru-cache: 11.5.2 - '@asamuzakjp/dom-selector@7.1.1': - dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.2.1 - is-potential-custom-element-name: 1.0.1 - optional: true - - '@asamuzakjp/generational-cache@1.0.1': - optional: true - '@asamuzakjp/nwsapi@2.3.9': {} '@babel/code-frame@7.29.7': @@ -3760,11 +3660,6 @@ snapshots: '@bomb.sh/args@0.3.1': {} - '@bramus/specificity@2.4.2': - dependencies: - css-tree: 3.2.1 - optional: true - '@clack/core@0.5.0': dependencies: picocolors: 1.1.1 @@ -3778,20 +3673,11 @@ snapshots: '@csstools/color-helpers@5.1.0': {} - '@csstools/color-helpers@6.1.0': - optional: true - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/color-helpers': 5.1.0 @@ -3799,32 +3685,16 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-color-parser@4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/color-helpers': 6.1.0 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - optional: true - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-tokenizer': 4.0.0 - optional: true - '@csstools/css-syntax-patches-for-csstree@1.1.6(css-tree@3.2.1)': optionalDependencies: css-tree: 3.2.1 '@csstools/css-tokenizer@3.0.4': {} - '@csstools/css-tokenizer@4.0.0': - optional: true - '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -4092,9 +3962,6 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@exodus/bytes@1.15.1': - optional: true - '@fontsource-variable/atkinson-hyperlegible-next@5.3.0': {} '@fontsource-variable/azeret-mono@5.3.0': {} @@ -5199,7 +5066,7 @@ snapshots: '@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.23.12)(yaml@2.8.2)) playwright: 1.61.1 tinyrainbow: 3.0.3 - vitest: 4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@29.1.1)(tsx@4.23.12)(yaml@2.8.2) + vitest: 4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@27.3.0)(tsx@4.23.12)(yaml@2.8.2) transitivePeerDependencies: - bufferutil - msw @@ -5228,7 +5095,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@29.1.1)(tsx@4.23.12)(yaml@2.8.2) + vitest: 4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@27.3.0)(tsx@4.23.12)(yaml@2.8.2) ws: 8.18.3 transitivePeerDependencies: - bufferutil @@ -5540,14 +5407,6 @@ snapshots: whatwg-mimetype: 4.0.0 whatwg-url: 15.1.0 - data-urls@7.0.0: - dependencies: - whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - debug@4.4.3: dependencies: ms: 2.1.3 @@ -5836,13 +5695,6 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 - html-encoding-sniffer@6.0.0: - dependencies: - '@exodus/bytes': 1.15.1 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - html-escaper@2.0.2: {} http-proxy-agent@7.0.2: @@ -5962,33 +5814,6 @@ snapshots: - supports-color - utf-8-validate - jsdom@29.1.1: - dependencies: - '@asamuzakjp/css-color': 5.1.11 - '@asamuzakjp/dom-selector': 7.1.1 - '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.6(css-tree@3.2.1) - '@exodus/bytes': 1.15.1 - css-tree: 3.2.1 - data-urls: 7.0.0 - decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.5.2 - parse5: 8.0.1 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.2 - undici: 7.28.0 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -6703,9 +6528,6 @@ snapshots: undici-types@7.16.0: {} - undici@7.28.0: - optional: true - unist-util-is@4.1.0: {} unist-util-stringify-position@2.0.3: @@ -6867,45 +6689,6 @@ snapshots: - tsx - yaml - vitest@4.0.16(@types/node@24.10.4)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@29.1.1)(tsx@4.23.12)(yaml@2.8.2): - dependencies: - '@vitest/expect': 4.0.16 - '@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.23.12)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.16 - '@vitest/runner': 4.0.16 - '@vitest/snapshot': 4.0.16 - '@vitest/spy': 4.0.16 - '@vitest/utils': 4.0.16 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.5 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.17 - tinyrainbow: 3.0.3 - vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.23.12)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.10.4 - '@vitest/browser-playwright': 4.0.16(playwright@1.61.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.23.12)(yaml@2.8.2))(vitest@4.0.16) - jsdom: 29.1.1 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vitest@4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(jsdom@27.3.0)(tsx@4.23.12)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.16 @@ -6959,23 +6742,11 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-mimetype@5.0.0: - optional: true - whatwg-url@15.1.0: dependencies: tr46: 6.0.0 webidl-conversions: 8.0.1 - whatwg-url@16.0.1: - dependencies: - '@exodus/bytes': 1.15.1 - tr46: 6.0.0 - webidl-conversions: 8.0.1 - transitivePeerDependencies: - - '@noble/hashes' - optional: true - which@2.0.2: dependencies: isexe: 2.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 589c44b..747ead8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,9 @@ packages: - packages/* - apps/* +overrides: + jsdom: 27.3.0 + allowBuilds: esbuild: true