openpencil/packages/core/package.json

217 lines
6.2 KiB
JSON
Raw Normal View History

{
"name": "@open-pencil/core",
2026-09-18 13:19:49 +00:00
"version": "0.15.1",
2026-03-02 05:31:54 +00:00
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/open-pencil/open-pencil.git",
"directory": "packages/core"
},
"files": [
"dist",
fix(packages): make packed exports runtime-safe (#665) * fix(packages): make packed exports runtime-safe Make checked-in package manifests truthful for ordinary npm and Bun packing, and verify installed artifacts under both runtimes. Centralize package discovery, artifact inspection, and bounded process execution so CI and release publication share the same contracts. * ci: build package dependencies before checks Keep workspace jobs independent of ignored dist output now that public package exports consistently resolve built artifacts. * ci: preserve source-first engine tests Keep the broader dependency build for package and repository validation, but retain Core-only setup for engine shards so workspace tests continue exercising source modules. * ci: build engine shard dependencies Build the seven workspace packages imported by engine tests in dependency order. This preserves a single module instance per package and keeps each clean CI shard independent of ignored dist output. * ci: restore established package build boundaries Keep the original repository and engine job setup, and add installed artifact verification only after the existing package build. Avoid changing which module copies unrelated tests execute. * fix(packages): preserve Bun source identity in tarballs Retain source-first workspace resolution and ship complete source trees for Bun conditions. Verify clean installed consumers without overlaying archives, reuse consumer validation before release publication, and repair Bun 1.3.10 private source alias resolution. * refactor(tooling): reuse package and process utilities Use pkg-types for manifest I/O and types, tinyexec for subprocess lifecycle, and npm's pack listing for release staging. Preserve archive verification and project release invariants rather than reimplementing package-manager file selection. * refactor(tooling): resolve workspace roots at CLI boundaries Discover and validate the nearest workspace once, support explicit roots, and pass roots to reusable checks. Replace subprocess entrypoint dispatch with direct calls and preserve aggregate package diagnostics without adding arbitrary test timeout increases. * fix(release): enforce publication boundaries Use root version alignment and shared validated npm output parsing. Enforce the public npm registry policy and test verification-before-publication, mismatched artifacts, and partial retries without registry writes. * refactor(tooling): validate package responses with Valibot Express npm pack and manifest identity contracts as schemas, infer parsed output types, and preserve contextual failures and relative-path safety. Document Valibot as the first-party validation convention while retaining Zod at SDK boundaries. * refactor(tooling): validate manifests at input boundaries Share Valibot schemas for consumed manifest fields, recursive exports, supported workspace declarations, and npm registry responses. Infer domain types and reject malformed metadata instead of silently skipping it downstream. * refactor(tooling): group package helpers by ownership Colocate manifest and workspace contracts, separate npm response parsing from generic JSON handling, and split smoke packing, installation, and runtime checks. Remove the release tarball forwarding shim and consolidate its coverage in package-artifacts. Preserve public tooling exports and CLI commands.
2026-09-09 15:25:22 +00:00
"src",
"assets"
],
"type": "module",
"sideEffects": false,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Refactor architecture boundaries across core, app, and packages (#234) * refactor(core): decompose editor factory and action modules Split the monolithic editor factory and large action modules into focused domain helpers: - create.ts assembles context through bridge modules (clipboard, components, structure, undo) and delegates to graph-reads, graph-events, layout-runner, component-sync, and state factory - structure.ts delegates to group, container-wrap, auto-layout-wrap, reorder, and state-toggle helpers - selection.ts delegates to hit-test, overlays, container navigation, and read helpers - clipboard.ts delegates to subtree-history, images, export, copy, fonts, and placement helpers - shapes.ts delegates to pen actions and section-adopt - components.ts delegates to focus and instances helpers - alignment.ts delegates to flip-rotate helper - text.ts uses explicit TextEditSession for snapshot comparison New focused modules: nudge, variable-bindings, layout-mode, page-viewports, tool-registry, color-space Undo: history/position and history/snapshot helpers, hardened batch/rollback with nested batch support and configurable limit * refactor(core): split tool definitions by domain Split the monolithic tool registry into domain-specific modules: - read/ — selection, find, pages, fonts, components, nodes, query, jsx - create/ — basic shapes, components, vector, JSX render - modify/ — paint, effects, geometry, layout, state, text, update - structure/ — basic, arrange, batch, hierarchy, replace, tree - variables/ — bindings, collections, read, values - vector/ — boolean, path, export, viewport - analyze/ — colors, typography, spacing, clusters, diff, eval - describe/ — summaries, tree, roles, layout-issues - stock-photo/ — providers, requests, apply - codegen/ — component-map, tokens Split registry into core/extended tiers; refine schema and AI adapter * refactor(core): restructure kiwi codec and instance overrides Reorganize the Kiwi .fig codec into domain subdirectories: - binary/ — codec, schema, protocol - fig/ — file, import, parse (core, worker, transfer) - node-change/ — convert, export-node, serialize, plugin-data - instance-overrides/ — constraints, dsd, populate, props, resolve, symbol-overrides, symbol-props, sync, types Vendored kiwi-schema/ left isolated * refactor(core): split profiler, icons, IO, and add subpath exports Profiler: speedscope-export, capture-session, hud-controller Icons: api, svg, types, render, create-icons tool IO: format registry and subpath exports Canvas/color/text/vector: targeted cleanup Add deliberate subpath exports: random, xpath, vector, color, canvas, scene-graph, kiwi, design-jsx, io, tools, editor, layout, canvaskit, profiler, text, lint, rpc, figma-api, constants * refactor(vue): decompose canvas input, surface lifecycle, and controls Canvas surface: gl-surface, kit-loader, render-loop, resize-observer Canvas input handlers: - move: drop-target, move-snap, duplicate-drag - select: select-move, select-hover, select-hit - resize: resize-rect, resize-vector, resize-start - transform: rotation, marquee, pan, text-selection - text-edit: navigation, clipboard, textarea lifecycle - Shared: click-count, space-key, pan, pan-zoom, draw, raf-scheduler Editor composition: - commands split: actions, context, metadata, edit, selection, view - menu-model split: command-groups, builders, types - Gradient stop composable reuse in primitive root Controls: fill, layout, typography, appearance, effects, stroke, okhcl, prop-scrub, node-props, undo-batch, color-variable-binding Variables/i18n/document/export helpers Organize canvas, primitives, controls, editor, and variables into cohesive module directories with package-local import aliases Expose MenuActionNode/MenuSeparatorNode from public API * refactor(app): split document IO, editor session, and automation bridge Document IO: source-state, naming, writer, reload-source, reload-state, imported-document, watch-targets, save-targets Editor session: create, modules, types, accessors, computed, refs Editor canvas: loader-overlay, collaboration-awareness, context-selection, menu-actions, menu-model Automation bridge: eval, tools, exports, files, selection, RPC fallback AI/ACP: transport, map-update, permission, debug, chat effects/storage Collab: awareness, graph-bindings, yjs-sync, follow, session, types Shell keyboard: actions, bindings, clipboard, focus, nudging, raw-events, registry, reserved, shortcuts, space-tool Shell menu: app-menu, document-name, entry, files Demo: colors, effects, helpers, section builders (components, app-preview, effects, standalone, variables) — document.ts reduced from 981 to 32 lines as pure orchestrator Move app modules under src/app/ with organized domain structure: editor, document, ai, collab, shell, automation, demo, tabs * refactor(app): decompose UI components with provide/inject context Split monolithic components using Reka UI-inspired namespace folders with scoped provide/inject context — no prop drilling: - CollabPanel/ — context, avatars, share, connected, join - ColorPickerPanel/ — context, area, format, field groups, sliders - MobileHud/ — context, action toast, tool badge, file menu, presence - ProviderSettings/ — context, API key/type, endpoint, tokens, photos - Toolbar/ — actions, types, desktop, mobile, tool button, flyout - LayoutSection/ — types, auto-layout, flex, grid, padding, size, clip Properties helpers: fill-okhcl adapter, fill-label, color-style-row Menu: entry helpers, document-name rename, stale type removal * refactor(mcp): split server into focused modules - browser-rpc — WebSocket client management - mcp-sessions — session lifecycle - tool-output — response formatting - tool-schema — Zod schema generation from ToolDefs - jsx-preprocess — JSX source transformation - result — result helpers - tool-registration — MCP tool wiring - auth — API key validation - http-options — CORS/request handling - stdio-bridge — stdio transport adapter * refactor(cli): split analyze subcommands and shared helpers - Analyze subcommands: clusters, colors, spacing, typography - RPC data loading helper - Migrate imports to targeted core subpath exports * refactor(docs): split VitePress config and shared table component Config helpers: sdk-sidebar, seo, labels, sidebars, locale-theme, root-theme, locales Shared SdkDataTable component replaces duplicated table markup in SdkPropsTable, SdkEventsTable, and SdkSlotsTable Update contributing and testing docs * refactor(tauri): decompose desktop entrypoint Split lib.rs into focused service modules: - fig_container.rs — .fig archive/compression commands - fonts.rs — font cache and system font enumeration - menu.rs — native menu construction - menu_events.rs — menu event dispatch and devtools toggle - window.rs — main window show/focus lifecycle * test: share domain test factories and migrate fixtures New shared helpers: - tests/helpers/scene.ts — makeSceneGraph factory - tests/helpers/vector-network.ts — vertex/segment/network builders - tests/helpers/fig-traversal.ts — all-node collection, type counts - tests/helpers/undo.ts — undo test utilities - tests/helpers/editor-history.ts — editor history test helpers Migrate render, vector, fig-roundtrip, and undo tests to use shared factories instead of inline fixture construction * build: add structural lint rules, split vite config, update docs Structural lint (oxlint.structure.json + lint/plugin.js): - 20+ custom rules enforcing package boundaries, lifecycle patterns, naming conventions, and import discipline Vite config split: raw-markdown, canvaskit-assets, pwa, server, aliases, automation plugins Remove legacy shims and utils superseded by SDK/core modules Update AGENTS.md, CONTRIBUTING.md, eval-command docs, tsconfig * fix(vue): normalize canvas directory casing and remove duplicate export - Rename Canvas/ to canvas/ in git index to match #vue/canvas/* imports (PascalCase was correct for component primitives but canvas/ is a non-component domain directory) - Remove duplicate ./random subpath export in core package.json * fix: add #vue and #core Vite resolve aliases for dev server * refactor(core): reduce remaining large modules Split the remaining large core hotspots into cohesive domain modules while preserving public facades and behavior. - Extract scene graph types, variables, node defaults, and vector-network helpers - Decompose canvas renderer orchestration, state, paints, colors, lifecycle, labels, and delegated domain methods into renderer/ and labels/ subfolders - Split Kiwi node-change, binary variable binding, layout, RPC, vector, JSX export, clipboard, design JSX, and Figma proxy helpers - Replace collision-driven *Fn import aliases with namespace imports and enforce the pattern in lint Validation: - bun run check - bun --filter @open-pencil/vue build - bun run test:dupes * fix(app): forward color input attrs * fix(app): cover section drawing errors * fix(editor): undo option-drag duplicates * docs: document domain subfolder convention * fix(app): handle undo redo on keydown * refactor(app): dispatch shortcuts from keydown * refactor: group prefixed domain modules * refactor(app): use tinykeys for shortcuts * refactor(core): group symbol override modules * refactor(core): group fig kiwi container helper * refactor(canvas): split overlay rendering modules * refactor(vue): remove unused internal barrels * fix(app): lay out demo components before instancing * fix(app): restore demo badge spacing * perf(canvas): split scene and overlay rendering * refactor(vue): wrap wheel gesture lifecycle * fix(canvas): wait for fonts before hiding loader * docs: update unreleased changelog
2026-04-30 12:14:19 +00:00
"imports": {
test(core): move the fig round-trip suite home, and stop test imports drilling * test(core): move the fig round-trip suite into the package test home The reader change added `verifier-contracts.test.ts` under `tests/engine` and grew the migration baseline to admit it, which the testing architecture forbids: new tests go to the canonical home and the baseline only shrinks. It also started `packages/core/tests/io/formats/fig/roundtrip/`, leaving two homes for one domain. These tests drive Core's exporter, so Core's home is the canonical one. The directory moves whole — eleven files, its helpers and raw verifiers with it — and picks up the local `assert`, `traversal`, `test-utils` and fixture helpers already there. The baseline loses nine entries. * refactor(core): address test helpers by alias instead of drilling `open-pencil/no-deep-parent-relative-imports` already forbids `../../` drilling, but `lint:structure` names the directories it checks and `packages/{core,scene-graph,vue}/tests` were never added — so the 72 drilled imports in Core's tests, including the ones the round-trip move just wrote, were never seen. Core gains `#core-tests/*` beside fig's `#fig-tests/*`, registered with the architecture rules, and its tests reach their helpers through it and their source through `#core/*`. The three test directories join `lint:structure`, which also surfaced six errors they had never been checked for: four duplicated imports, an empty `noop`, and a self-assignment the test meant, now written through a named binding. Both guides state the rule, since a lint nobody can find in prose is how this went unnoticed. * fix(tools): point the heavy unit patterns at the relocated round-trip tests `HEAVY_UNIT_TEST_PATTERNS` still listed the three heavy round-trip tests under `tests/engine`. `test:unit` discovers them by directory so the move looked clean, but `--heavy-only` selects by path and silently stopped choosing them: 8 files, 52 tests, where it now runs 11 and 80.
2026-10-01 10:11:53 +00:00
"#core/*": "./src/*.ts",
"#core-tests/*": "./tests/*.ts"
Refactor architecture boundaries across core, app, and packages (#234) * refactor(core): decompose editor factory and action modules Split the monolithic editor factory and large action modules into focused domain helpers: - create.ts assembles context through bridge modules (clipboard, components, structure, undo) and delegates to graph-reads, graph-events, layout-runner, component-sync, and state factory - structure.ts delegates to group, container-wrap, auto-layout-wrap, reorder, and state-toggle helpers - selection.ts delegates to hit-test, overlays, container navigation, and read helpers - clipboard.ts delegates to subtree-history, images, export, copy, fonts, and placement helpers - shapes.ts delegates to pen actions and section-adopt - components.ts delegates to focus and instances helpers - alignment.ts delegates to flip-rotate helper - text.ts uses explicit TextEditSession for snapshot comparison New focused modules: nudge, variable-bindings, layout-mode, page-viewports, tool-registry, color-space Undo: history/position and history/snapshot helpers, hardened batch/rollback with nested batch support and configurable limit * refactor(core): split tool definitions by domain Split the monolithic tool registry into domain-specific modules: - read/ — selection, find, pages, fonts, components, nodes, query, jsx - create/ — basic shapes, components, vector, JSX render - modify/ — paint, effects, geometry, layout, state, text, update - structure/ — basic, arrange, batch, hierarchy, replace, tree - variables/ — bindings, collections, read, values - vector/ — boolean, path, export, viewport - analyze/ — colors, typography, spacing, clusters, diff, eval - describe/ — summaries, tree, roles, layout-issues - stock-photo/ — providers, requests, apply - codegen/ — component-map, tokens Split registry into core/extended tiers; refine schema and AI adapter * refactor(core): restructure kiwi codec and instance overrides Reorganize the Kiwi .fig codec into domain subdirectories: - binary/ — codec, schema, protocol - fig/ — file, import, parse (core, worker, transfer) - node-change/ — convert, export-node, serialize, plugin-data - instance-overrides/ — constraints, dsd, populate, props, resolve, symbol-overrides, symbol-props, sync, types Vendored kiwi-schema/ left isolated * refactor(core): split profiler, icons, IO, and add subpath exports Profiler: speedscope-export, capture-session, hud-controller Icons: api, svg, types, render, create-icons tool IO: format registry and subpath exports Canvas/color/text/vector: targeted cleanup Add deliberate subpath exports: random, xpath, vector, color, canvas, scene-graph, kiwi, design-jsx, io, tools, editor, layout, canvaskit, profiler, text, lint, rpc, figma-api, constants * refactor(vue): decompose canvas input, surface lifecycle, and controls Canvas surface: gl-surface, kit-loader, render-loop, resize-observer Canvas input handlers: - move: drop-target, move-snap, duplicate-drag - select: select-move, select-hover, select-hit - resize: resize-rect, resize-vector, resize-start - transform: rotation, marquee, pan, text-selection - text-edit: navigation, clipboard, textarea lifecycle - Shared: click-count, space-key, pan, pan-zoom, draw, raf-scheduler Editor composition: - commands split: actions, context, metadata, edit, selection, view - menu-model split: command-groups, builders, types - Gradient stop composable reuse in primitive root Controls: fill, layout, typography, appearance, effects, stroke, okhcl, prop-scrub, node-props, undo-batch, color-variable-binding Variables/i18n/document/export helpers Organize canvas, primitives, controls, editor, and variables into cohesive module directories with package-local import aliases Expose MenuActionNode/MenuSeparatorNode from public API * refactor(app): split document IO, editor session, and automation bridge Document IO: source-state, naming, writer, reload-source, reload-state, imported-document, watch-targets, save-targets Editor session: create, modules, types, accessors, computed, refs Editor canvas: loader-overlay, collaboration-awareness, context-selection, menu-actions, menu-model Automation bridge: eval, tools, exports, files, selection, RPC fallback AI/ACP: transport, map-update, permission, debug, chat effects/storage Collab: awareness, graph-bindings, yjs-sync, follow, session, types Shell keyboard: actions, bindings, clipboard, focus, nudging, raw-events, registry, reserved, shortcuts, space-tool Shell menu: app-menu, document-name, entry, files Demo: colors, effects, helpers, section builders (components, app-preview, effects, standalone, variables) — document.ts reduced from 981 to 32 lines as pure orchestrator Move app modules under src/app/ with organized domain structure: editor, document, ai, collab, shell, automation, demo, tabs * refactor(app): decompose UI components with provide/inject context Split monolithic components using Reka UI-inspired namespace folders with scoped provide/inject context — no prop drilling: - CollabPanel/ — context, avatars, share, connected, join - ColorPickerPanel/ — context, area, format, field groups, sliders - MobileHud/ — context, action toast, tool badge, file menu, presence - ProviderSettings/ — context, API key/type, endpoint, tokens, photos - Toolbar/ — actions, types, desktop, mobile, tool button, flyout - LayoutSection/ — types, auto-layout, flex, grid, padding, size, clip Properties helpers: fill-okhcl adapter, fill-label, color-style-row Menu: entry helpers, document-name rename, stale type removal * refactor(mcp): split server into focused modules - browser-rpc — WebSocket client management - mcp-sessions — session lifecycle - tool-output — response formatting - tool-schema — Zod schema generation from ToolDefs - jsx-preprocess — JSX source transformation - result — result helpers - tool-registration — MCP tool wiring - auth — API key validation - http-options — CORS/request handling - stdio-bridge — stdio transport adapter * refactor(cli): split analyze subcommands and shared helpers - Analyze subcommands: clusters, colors, spacing, typography - RPC data loading helper - Migrate imports to targeted core subpath exports * refactor(docs): split VitePress config and shared table component Config helpers: sdk-sidebar, seo, labels, sidebars, locale-theme, root-theme, locales Shared SdkDataTable component replaces duplicated table markup in SdkPropsTable, SdkEventsTable, and SdkSlotsTable Update contributing and testing docs * refactor(tauri): decompose desktop entrypoint Split lib.rs into focused service modules: - fig_container.rs — .fig archive/compression commands - fonts.rs — font cache and system font enumeration - menu.rs — native menu construction - menu_events.rs — menu event dispatch and devtools toggle - window.rs — main window show/focus lifecycle * test: share domain test factories and migrate fixtures New shared helpers: - tests/helpers/scene.ts — makeSceneGraph factory - tests/helpers/vector-network.ts — vertex/segment/network builders - tests/helpers/fig-traversal.ts — all-node collection, type counts - tests/helpers/undo.ts — undo test utilities - tests/helpers/editor-history.ts — editor history test helpers Migrate render, vector, fig-roundtrip, and undo tests to use shared factories instead of inline fixture construction * build: add structural lint rules, split vite config, update docs Structural lint (oxlint.structure.json + lint/plugin.js): - 20+ custom rules enforcing package boundaries, lifecycle patterns, naming conventions, and import discipline Vite config split: raw-markdown, canvaskit-assets, pwa, server, aliases, automation plugins Remove legacy shims and utils superseded by SDK/core modules Update AGENTS.md, CONTRIBUTING.md, eval-command docs, tsconfig * fix(vue): normalize canvas directory casing and remove duplicate export - Rename Canvas/ to canvas/ in git index to match #vue/canvas/* imports (PascalCase was correct for component primitives but canvas/ is a non-component domain directory) - Remove duplicate ./random subpath export in core package.json * fix: add #vue and #core Vite resolve aliases for dev server * refactor(core): reduce remaining large modules Split the remaining large core hotspots into cohesive domain modules while preserving public facades and behavior. - Extract scene graph types, variables, node defaults, and vector-network helpers - Decompose canvas renderer orchestration, state, paints, colors, lifecycle, labels, and delegated domain methods into renderer/ and labels/ subfolders - Split Kiwi node-change, binary variable binding, layout, RPC, vector, JSX export, clipboard, design JSX, and Figma proxy helpers - Replace collision-driven *Fn import aliases with namespace imports and enforce the pattern in lint Validation: - bun run check - bun --filter @open-pencil/vue build - bun run test:dupes * fix(app): forward color input attrs * fix(app): cover section drawing errors * fix(editor): undo option-drag duplicates * docs: document domain subfolder convention * fix(app): handle undo redo on keydown * refactor(app): dispatch shortcuts from keydown * refactor: group prefixed domain modules * refactor(app): use tinykeys for shortcuts * refactor(core): group symbol override modules * refactor(core): group fig kiwi container helper * refactor(canvas): split overlay rendering modules * refactor(vue): remove unused internal barrels * fix(app): lay out demo components before instancing * fix(app): restore demo badge spacing * perf(canvas): split scene and overlay rendering * refactor(vue): wrap wheel gesture lifecycle * fix(canvas): wait for fonts before hiding loader * docs: update unreleased changelog
2026-04-30 12:14:19 +00:00
},
"exports": {
"./package.json": "./package.json",
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
},
"./geometry": {
"types": "./dist/geometry/index.d.ts",
"import": "./dist/geometry/index.js",
"default": "./dist/geometry/index.js"
},
"./text": {
"types": "./dist/text/index.d.ts",
"import": "./dist/text/index.js",
"default": "./dist/text/index.js"
},
"./text/web-font/assets": {
"types": "./dist/text/web-font/assets.d.ts",
"import": "./dist/text/web-font/assets.js",
"default": "./dist/text/web-font/assets.js"
},
"./vector": {
"types": "./dist/vector/index.d.ts",
"import": "./dist/vector/index.js",
"default": "./dist/vector/index.js"
},
feat: behaviours and preview mode (#893) * feat: author behaviours on main components A main component or component set can behave as a Switch, Checkbox, Slider, or Tabs, after Reka UI's primitives. The behaviour lives in OpenPencil plugin data: boolean values bind to variant or boolean properties with the values meaning on and off, a number keeps its own range since Figma has no number property, and the control's subcomponents bind to the component's slots. A Behaviour section in the properties panel adds, binds, and removes it, each as one undo step, and flags required bindings that are missing. The canvas-only layout's pill becomes a component that preview will reuse. * feat: preview instances with behaviours on the canvas View > Preview (Cmd+Alt+Enter) puts the canvas in preview: a lone canvas switches to the canvas-only layout with a Previewing pill, and a split canvas previews on its own side. Clicking a Switch or Checkbox flips it, dragging a Slider moves its thumb and range, and clicking a Tabs trigger shows its panel. Preview keeps its state on copies of the instances it touched, in a private graph with the document's ids, and the canvas draws those copies in place of the originals, so the document, undo, autosave, and collaborators never see it. Escape or the pill leaves preview, Reset restores every control, and editing shortcuts, labels, and outlines stay off while previewing. * feat: translate behaviour and preview strings; cover preview with an e2e flow * refactor(vue): reuse VariantDefinitionControl for behaviour property options * refactor: split variant actions and preview interactions by domain Variant authoring was one 706-line closure; it is now graph queries (model), undo snapshots (history), property definition edits (definitions), and the editor facade (index). Preview interactions move into play/kinds, one module per control, registered by behaviour kind so a new kind cannot ship without its contract and interaction. Behaviour contracts are keyed by kind. In the Vue SDK, slot and variant authoring controls get their own folders beside component-props and behaviour, and the app's variant section joins slot/ and behaviour/. * refactor: keep the behaviour model in scene-graph's plugin-data registry Master now defines every OpenPencil plugin-data key in one typed registry in scene-graph. The behaviour schema registers there as a field, and the model and contracts move beside slots, exported from the package root; the @open-pencil/core/behaviours subpath is gone. * feat: interaction states and keyboard focus in preview A behaviour can bind a variant property to the default, hover, pressed, focus, and disabled states; binding it maps values named like those states. Preview switches the instance's copy to the matching variant as the pointer hovers, presses, and releases, keeps other values when the set draws the combination and falls back to rest otherwise, and skips disabled instances. Tab moves visible keyboard focus between controls, Space, Enter, arrows, Home, and End use the focused one, and Escape takes visible focus off before leaving preview. A Button kind covers controls that only have states. * feat: toggle, radio, group, progress, collapsible, and accordion behaviours Radio group, toggle group, and accordion hold their items in a slot; each item is an instance with its own behaviour, so a press inside the slot goes to the group, which turns the pressed item on and the others off through the item's own interaction. Progress shares the slider's number handling through rangeControl, and a collapsible shows and hides its content slot from its trigger, remembering its open state even when no property draws it. Tabs and groups share arrow-key navigation. * feat: text field, textarea, and number field behaviours A behaviour value can now be text, bound to a text property, so preview types into a copy of the field through the same property path the editor uses. A bound Filled value switches to the placeholder variant when the field empties. A number field keeps its own range, shows its value through a text property, and steps from its increment and decrement slots and the arrow keys. Text fields show focus from a click, and the focused control receives every key; Option still types, and only Cmd or Ctrl combinations stay shortcuts. * fix: keep behaviour bindings when saving as .fig Saving as .fig gives component properties new GUIDs, but behaviours kept the old ids in their plugin data, so every binding read as missing after reopening. The export now renames the ids behaviours bind with the same GUIDs, on its own copy of the document. * fix: let previewed controls resize layout imported from .fig Layers from a .fig keep the sizes Figma computed, and auto layout prefers them, so an opened collapsible or accordion item kept its closed height in preview. When preview shows, hides, or retypes a layer in a copy, it drops those sizes from the layer's copied ancestors so auto layout sizes them again; untouched layers keep Figma's sizes. * fix: publish behaviours and other plugin content with library assets Every OpenPencil plugin-data field now declares its role: content that exists only as plugin data (behaviours, OkHCL picks), format copies of node fields written for files, or bookkeeping about where a document or node came from. Library snapshots keep a node's content plugin data, including other plugins' entries, and drop the rest; the asset hash counts the same entries, so a behaviour-only change is offered as an update while a .fig round trip still changes nothing. * feat: name behaviour rows by meaning and create what they need The Behaviour section named every main value "Value" under a "Values" heading, and a component without matching properties left an empty picker with no way forward. Rows are now named for the control (On, Checked, Pressed, Text), rows the control needs or already uses come first, and the optional rest folds under More options; a button keeps its states in view. An empty row creates what it needs in one undo step: a text layer and text property, Off and On variants on a set, or a slot frame for a part. The missing chip names the row it means and takes you there. * fix(dom-css): position free layers, hug content, and round ellipses HTML and Tailwind export stacked the layers of frames without auto layout in block flow, wrote fixed pixel sizes for auto layout frames set to Hug and for auto-sizing text, and drew ellipses as boxes. Layers a parent does not lay out are now absolutely positioned at their coordinates inside a relative frame, hugging axes are left to the content, and ellipses get a 50% radius. * feat: run preview as live Reka UI islands over the canvas Preview simulated controls on the canvas: copies of instances, a handler per kind, its own key routing, and append-only text. It now runs them as real components. Each top-level layer that holds an instance with a behaviour becomes an island: its layers are projected to DOM through dom-css into a shadow root laid over the pane at its pan and zoom, and each behaviour mounts its Reka UI primitives on its layers, so text fields are real inputs and focus, keys, and layout are the browser's. Core's resolvePlayState shows instances in a state on a private graph, so the component's variants draw it, and controls are keyed by layer path so a variant switch keeps their DOM. The canvas leaves island layers to the islands, and the canvas play runtime and its key routing are gone. * fix: derive variant properties from Property=Value component names figma.combineAsVariants and Combine as variants only derived variant properties from slash-separated names, so components named as Figma names variants, such as State=On, Size=Large, became a set with no properties. Both now derive each named property and its values, after the slash form. * feat: script and tool access to behaviours by name Behaviour contracts follow Reka UI's anatomy: tabs keep their triggers in the list slot and their content panels in a panels slot, and a slot of repeated parts names the Reka part of its children. A behaviour spec names component properties and slots instead of ids and resolves to the stored behaviour and back, with errors that list what the component has. Scripts get an `openpencil` global next to `figma`, in the Figma API's style: setBehaviour, getBehaviour with bindValue, bindPart, states, and missing, behaviourKinds, and createSlot. The eval tool, the CLI, and app automation compile scripts through one compileScript, so the CLI now returns the last expression as the others do. MCP and AI chat get set_behaviour, get_behaviour, and create_slot. * feat: write controls in design JSX with Reka UI's element names `<Switch.Root modelValue="State">` renders a main component, or a set when its children are variants, that behaves as a switch, and `<Switch.Thumb>` the slot that draws its thumb, one slot across the set's variants. Inputs become the text property of a field, tab triggers and panels go in their List and Panels slots, and a group's items are `<RadioGroup.Item of={…} />` instances in its Items slot. JSX export writes components with behaviours the same way, so they render back unchanged. The authoring reference documents controls, and the codegen and chat prompts now include it verbatim instead of dedenting its code examples. * chore: format the CLI export test * docs: document slots, behaviours, preview, and the openpencil API The components guide covers slots, behaviours, and preview with its shortcut; scripting covers the openpencil global and eval's last- expression result; the MCP and AI chat pages list the new tools; the features overview, README, and roadmap mention working controls. The chat prompt says how to build a control, and the codegen prompt builds components with behaviours on their Reka UI primitives. * chore: format the eval CLI test * docs: explain behaviours and preview islands, and guide the openpencil API A development page explains the behaviour model, the four authoring surfaces, how preview islands turn a control's state into live Reka UI components, and how to add a kind; the architecture page links it. The Core guide sets the rules for OpenPencilAPI: Figma-only `figma`, OpenPencil features on `openpencil` in the same style, one compileScript, names over ids, and docs with every member. Package READMEs mention the openpencil global, PlayIslands, Reka-named JSX, and the behaviour model. Design JSX's behaviour modules move into a behaviours folder instead of a suffixed sibling. * refactor: center pasted layers through translate centerNodesAt repeated translate's loop, which test:dupes reports on master too. * fix: validate behaviour ranges and guess on and off by name A number value now needs max above min and a positive step: the schema, specs, and the panel reject a range a slider cannot step through. Binding a variant property guesses on and off by value name, as specs do, and a boolean property gets no on/off pair. Part bindings are read through partBinding, a replaced document restarts preview from its designed state, and the e2e preview shortcut uses ControlOrMeta. * feat: make the Behaviour section say what to do next A slider's range fields now carry inline Min, Max, Step, and Start labels. States offers Add state variants, which adds a Default, Hover, Pressed, Focus, and Disabled variant and binds them; Add Off and On variants and Add state variants turn a lone main component into a component set first, and a part's slot can be added to a set, in every variant under one slot id. Rows that could do nothing are gone: no empty pickers and no hints to combine variants by hand, and an unbound Disabled is left to the states. A warning line names what is still needed and replaces the missing chip, and the Switch's main value is called Checked. * fix: keep each slot to one part and keep creating slots at hand A slot draws one part, so the Behaviour section no longer offers a slot another part uses, and specs (the openpencil API, tools, and JSX) reject binding one slot to two parts. A part's picker keeps an action to add a new slot in its footer, so adding the first slot no longer hides it for the other parts.
2026-10-06 13:23:05 +00:00
"./openpencil-api": {
"types": "./dist/openpencil-api/index.d.ts",
"import": "./dist/openpencil-api/index.js",
"default": "./dist/openpencil-api/index.js"
},
"./figma-api": {
"types": "./dist/figma-api/index.d.ts",
"import": "./dist/figma-api/index.js",
"default": "./dist/figma-api/index.js"
},
"./icons": {
"types": "./dist/icons/index.d.ts",
"import": "./dist/icons/index.js",
"default": "./dist/icons/index.js"
},
"./canvas": {
"types": "./dist/canvas/index.d.ts",
"import": "./dist/canvas/index.js",
"default": "./dist/canvas/index.js"
},
"./design-jsx": {
"types": "./dist/design-jsx/index.d.ts",
"import": "./dist/design-jsx/index.js",
"default": "./dist/design-jsx/index.js"
},
"./editor": {
"types": "./dist/editor/index.d.ts",
"import": "./dist/editor/index.js",
"default": "./dist/editor/index.js"
},
"./tools": {
"types": "./dist/tools/index.d.ts",
"import": "./dist/tools/index.js",
"default": "./dist/tools/index.js"
},
"./profiler": {
"types": "./dist/profiler/index.d.ts",
"import": "./dist/profiler/index.js",
"default": "./dist/profiler/index.js"
},
"./rpc": {
"types": "./dist/rpc/index.d.ts",
"import": "./dist/rpc/index.js",
"default": "./dist/rpc/index.js"
},
"./library": {
"bun": "./src/library/index.ts",
"types": "./dist/library/index.d.ts",
"import": "./dist/library/index.js",
"default": "./dist/library/index.js"
},
"./lint": {
"types": "./dist/lint/index.d.ts",
"import": "./dist/lint/index.js",
"default": "./dist/lint/index.js"
2026-03-27 22:58:05 +00:00
},
"./io": {
"types": "./dist/io/index.d.ts",
"import": "./dist/io/index.js",
"default": "./dist/io/index.js"
},
"./io/formats/fig": {
"types": "./dist/io/formats/fig/index.d.ts",
"import": "./dist/io/formats/fig/index.js",
"default": "./dist/io/formats/fig/index.js"
},
"./io/formats/raster": {
"types": "./dist/io/formats/raster/index.d.ts",
"import": "./dist/io/formats/raster/index.js",
"default": "./dist/io/formats/raster/index.js"
},
"./io/formats/svg": {
"types": "./dist/io/formats/svg/index.d.ts",
"import": "./dist/io/formats/svg/index.js",
"default": "./dist/io/formats/svg/index.js"
},
"./kiwi": {
"types": "./dist/kiwi/index.d.ts",
"import": "./dist/kiwi/index.js",
"default": "./dist/kiwi/index.js"
},
"./clipboard": {
"types": "./dist/clipboard.d.ts",
"import": "./dist/clipboard.js",
"default": "./dist/clipboard.js"
},
"./constants": {
"types": "./dist/constants.d.ts",
"import": "./dist/constants.js",
"default": "./dist/constants.js"
},
Refactor architecture boundaries across core, app, and packages (#234) * refactor(core): decompose editor factory and action modules Split the monolithic editor factory and large action modules into focused domain helpers: - create.ts assembles context through bridge modules (clipboard, components, structure, undo) and delegates to graph-reads, graph-events, layout-runner, component-sync, and state factory - structure.ts delegates to group, container-wrap, auto-layout-wrap, reorder, and state-toggle helpers - selection.ts delegates to hit-test, overlays, container navigation, and read helpers - clipboard.ts delegates to subtree-history, images, export, copy, fonts, and placement helpers - shapes.ts delegates to pen actions and section-adopt - components.ts delegates to focus and instances helpers - alignment.ts delegates to flip-rotate helper - text.ts uses explicit TextEditSession for snapshot comparison New focused modules: nudge, variable-bindings, layout-mode, page-viewports, tool-registry, color-space Undo: history/position and history/snapshot helpers, hardened batch/rollback with nested batch support and configurable limit * refactor(core): split tool definitions by domain Split the monolithic tool registry into domain-specific modules: - read/ — selection, find, pages, fonts, components, nodes, query, jsx - create/ — basic shapes, components, vector, JSX render - modify/ — paint, effects, geometry, layout, state, text, update - structure/ — basic, arrange, batch, hierarchy, replace, tree - variables/ — bindings, collections, read, values - vector/ — boolean, path, export, viewport - analyze/ — colors, typography, spacing, clusters, diff, eval - describe/ — summaries, tree, roles, layout-issues - stock-photo/ — providers, requests, apply - codegen/ — component-map, tokens Split registry into core/extended tiers; refine schema and AI adapter * refactor(core): restructure kiwi codec and instance overrides Reorganize the Kiwi .fig codec into domain subdirectories: - binary/ — codec, schema, protocol - fig/ — file, import, parse (core, worker, transfer) - node-change/ — convert, export-node, serialize, plugin-data - instance-overrides/ — constraints, dsd, populate, props, resolve, symbol-overrides, symbol-props, sync, types Vendored kiwi-schema/ left isolated * refactor(core): split profiler, icons, IO, and add subpath exports Profiler: speedscope-export, capture-session, hud-controller Icons: api, svg, types, render, create-icons tool IO: format registry and subpath exports Canvas/color/text/vector: targeted cleanup Add deliberate subpath exports: random, xpath, vector, color, canvas, scene-graph, kiwi, design-jsx, io, tools, editor, layout, canvaskit, profiler, text, lint, rpc, figma-api, constants * refactor(vue): decompose canvas input, surface lifecycle, and controls Canvas surface: gl-surface, kit-loader, render-loop, resize-observer Canvas input handlers: - move: drop-target, move-snap, duplicate-drag - select: select-move, select-hover, select-hit - resize: resize-rect, resize-vector, resize-start - transform: rotation, marquee, pan, text-selection - text-edit: navigation, clipboard, textarea lifecycle - Shared: click-count, space-key, pan, pan-zoom, draw, raf-scheduler Editor composition: - commands split: actions, context, metadata, edit, selection, view - menu-model split: command-groups, builders, types - Gradient stop composable reuse in primitive root Controls: fill, layout, typography, appearance, effects, stroke, okhcl, prop-scrub, node-props, undo-batch, color-variable-binding Variables/i18n/document/export helpers Organize canvas, primitives, controls, editor, and variables into cohesive module directories with package-local import aliases Expose MenuActionNode/MenuSeparatorNode from public API * refactor(app): split document IO, editor session, and automation bridge Document IO: source-state, naming, writer, reload-source, reload-state, imported-document, watch-targets, save-targets Editor session: create, modules, types, accessors, computed, refs Editor canvas: loader-overlay, collaboration-awareness, context-selection, menu-actions, menu-model Automation bridge: eval, tools, exports, files, selection, RPC fallback AI/ACP: transport, map-update, permission, debug, chat effects/storage Collab: awareness, graph-bindings, yjs-sync, follow, session, types Shell keyboard: actions, bindings, clipboard, focus, nudging, raw-events, registry, reserved, shortcuts, space-tool Shell menu: app-menu, document-name, entry, files Demo: colors, effects, helpers, section builders (components, app-preview, effects, standalone, variables) — document.ts reduced from 981 to 32 lines as pure orchestrator Move app modules under src/app/ with organized domain structure: editor, document, ai, collab, shell, automation, demo, tabs * refactor(app): decompose UI components with provide/inject context Split monolithic components using Reka UI-inspired namespace folders with scoped provide/inject context — no prop drilling: - CollabPanel/ — context, avatars, share, connected, join - ColorPickerPanel/ — context, area, format, field groups, sliders - MobileHud/ — context, action toast, tool badge, file menu, presence - ProviderSettings/ — context, API key/type, endpoint, tokens, photos - Toolbar/ — actions, types, desktop, mobile, tool button, flyout - LayoutSection/ — types, auto-layout, flex, grid, padding, size, clip Properties helpers: fill-okhcl adapter, fill-label, color-style-row Menu: entry helpers, document-name rename, stale type removal * refactor(mcp): split server into focused modules - browser-rpc — WebSocket client management - mcp-sessions — session lifecycle - tool-output — response formatting - tool-schema — Zod schema generation from ToolDefs - jsx-preprocess — JSX source transformation - result — result helpers - tool-registration — MCP tool wiring - auth — API key validation - http-options — CORS/request handling - stdio-bridge — stdio transport adapter * refactor(cli): split analyze subcommands and shared helpers - Analyze subcommands: clusters, colors, spacing, typography - RPC data loading helper - Migrate imports to targeted core subpath exports * refactor(docs): split VitePress config and shared table component Config helpers: sdk-sidebar, seo, labels, sidebars, locale-theme, root-theme, locales Shared SdkDataTable component replaces duplicated table markup in SdkPropsTable, SdkEventsTable, and SdkSlotsTable Update contributing and testing docs * refactor(tauri): decompose desktop entrypoint Split lib.rs into focused service modules: - fig_container.rs — .fig archive/compression commands - fonts.rs — font cache and system font enumeration - menu.rs — native menu construction - menu_events.rs — menu event dispatch and devtools toggle - window.rs — main window show/focus lifecycle * test: share domain test factories and migrate fixtures New shared helpers: - tests/helpers/scene.ts — makeSceneGraph factory - tests/helpers/vector-network.ts — vertex/segment/network builders - tests/helpers/fig-traversal.ts — all-node collection, type counts - tests/helpers/undo.ts — undo test utilities - tests/helpers/editor-history.ts — editor history test helpers Migrate render, vector, fig-roundtrip, and undo tests to use shared factories instead of inline fixture construction * build: add structural lint rules, split vite config, update docs Structural lint (oxlint.structure.json + lint/plugin.js): - 20+ custom rules enforcing package boundaries, lifecycle patterns, naming conventions, and import discipline Vite config split: raw-markdown, canvaskit-assets, pwa, server, aliases, automation plugins Remove legacy shims and utils superseded by SDK/core modules Update AGENTS.md, CONTRIBUTING.md, eval-command docs, tsconfig * fix(vue): normalize canvas directory casing and remove duplicate export - Rename Canvas/ to canvas/ in git index to match #vue/canvas/* imports (PascalCase was correct for component primitives but canvas/ is a non-component domain directory) - Remove duplicate ./random subpath export in core package.json * fix: add #vue and #core Vite resolve aliases for dev server * refactor(core): reduce remaining large modules Split the remaining large core hotspots into cohesive domain modules while preserving public facades and behavior. - Extract scene graph types, variables, node defaults, and vector-network helpers - Decompose canvas renderer orchestration, state, paints, colors, lifecycle, labels, and delegated domain methods into renderer/ and labels/ subfolders - Split Kiwi node-change, binary variable binding, layout, RPC, vector, JSX export, clipboard, design JSX, and Figma proxy helpers - Replace collision-driven *Fn import aliases with namespace imports and enforce the pattern in lint Validation: - bun run check - bun --filter @open-pencil/vue build - bun run test:dupes * fix(app): forward color input attrs * fix(app): cover section drawing errors * fix(editor): undo option-drag duplicates * docs: document domain subfolder convention * fix(app): handle undo redo on keydown * refactor(app): dispatch shortcuts from keydown * refactor: group prefixed domain modules * refactor(app): use tinykeys for shortcuts * refactor(core): group symbol override modules * refactor(core): group fig kiwi container helper * refactor(canvas): split overlay rendering modules * refactor(vue): remove unused internal barrels * fix(app): lay out demo components before instancing * fix(app): restore demo badge spacing * perf(canvas): split scene and overlay rendering * refactor(vue): wrap wheel gesture lifecycle * fix(canvas): wait for fonts before hiding loader * docs: update unreleased changelog
2026-04-30 12:14:19 +00:00
"./xpath": {
"types": "./dist/xpath.d.ts",
"import": "./dist/xpath.js",
"default": "./dist/xpath.js"
Refactor architecture boundaries across core, app, and packages (#234) * refactor(core): decompose editor factory and action modules Split the monolithic editor factory and large action modules into focused domain helpers: - create.ts assembles context through bridge modules (clipboard, components, structure, undo) and delegates to graph-reads, graph-events, layout-runner, component-sync, and state factory - structure.ts delegates to group, container-wrap, auto-layout-wrap, reorder, and state-toggle helpers - selection.ts delegates to hit-test, overlays, container navigation, and read helpers - clipboard.ts delegates to subtree-history, images, export, copy, fonts, and placement helpers - shapes.ts delegates to pen actions and section-adopt - components.ts delegates to focus and instances helpers - alignment.ts delegates to flip-rotate helper - text.ts uses explicit TextEditSession for snapshot comparison New focused modules: nudge, variable-bindings, layout-mode, page-viewports, tool-registry, color-space Undo: history/position and history/snapshot helpers, hardened batch/rollback with nested batch support and configurable limit * refactor(core): split tool definitions by domain Split the monolithic tool registry into domain-specific modules: - read/ — selection, find, pages, fonts, components, nodes, query, jsx - create/ — basic shapes, components, vector, JSX render - modify/ — paint, effects, geometry, layout, state, text, update - structure/ — basic, arrange, batch, hierarchy, replace, tree - variables/ — bindings, collections, read, values - vector/ — boolean, path, export, viewport - analyze/ — colors, typography, spacing, clusters, diff, eval - describe/ — summaries, tree, roles, layout-issues - stock-photo/ — providers, requests, apply - codegen/ — component-map, tokens Split registry into core/extended tiers; refine schema and AI adapter * refactor(core): restructure kiwi codec and instance overrides Reorganize the Kiwi .fig codec into domain subdirectories: - binary/ — codec, schema, protocol - fig/ — file, import, parse (core, worker, transfer) - node-change/ — convert, export-node, serialize, plugin-data - instance-overrides/ — constraints, dsd, populate, props, resolve, symbol-overrides, symbol-props, sync, types Vendored kiwi-schema/ left isolated * refactor(core): split profiler, icons, IO, and add subpath exports Profiler: speedscope-export, capture-session, hud-controller Icons: api, svg, types, render, create-icons tool IO: format registry and subpath exports Canvas/color/text/vector: targeted cleanup Add deliberate subpath exports: random, xpath, vector, color, canvas, scene-graph, kiwi, design-jsx, io, tools, editor, layout, canvaskit, profiler, text, lint, rpc, figma-api, constants * refactor(vue): decompose canvas input, surface lifecycle, and controls Canvas surface: gl-surface, kit-loader, render-loop, resize-observer Canvas input handlers: - move: drop-target, move-snap, duplicate-drag - select: select-move, select-hover, select-hit - resize: resize-rect, resize-vector, resize-start - transform: rotation, marquee, pan, text-selection - text-edit: navigation, clipboard, textarea lifecycle - Shared: click-count, space-key, pan, pan-zoom, draw, raf-scheduler Editor composition: - commands split: actions, context, metadata, edit, selection, view - menu-model split: command-groups, builders, types - Gradient stop composable reuse in primitive root Controls: fill, layout, typography, appearance, effects, stroke, okhcl, prop-scrub, node-props, undo-batch, color-variable-binding Variables/i18n/document/export helpers Organize canvas, primitives, controls, editor, and variables into cohesive module directories with package-local import aliases Expose MenuActionNode/MenuSeparatorNode from public API * refactor(app): split document IO, editor session, and automation bridge Document IO: source-state, naming, writer, reload-source, reload-state, imported-document, watch-targets, save-targets Editor session: create, modules, types, accessors, computed, refs Editor canvas: loader-overlay, collaboration-awareness, context-selection, menu-actions, menu-model Automation bridge: eval, tools, exports, files, selection, RPC fallback AI/ACP: transport, map-update, permission, debug, chat effects/storage Collab: awareness, graph-bindings, yjs-sync, follow, session, types Shell keyboard: actions, bindings, clipboard, focus, nudging, raw-events, registry, reserved, shortcuts, space-tool Shell menu: app-menu, document-name, entry, files Demo: colors, effects, helpers, section builders (components, app-preview, effects, standalone, variables) — document.ts reduced from 981 to 32 lines as pure orchestrator Move app modules under src/app/ with organized domain structure: editor, document, ai, collab, shell, automation, demo, tabs * refactor(app): decompose UI components with provide/inject context Split monolithic components using Reka UI-inspired namespace folders with scoped provide/inject context — no prop drilling: - CollabPanel/ — context, avatars, share, connected, join - ColorPickerPanel/ — context, area, format, field groups, sliders - MobileHud/ — context, action toast, tool badge, file menu, presence - ProviderSettings/ — context, API key/type, endpoint, tokens, photos - Toolbar/ — actions, types, desktop, mobile, tool button, flyout - LayoutSection/ — types, auto-layout, flex, grid, padding, size, clip Properties helpers: fill-okhcl adapter, fill-label, color-style-row Menu: entry helpers, document-name rename, stale type removal * refactor(mcp): split server into focused modules - browser-rpc — WebSocket client management - mcp-sessions — session lifecycle - tool-output — response formatting - tool-schema — Zod schema generation from ToolDefs - jsx-preprocess — JSX source transformation - result — result helpers - tool-registration — MCP tool wiring - auth — API key validation - http-options — CORS/request handling - stdio-bridge — stdio transport adapter * refactor(cli): split analyze subcommands and shared helpers - Analyze subcommands: clusters, colors, spacing, typography - RPC data loading helper - Migrate imports to targeted core subpath exports * refactor(docs): split VitePress config and shared table component Config helpers: sdk-sidebar, seo, labels, sidebars, locale-theme, root-theme, locales Shared SdkDataTable component replaces duplicated table markup in SdkPropsTable, SdkEventsTable, and SdkSlotsTable Update contributing and testing docs * refactor(tauri): decompose desktop entrypoint Split lib.rs into focused service modules: - fig_container.rs — .fig archive/compression commands - fonts.rs — font cache and system font enumeration - menu.rs — native menu construction - menu_events.rs — menu event dispatch and devtools toggle - window.rs — main window show/focus lifecycle * test: share domain test factories and migrate fixtures New shared helpers: - tests/helpers/scene.ts — makeSceneGraph factory - tests/helpers/vector-network.ts — vertex/segment/network builders - tests/helpers/fig-traversal.ts — all-node collection, type counts - tests/helpers/undo.ts — undo test utilities - tests/helpers/editor-history.ts — editor history test helpers Migrate render, vector, fig-roundtrip, and undo tests to use shared factories instead of inline fixture construction * build: add structural lint rules, split vite config, update docs Structural lint (oxlint.structure.json + lint/plugin.js): - 20+ custom rules enforcing package boundaries, lifecycle patterns, naming conventions, and import discipline Vite config split: raw-markdown, canvaskit-assets, pwa, server, aliases, automation plugins Remove legacy shims and utils superseded by SDK/core modules Update AGENTS.md, CONTRIBUTING.md, eval-command docs, tsconfig * fix(vue): normalize canvas directory casing and remove duplicate export - Rename Canvas/ to canvas/ in git index to match #vue/canvas/* imports (PascalCase was correct for component primitives but canvas/ is a non-component domain directory) - Remove duplicate ./random subpath export in core package.json * fix: add #vue and #core Vite resolve aliases for dev server * refactor(core): reduce remaining large modules Split the remaining large core hotspots into cohesive domain modules while preserving public facades and behavior. - Extract scene graph types, variables, node defaults, and vector-network helpers - Decompose canvas renderer orchestration, state, paints, colors, lifecycle, labels, and delegated domain methods into renderer/ and labels/ subfolders - Split Kiwi node-change, binary variable binding, layout, RPC, vector, JSX export, clipboard, design JSX, and Figma proxy helpers - Replace collision-driven *Fn import aliases with namespace imports and enforce the pattern in lint Validation: - bun run check - bun --filter @open-pencil/vue build - bun run test:dupes * fix(app): forward color input attrs * fix(app): cover section drawing errors * fix(editor): undo option-drag duplicates * docs: document domain subfolder convention * fix(app): handle undo redo on keydown * refactor(app): dispatch shortcuts from keydown * refactor: group prefixed domain modules * refactor(app): use tinykeys for shortcuts * refactor(core): group symbol override modules * refactor(core): group fig kiwi container helper * refactor(canvas): split overlay rendering modules * refactor(vue): remove unused internal barrels * fix(app): lay out demo components before instancing * fix(app): restore demo badge spacing * perf(canvas): split scene and overlay rendering * refactor(vue): wrap wheel gesture lifecycle * fix(canvas): wait for fonts before hiding loader * docs: update unreleased changelog
2026-04-30 12:14:19 +00:00
},
"./canvaskit": {
"types": "./dist/canvaskit.d.ts",
"import": "./dist/canvaskit.js",
"default": "./dist/canvaskit.js"
},
"./layout": {
"types": "./dist/layout.d.ts",
"import": "./dist/layout.js",
"default": "./dist/layout.js"
}
},
"publishConfig": {
"access": "public",
"provenance": true
},
"scripts": {
"build": "bunx tsdown --config tsdown.config.ts",
"prepublishOnly": "bun run build",
"test": "bun test tests",
"typecheck": "bunx tsgo --noEmit -p tsconfig.test.json"
},
"dependencies": {
"@chenglou/pretext": "^0.0.7",
"@iconify/utils": "^3.1.4",
"@open-pencil/design-jsx": "workspace:*",
refactor!: move shared primitives below dom-css and core (#771) * refactor!: move shared primitives below dom-css and core dom-css depended on core for color conversion, base64 helpers, text direction, and web-font assets, so core could not use dom-css and every caller special-cased HTML and Tailwind output. Color conversion and management, base64 helpers, and text/layout direction now live in scene-graph under `color`, `bytes`, and `text-direction`. dom-css takes web-font resolution as an injected `fonts` option and owns the font face types, so it depends only on scene-graph and core can depend on it. BREAKING CHANGE: `@open-pencil/core/color` and `@open-pencil/core/bytes` are removed, and the direction helpers are no longer exported from `@open-pencil/core/text`; import them from `@open-pencil/scene-graph` subpaths. `exportHTMLBundle` takes a font resolver in `fonts` instead of `'assets'`. * fix(tools): import color parsing from scene-graph in visual bisect * fix(mcp): declare the scene-graph dependency MCP imports `@open-pencil/scene-graph/bytes` since base64 helpers moved there, but only reached scene-graph through core, so isolated installs and package checks depended on transitive resolution. * refactor!: use js-base64 directly instead of a base64 wrapper Base64 helpers had moved into scene-graph only to sit below dom-css, but they are a thin wrapper over js-base64 and unrelated to the graph; fig already called js-base64 directly. Callers use js-base64 and check `isValid` where input comes from outside (clipboard, imported HTML, tool arguments, the plugin API). A new `open-pencil/no-hand-rolled-base64` lint rule rejects atob, btoa, and Buffer Base64 conversions, and AGENTS.md records the convention. BREAKING CHANGE: `@open-pencil/core/bytes` is removed; use `js-base64`. * fix(dom-css): keep images with invalid Base64 inline in HTML export `exportHTMLBundle` accepts documents parsed from outside HTML, and js-base64 drops characters it cannot decode, so extracting an invalid image data URL wrote different bytes. Such images now stay inline.
2026-09-26 07:39:11 +00:00
"@open-pencil/dom-css": "workspace:*",
"@open-pencil/fig": "workspace:*",
"@open-pencil/kiwi": "workspace:*",
"@open-pencil/pen": "workspace:*",
"@open-pencil/scene-graph": "workspace:*",
build: update dependencies (#873) * build: update dependencies Update the AI SDK providers, Vue, Reka UI, Valibot, Zod, es-toolkit, CodeMirror, Storybook, Playwright, Hono and other dependencies to their current releases, consistently across workspaces. The Tauri plugin packages must match their Rust crates, and the new plugin crates require Tauri 2.12, so Cargo.lock, @tauri-apps/api and the Tauri CLI move to 2.12 as well. * build(harness): update the AI SDK harness packages @ai-sdk/harness 1.0.74 pinned ai 7.0.67, so the workspace carried a second copy of ai next to the root one; 1.0.138 depends on the same ai release. The Pi adapter no longer takes a model: HarnessAgent does. The settings were spread from untyped records, so the compiler could not reject the stale key and the chosen model would have been dropped; they are plain literals now. PiAuthOptions is now PiAuthenticationMode, and auth accepts an environment record. Pass the gateway key that way instead of writing it into the process-wide environment while a session is created. Derive the thinking level from the adapter's settings, which adds 'max'. * build: hold vue-tsc at 3.3.11 vue-tsc 3.3.12 no longer sees a v-slot binding inside a component that also has an event listener, so check:vue reports "Cannot find name 'control'" in MCPConnectionEditor and ProfileEditor. 3.3.11 checks them cleanly. * fix(ai): keep retryability for provider errors reported mid-stream From ai 7.0.80 a provider error after the response stream starts is a StreamProviderError rather than an APICallError, so classifyAIChatError lost its isRetryable. * feat(desktop): accept updates only when signed for their version Tauri CLI 2.12 records the app version in each updater signature, and updater 2.13 checks it against the version latest.json announces. With requireSignedVersion it also rejects signatures that carry no version, so a tampered manifest cannot pair a newer version number with an older, still validly signed bundle. Release assembly now fails when a signature does not name the version being released, instead of shipping one that installed apps would reject. * docs: note the dependency update's security fixes in the changelog * feat(ai): recommend the latest models The provider packages now know Claude Sonnet 5.5 and Opus 5.5 and the GPT-6 series. Make Sonnet 5.5 and GPT-6.1 Sol the defaults, list Opus 5.5, Fable 5.1, GPT-6 Astra and GPT-6 Luna, and replace the two free OpenRouter models that OpenRouter no longer serves. * build: align the fig package's valibot with the workspace
2026-10-04 12:48:24 +00:00
"@tauri-apps/api": "^2.12.1",
"@valibot/to-json-schema": "^1.8.0",
build: update dependencies (#873) * build: update dependencies Update the AI SDK providers, Vue, Reka UI, Valibot, Zod, es-toolkit, CodeMirror, Storybook, Playwright, Hono and other dependencies to their current releases, consistently across workspaces. The Tauri plugin packages must match their Rust crates, and the new plugin crates require Tauri 2.12, so Cargo.lock, @tauri-apps/api and the Tauri CLI move to 2.12 as well. * build(harness): update the AI SDK harness packages @ai-sdk/harness 1.0.74 pinned ai 7.0.67, so the workspace carried a second copy of ai next to the root one; 1.0.138 depends on the same ai release. The Pi adapter no longer takes a model: HarnessAgent does. The settings were spread from untyped records, so the compiler could not reject the stale key and the chosen model would have been dropped; they are plain literals now. PiAuthOptions is now PiAuthenticationMode, and auth accepts an environment record. Pass the gateway key that way instead of writing it into the process-wide environment while a session is created. Derive the thinking level from the adapter's settings, which adds 'max'. * build: hold vue-tsc at 3.3.11 vue-tsc 3.3.12 no longer sees a v-slot binding inside a component that also has an event listener, so check:vue reports "Cannot find name 'control'" in MCPConnectionEditor and ProfileEditor. 3.3.11 checks them cleanly. * fix(ai): keep retryability for provider errors reported mid-stream From ai 7.0.80 a provider error after the response stream starts is a StreamProviderError rather than an APICallError, so classifyAIChatError lost its isRetryable. * feat(desktop): accept updates only when signed for their version Tauri CLI 2.12 records the app version in each updater signature, and updater 2.13 checks it against the version latest.json announces. With requireSignedVersion it also rejects signatures that carry no version, so a tampered manifest cannot pair a newer version number with an older, still validly signed bundle. Release assembly now fails when a signature does not name the version being released, instead of shipping one that installed apps would reject. * docs: note the dependency update's security fixes in the changelog * feat(ai): recommend the latest models The provider packages now know Claude Sonnet 5.5 and Opus 5.5 and the GPT-6 series. Make Sonnet 5.5 and GPT-6.1 Sol the defaults, list Opus 5.5, Fable 5.1, GPT-6 Astra and GPT-6 Luna, and replace the two free OpenRouter models that OpenRouter no longer serves. * build: align the fig package's valibot with the workspace
2026-10-04 12:48:24 +00:00
"@xmldom/xmldom": "^0.9.12",
"acorn": "^8.18.0",
"canvaskit-wasm": "^0.41.1",
"culori": "^4.0.2",
"destr": "^2.0.5",
"diff": "^8.0.4",
build: update dependencies (#873) * build: update dependencies Update the AI SDK providers, Vue, Reka UI, Valibot, Zod, es-toolkit, CodeMirror, Storybook, Playwright, Hono and other dependencies to their current releases, consistently across workspaces. The Tauri plugin packages must match their Rust crates, and the new plugin crates require Tauri 2.12, so Cargo.lock, @tauri-apps/api and the Tauri CLI move to 2.12 as well. * build(harness): update the AI SDK harness packages @ai-sdk/harness 1.0.74 pinned ai 7.0.67, so the workspace carried a second copy of ai next to the root one; 1.0.138 depends on the same ai release. The Pi adapter no longer takes a model: HarnessAgent does. The settings were spread from untyped records, so the compiler could not reject the stale key and the chosen model would have been dropped; they are plain literals now. PiAuthOptions is now PiAuthenticationMode, and auth accepts an environment record. Pass the gateway key that way instead of writing it into the process-wide environment while a session is created. Derive the thinking level from the adapter's settings, which adds 'max'. * build: hold vue-tsc at 3.3.11 vue-tsc 3.3.12 no longer sees a v-slot binding inside a component that also has an event listener, so check:vue reports "Cannot find name 'control'" in MCPConnectionEditor and ProfileEditor. 3.3.11 checks them cleanly. * fix(ai): keep retryability for provider errors reported mid-stream From ai 7.0.80 a provider error after the response stream starts is a StreamProviderError rather than an APICallError, so classifyAIChatError lost its isRetryable. * feat(desktop): accept updates only when signed for their version Tauri CLI 2.12 records the app version in each updater signature, and updater 2.13 checks it against the version latest.json announces. With requireSignedVersion it also rejects signatures that carry no version, so a tampered manifest cannot pair a newer version number with an older, still validly signed bundle. Release assembly now fails when a signature does not name the version being released, instead of shipping one that installed apps would reject. * docs: note the dependency update's security fixes in the changelog * feat(ai): recommend the latest models The provider packages now know Claude Sonnet 5.5 and Opus 5.5 and the GPT-6 series. Make Sonnet 5.5 and GPT-6.1 Sol the defaults, list Opus 5.5, Fable 5.1, GPT-6 Astra and GPT-6 Luna, and replace the two free OpenRouter models that OpenRouter no longer serves. * build: align the fig package's valibot with the workspace
2026-10-04 12:48:24 +00:00
"es-toolkit": "^1.52.0",
"fflate": "^0.8.3",
"fontoxpath": "^3.34.0",
"fzstd": "^0.1.1",
"js-base64": "^3.9.3",
fix(tools): evaluate calc expressions without expr-eval (#753) * fix(tools): evaluate calc expressions without expr-eval expr-eval has an unpatched critical advisory for code execution through toJSFunction(), which compiles expressions with new Function (GHSA-q9v2-7m5w-4693). The advisory covers every published version, so `bun run check:audit` fails on every branch and `bun audit fix` has nothing to upgrade to. The calc tool only ever called evaluate(), so the advisory's own vector was not reachable, but the dependency stays flagged and the evaluator's surface was far wider than the tool documents: random(), factorials, trigonometry, constants, strings, array indexing, property access and statement sequences all evaluated, while the documented ** operator did not parse at all, since expr-eval spells power as ^. Replace it with a recursive-descent evaluator for exactly the documented grammar. It compiles nothing, reaches no host object, and fixes **, which is right-associative and binds tighter than a leading sign, so -2 ** 2 is -4 as in ordinary notation. Non-finite results are still reported by the tool rather than the evaluator, so 1 / 0 keeps its "Produced Infinity" message. The tool had no tests; both the evaluator and the tool's JSON-array and error-reporting paths are covered now. * refactor(tools): parse calc expressions with jsep Replace the hand-written tokenizer and recursive-descent parser with jsep, a maintained zero-dependency expression parser with no advisory history, and keep only the tree walk: an allowlist of node types, arithmetic operators and the documented functions. Parsing, where the vulnerabilities in this class of library live, is no longer ours to maintain. Behaviour follows the parser rather than the previous hand-written precedence, so a leading sign now binds tighter than '**' and '-2 ** 2' is 4; the tests pin that alongside right-associativity. Parse errors keep jsep's own wording and character positions. * fix(tools): reject inherited names and fold long calc argument lists Two findings from review of this branch. The function lookup used `in`, so an inherited key such as `constructor(1)` passed the guard and then failed while destructuring a missing arity, reporting a TypeError instead of an unknown function; it now uses Object.hasOwn. min and max spread their arguments, which overflows the call stack on V8 at roughly 125k arguments, so they fold instead. Both paths are covered by tests.
2026-09-24 21:44:46 +00:00
"jsep": "^1.4.0",
feat: add visual diff and patch apply tools and openpencil diff (#810) * feat(core): add visual diff and patch apply tools diff_visual renders two nodes at one scale through the existing raster export, compares them with pixelmatch, and returns the diff PNG with the changed ratio and region in source-node coordinates. It takes export_image's scale and maxEdge inputs. FigmaAPI gains a CanvasKit-backed raster codec and a pageId export option, so the app and headless CLI decode pixels and render nodes off the current page. diff_apply applies diff_create and diff_show patches through the Figma API, validates every node before changing any, and supports dryRun and force. diff_show now simulates changes on a detached copy with the same property code. One serializer and parser back all three. diffDocuments compares two documents page by page by name path. Image tool results now reach models as media with their metadata as text, for any tool rather than export_image alone. diff_create, diff_jsx, and diff_visual join the default AI tool set, and the diff tools are no longer hidden from WebMCP. * feat(cli): add diff commands and agent diff guidance openpencil diff create, jsx, show, apply, and visual run the Core diff tools on a file or the running app; apply writes back with --write or --output like eval. diff files compares two documents page by page and exits 1 when they differ. The chat prompt asks the agent to edit in place and to verify risky edits against a reference copy with diff_jsx, diff_create, and diff_visual. The skill, CLI reference, MCP tool table, and a new Comparing Designs page document the commands and tools. * feat(core): diff and patch node trees as JSX attributes diff_create, diff_show, diff_apply, and diffDocuments used a hand-rolled `key: value` property format that covered about fifteen properties, matched children by name path, and could not see moves. Nodes are now projected to the attributes the JSX export prints, and jsondiffpatch matches children (by ID or by name path) and detects moves. Patches list `-`/`+` attribute lines per node plus moved, added, and removed children. diff_apply checks every hunk first, applies attribute changes through the renderer's prop handling, and changes only the fields an attribute moves, so IDs, instance links, and other state survive. diff_show takes JSX attributes instead of a JSON props object. design-jsx gains sceneNodeAttributes, parseJSXAttributes, and jsxNodeFields for this, and the export round-trip property table is shared so every case is also diffed and applied. `diff files` loads its documents in order so node IDs, and so its patches, are deterministic. * fix(core): keep diff_apply atomic and diff files honest about differences - Added nodes render before anything else changes; if one fails, for example on a missing component, the rendered ones are deleted and nothing else is committed. - A hunk with an attribute the renderer ignores fails instead of reporting "unchanged". - diffDocuments reports `changed` from page statuses, and a page only one document has gets its status but no patch, since patches do not add or remove pages. diff files uses it, so an added empty page no longer reads as a match. - diff files rejects a --page neither document has and a --depth that is not a non-negative integer, exiting 2; diff_create's depth is validated the same way.
2026-10-03 17:00:13 +00:00
"jsondiffpatch": "^0.7.6",
"jspdf": "^4.2.1",
"nanoevents": "^9.1.0",
"ofetch": "^1.5.1",
"opentype.js": "^2.0.0",
feat: add visual diff and patch apply tools and openpencil diff (#810) * feat(core): add visual diff and patch apply tools diff_visual renders two nodes at one scale through the existing raster export, compares them with pixelmatch, and returns the diff PNG with the changed ratio and region in source-node coordinates. It takes export_image's scale and maxEdge inputs. FigmaAPI gains a CanvasKit-backed raster codec and a pageId export option, so the app and headless CLI decode pixels and render nodes off the current page. diff_apply applies diff_create and diff_show patches through the Figma API, validates every node before changing any, and supports dryRun and force. diff_show now simulates changes on a detached copy with the same property code. One serializer and parser back all three. diffDocuments compares two documents page by page by name path. Image tool results now reach models as media with their metadata as text, for any tool rather than export_image alone. diff_create, diff_jsx, and diff_visual join the default AI tool set, and the diff tools are no longer hidden from WebMCP. * feat(cli): add diff commands and agent diff guidance openpencil diff create, jsx, show, apply, and visual run the Core diff tools on a file or the running app; apply writes back with --write or --output like eval. diff files compares two documents page by page and exits 1 when they differ. The chat prompt asks the agent to edit in place and to verify risky edits against a reference copy with diff_jsx, diff_create, and diff_visual. The skill, CLI reference, MCP tool table, and a new Comparing Designs page document the commands and tools. * feat(core): diff and patch node trees as JSX attributes diff_create, diff_show, diff_apply, and diffDocuments used a hand-rolled `key: value` property format that covered about fifteen properties, matched children by name path, and could not see moves. Nodes are now projected to the attributes the JSX export prints, and jsondiffpatch matches children (by ID or by name path) and detects moves. Patches list `-`/`+` attribute lines per node plus moved, added, and removed children. diff_apply checks every hunk first, applies attribute changes through the renderer's prop handling, and changes only the fields an attribute moves, so IDs, instance links, and other state survive. diff_show takes JSX attributes instead of a JSON props object. design-jsx gains sceneNodeAttributes, parseJSXAttributes, and jsxNodeFields for this, and the export round-trip property table is shared so every case is also diffed and applied. `diff files` loads its documents in order so node IDs, and so its patches, are deterministic. * fix(core): keep diff_apply atomic and diff files honest about differences - Added nodes render before anything else changes; if one fails, for example on a missing component, the rendered ones are deleted and nothing else is committed. - A hunk with an attribute the renderer ignores fails instead of reporting "unchanged". - diffDocuments reports `changed` from page statuses, and a page only one document has gets its status but no patch, since patches do not add or remove pages. diff files uses it, so an added empty page no longer reads as a match. - diff files rejects a --page neither document has and a --depth that is not a non-negative integer, exiting 2; diff_create's depth is validated the same way.
2026-10-03 17:00:13 +00:00
"pixelmatch": "^7.2.0",
"pptxgenjs": "^4.0.1",
perf(canvas): rebuild navigation rendering (#591) * perf(canvas): add traced navigation benchmarks - Record and replay timestamped pan and zoom gestures through DOM and CDP input paths\n- Correlate input, viewport, render, long-task, and retained-backing events in Chromium traces\n- Report frame pacing, latency, jump, anchor drift, and crisp-settlement metrics * perf(canvas): stabilize navigation comparisons - Separate low-overhead metric runs from optional CPU-profile traces\n- Warm scenarios before recording and use a consistent SwiftShader browser configuration\n- Add a canonical momentum-pan reversal gesture alongside pinch reversal * fix(canvas): require hardware GPU navigation benchmarks - Run macOS performance captures through Metal-backed ANGLE and reject accidental SwiftShader fallback\n- Record the GL renderer and reserve software GPU mode for portable correctness smoke runs * perf(canvas): cache shadow rasters for crisp backing - Rasterize local drop and inner shadows only while constructing retained scene backing\n- Bound native image memory and invalidate cached entries with node and renderer lifecycle changes\n- Quantize zoom-aware raster resolution and reuse nearby scales without lowering normal scene quality * test(canvas): verify retained shadow raster fidelity - Compare settled retained-backing shadow output with direct CanvasKit rendering\n- Keep backdrop blur on the picture fallback and exercise graph-driven cache invalidation\n- Cover updates, deletion, and reparenting through actual SceneGraph events * perf(canvas): benchmark real FIG fixtures - Serve exact local fixture bytes through an isolated Playwright route for production preview runs\n- Wait for document loading and page population before zooming to fit and recording navigation\n- Record the resolved fixture path in benchmark environment artifacts * fix(canvas): preserve nested effect subtree pictures - Keep deeply nested shadow documents on one retained subtree picture instead of exploding them into per-node image draws\n- Restrict shadow raster acceleration to effect-bearing page children\n- Cover nested shadow fallback and restore gold-preview FIG pinch performance to master levels * refactor(canvas): share recorded wheel sample type * perf(canvas): defer backing settlement across zoom reversals - Track explicit navigation phases and gesture generations instead of inferring idle from viewport timing\n- Cancel or defer retained backing construction while pan, zoom, momentum, or tentative settlement is active\n- Add a repeated short-pause pinch reversal fixture based on the user trace * perf(canvas): index bounded render chunks - Split oversized painter subtrees into self-paint and bounded descendant chunks without dropping container visuals\n- Bulk-load chunk visual bounds into RBush for selective world-space queries\n- Cover bounded updates and gold-preview build/query complexity before tile rendering consumes the index * refactor(canvas): namespace render chunk coverage * perf(canvas): model chunk paint context - Preserve ancestor transform and clip dependencies for independently renderable chunks\n- Keep opacity, blend, blur, and mask isolation subtrees atomic until command-level splitting exists\n- Report oversized atomic chunks and lock gold-preview to bounded painter units * perf(canvas): record pixel-correct render chunks - Record interruptible chunks in world coordinates with ancestor transforms, clips, and chunk-local culling bounds\n- Draw opacity, blend, blur, and mask isolation chunks directly into destination surfaces in painter order\n- Compare composited chunk output with direct CanvasKit rendering instead of relaxing visual thresholds * perf(canvas): render selective world tiles - Map world regions to fixed 256-device-pixel tile targets and quantized sharpness levels\n- Query only intersecting render chunks and preserve atomic destination compositing\n- Match multi-tile CanvasKit output against direct rendering and measure gold-preview tile cost * perf(canvas): cache chunk pictures across tiles - Reuse world-space chunk command pictures for every intersecting tile\n- Pool 256-pixel tile surfaces and expose allocation, draw, flush, and snapshot timings\n- Keep expensive atomic foreground blur visible as an over-budget scheduler constraint * perf(canvas): schedule cached tile rendering - Bound tile images with an LRU cache and reuse pooled CanvasKit surfaces\n- Plan mandatory holes, stale visible refreshes, and overscan by navigation and content generation\n- Stop jobs at a strict deadline while reporting fallbacks, stale work, overruns, and over-budget effects * perf(canvas): integrate progressive tiled rendering - Keep retained scene output as the interaction fallback while exact tiles refine only after navigation becomes idle - Centralize runtime URL flags and pass renderer selection through the typed Vue canvas API - Replace benchmark sleeps with explicit mode-aware renderer settlement and report exact tiled coverage - Preserve bounded scheduler metrics, generation cancellation, native resource cleanup, and shared visual-bounds logic * refactor(app): centralize runtime query configuration - Parse collaboration, recent-files, benchmark, presentation, and renderer flags in one typed app module - Remove ad hoc URL parsing from workspace and collaboration runtime consumers - Cover supported values and production-safe defaults without adding a repository lint rule * fix(canvas): replace fallback pixels with exact tiles - Render opaque page-background tile cells and install them with source replacement instead of double-compositing translucent scene content - Exercise the live progressive controller against direct rendering across masks, effects, blend isolation, images, fallback text, transforms, and clipping - Preserve the bounded reversal path with zero Long Tasks and exact settlement near 128 ms on gold-preview.fig * perf(canvas): invalidate tiled content selectively - Index chunk dependencies across contained nodes and transform or clipping ancestors - Re-record affected chunk pictures and invalidate tiles intersecting old or new visual bounds - Advance unaffected cached tiles to the new scene generation instead of rebuilding the full chunk index and tile cache - Keep structural graph mutations on the safe full-rebuild path and cover selective refresh end to end * perf(canvas): bound atomic blur tile refresh - Render atomic blur chunks with tile-local isolation bounds and blur halos instead of replaying full-subtree layers - Keep content refresh behind the retained fallback, cap GPU submissions to four tile jobs per frame, and adapt estimates from measured work - Preserve large-radius CPU over-budget visibility while preventing Metal-backed refresh bursts and deferred GPU overload - Add deterministic node-mutation benchmarks and summarize scheduler throughput, job duration, overruns, and exact content settlement * perf(canvas): cancel obsolete tile refresh generations - Count and report queued jobs removed by content or navigation generation changes - Add deterministic mutation-then-reversal benchmark support without sleeps - Assert exact tile work remains suspended during navigation and resumes for the final viewport - Summarize cancellation alongside scheduler throughput, overruns, and settlement metrics * test(canvas): cover live tiled blur settlement - Load gold-preview.fig through the real tiled canvas surface and wait on explicit renderer settlement - Commit the settled radius-210 large-blur browser snapshot - Replay the canonical zoom reversal during refresh and require byte-identical final canvas convergence * fix(canvas): harden renderer resource lifecycle - Release tiled surfaces, images, pictures, and queued work across surface, font, graph, page, structure, and renderer lifecycle boundaries - Restore pooled canvas, viewport, and backing state through exception-safe native recording and raster paths - Rebuild tiled chunk topology only when isolation requirements actually change, preserving selective blur mutation performance - Document deterministic active-renderer settlement and add lifecycle, graph replacement, cache failure, and surface replacement regressions * test(canvas): remove source-matching renderer claims - Delete the autopsy suite that inferred runtime correctness from source text, regexes, line placement, and symbol counts - Keep renderer ordering, cache cleanup, effect behavior, and pixel fidelity covered by executable behavioral and lifecycle tests * perf(canvas): present retained backing during tiled navigation - Profile production reversal traces and attribute tiled p95 cost to GPU command-buffer flushes from full-scene fallback replay and tile presentation - Use the retained backing as the moving fallback while tile scheduling and cached lookup remain allocation-free - Defer tile image presentation until idle and expose visible versus presented tile counts in navigation telemetry - Reduce tiled reversal render p95 from about 8ms to 0.3ms while preserving exact idle replacement and visual parity * perf(canvas): prioritize visible tile settlement - Profile per-tile allocation, draw, flush, snapshot, and chunk costs through scheduler telemetry - Defer overscan until all visible exact tiles are covered - Replace the four-job idle cap with a higher safety ceiling while the measured five-millisecond deadline controls cheap work - Reduce mutation-plus-reversal exact settlement from about 272ms to 160ms without Long Tasks, overruns, or over-budget jobs * refactor(canvas): clarify renderer lifecycle boundaries - Extract retained backing state types and navigation preview timing\n- Isolate tiled scheduler telemetry from frame orchestration\n- Document settlement and CanvasKit ownership invariants\n- Preserve hot drawing loops, budgets, cache limits, and rendering decisions * fix(canvas): preserve current label rendering Retain the merged paragraph-label cache lifecycle and substituted-font readiness while reconstructing the renderer stack on current master. * test(canvas): keep tile benchmark assertions deterministic Keep performance timing in benchmark telemetry while asserting structural tile selectivity and cache behavior in CI. * feat(canvas): expose experimental tiled rendering - Persist retained or tiled canvas mode in General settings\n- Keep retained rendering as the default and apply changes after reload\n- Preserve URL overrides for deterministic benchmarks and support reproduction * refactor(app): centralize renderer preference state Expose renderer override provenance from runtime configuration and keep the settings control's derived state separate from its explicit persistence action. * refactor(app): share settings layout anatomy Reuse slot-based section headers and bordered groups while keeping each settings control row explicit. * fix(canvas): harden tiled renderer boundaries - Bound low-zoom tile planning and handle failed tile surface allocation\n- Preserve effect raster dependencies, runtime-safe clocks, and navigation timing contracts\n- Keep benchmarks deterministic, backward compatible, and accurately localized * fix(canvas): invalidate dependent node pictures Track first-child shadow dependencies for retained node pictures so child geometry updates cannot leave stale parent shadows.
2026-08-31 10:39:40 +00:00
"rbush": "^4.0.1",
Multi-provider AI, sucrase JSX, Figma zoom shortcuts (#72) * Add multi-provider AI support (Anthropic, OpenAI, Google AI, OpenAI-compatible) - Add AI_PROVIDERS registry with per-provider model lists, key placeholders, and URLs - Refactor use-chat composable: provider factory creates the right AI SDK model - Per-provider API key storage in localStorage with automatic legacy migration - New ProviderSetup.vue replaces APIKeySetup.vue with provider selector - New ProviderSettings.vue popover accessible from gear icon in chat input - OpenAI-compatible provider with custom base URL and model ID fields - Install @ai-sdk/anthropic and @ai-sdk/google dependencies - Update E2E tests for new provider setup flow * Fix reactivity, key masking, missing model ID field, and chat reset on model change - Use ref instead of computed for apiKey — computed getter over localStorage wasn't triggering reactivity when the key was set - Load stored key for new provider in providerId watcher - Reset chat on modelId and customModelId change, not just provider switch - Add custom model ID field to ProviderSetup.vue for OpenAI-compatible - Simplify ProviderSettings key field — empty input with contextual placeholder instead of fragile dot-masking that broke on partial edits - Use data-test-id locator for model selector in E2E test * Use useLocalStorage from vueuse instead of manual ref + watch + localStorage Replaces 5 hand-rolled ref/watch/localStorage sync pairs with useLocalStorage. API key uses a computed storage key that rebinds when the provider changes. * Use useLocalStorage for collab name persistence * Review fixes: changelog placement, remove dead class, cursor-pointer * Extract ProviderSelect component and uiInput helper - ProviderSelect.vue: shared select dropdown for AI providers - ui/input.ts: shared input styling (sm/md sizes) - Remove 7 duplicated input class strings across chat components * Use uppercase acronyms: keyURL, customBaseURL, supportsCustomBaseURL * Match select dropdown width to trigger via --reka-select-trigger-width Move min-w-[var(--reka-select-trigger-width)] into selectContent base style so all selects get it by default. Remove per-component overrides. * Uppercase acronyms in variable names, improve setup form layout - providerID, modelID, customModelID, setAPIKey, AIProviderID - Keep apiKey lowercase at start (standard JS convention) - Compact setup form: single column, full-width Connect button - Fix grammar: 'a OpenRouter' → 'an OpenRouter' - Shorter promo text * Allow text selection in chat panel * Fix chat E2E test: Save → Connect button text * Disable mermaid in chat markdown renderer Alias mermaid and beautiful-mermaid to empty shims in Vite config, preventing vue-stream-markdown from attempting to load them. * Interleave text and tool calls in chat messages Render message parts in order instead of grouping all tool calls first then all text. Use SDK's isToolUIPart/isTextUIPart/getToolName instead of custom type guards. Fix error state: output-error, not error. * Implement figma.viewport.scrollAndZoomIntoView() Figma Plugin API method that centers the viewport on given nodes. Reuses the same bounding box logic as the viewport_zoom_to_fit tool. * Catch tool execution errors and return them to the AI Instead of crashing with an unhandled exception, tool errors are caught and returned as { error: message } so the AI can retry or explain the failure. UI detects error outputs and shows them in red with the error message when expanded. * Replace esbuild with sucrase for JSX transform Sucrase is a pure JS transform (201 KB / 46 KB gzip) that works in both Node/Bun and the browser. Replaces esbuild (13 MB WASM) which only worked in Node/Bun. - buildComponent() and renderJSX() are now synchronous - render tool works in browser AI chat (no more 'esbuild required') - Handles full JS expressions (map, ternaries, Array.from, etc.) * Update system prompt to prioritize render tool with JSX Document available tags, props, layout, text, and sizing options. Instruct the AI to use full JS expressions in JSX for complex layouts. * Fix zoom shortcuts to match Figma Cmd+0: Zoom to 100% (was incorrectly mapped to Zoom to fit) Cmd+1: Zoom to fit Cmd+2: Zoom to selection Shift+1 / Shift+2: same as Cmd+1 / Cmd+2 Add zoomTo100() and zoomToSelection() to editor store. Refactor zoomToFit() to use shared zoomToBounds() helper. * Refactor keyboard shortcuts to useMagicKeys Replace manual keydown handler with VueUse useMagicKeys + whenever for declarative shortcut registration. - mod() helper for cross-platform Meta/Control shortcuts - plain() helper for modifier-free keys - Proper modifier exclusion (⌘G vs ⌘⇧G no longer conflict) - Add E2E tests: duplicate, zoom (⌘0/⌘1/⌘2/⇧1/⇧2), auto-layout (⇧A) - All 26 keyboard shortcut tests pass * Fix scrollAndZoomIntoView to actually zoom Match Figma Plugin API behavior (equivalent to Shift-1): compute zoom level that fits all nodes with padding, capped at 100%. Previously only set center without adjusting zoom.
2026-03-08 19:05:18 +00:00
"sucrase": "^3.35.1",
2026-08-17 09:00:01 +00:00
"svg-path-properties": "^2.0.2",
build: update dependencies (#873) * build: update dependencies Update the AI SDK providers, Vue, Reka UI, Valibot, Zod, es-toolkit, CodeMirror, Storybook, Playwright, Hono and other dependencies to their current releases, consistently across workspaces. The Tauri plugin packages must match their Rust crates, and the new plugin crates require Tauri 2.12, so Cargo.lock, @tauri-apps/api and the Tauri CLI move to 2.12 as well. * build(harness): update the AI SDK harness packages @ai-sdk/harness 1.0.74 pinned ai 7.0.67, so the workspace carried a second copy of ai next to the root one; 1.0.138 depends on the same ai release. The Pi adapter no longer takes a model: HarnessAgent does. The settings were spread from untyped records, so the compiler could not reject the stale key and the chosen model would have been dropped; they are plain literals now. PiAuthOptions is now PiAuthenticationMode, and auth accepts an environment record. Pass the gateway key that way instead of writing it into the process-wide environment while a session is created. Derive the thinking level from the adapter's settings, which adds 'max'. * build: hold vue-tsc at 3.3.11 vue-tsc 3.3.12 no longer sees a v-slot binding inside a component that also has an event listener, so check:vue reports "Cannot find name 'control'" in MCPConnectionEditor and ProfileEditor. 3.3.11 checks them cleanly. * fix(ai): keep retryability for provider errors reported mid-stream From ai 7.0.80 a provider error after the response stream starts is a StreamProviderError rather than an APICallError, so classifyAIChatError lost its isRetryable. * feat(desktop): accept updates only when signed for their version Tauri CLI 2.12 records the app version in each updater signature, and updater 2.13 checks it against the version latest.json announces. With requireSignedVersion it also rejects signatures that carry no version, so a tampered manifest cannot pair a newer version number with an older, still validly signed bundle. Release assembly now fails when a signature does not name the version being released, instead of shipping one that installed apps would reject. * docs: note the dependency update's security fixes in the changelog * feat(ai): recommend the latest models The provider packages now know Claude Sonnet 5.5 and Opus 5.5 and the GPT-6 series. Make Sonnet 5.5 and GPT-6.1 Sol the defaults, list Opus 5.5, Fable 5.1, GPT-6 Astra and GPT-6 Luna, and replace the two free OpenRouter models that OpenRouter no longer serves. * build: align the fig package's valibot with the workspace
2026-10-04 12:48:24 +00:00
"svg2pdf.js": "^2.8.1",
"svgpath": "^2.6.0",
"twirlwind": "^0.4.0",
"unifont": "0.7.4",
build: update dependencies (#873) * build: update dependencies Update the AI SDK providers, Vue, Reka UI, Valibot, Zod, es-toolkit, CodeMirror, Storybook, Playwright, Hono and other dependencies to their current releases, consistently across workspaces. The Tauri plugin packages must match their Rust crates, and the new plugin crates require Tauri 2.12, so Cargo.lock, @tauri-apps/api and the Tauri CLI move to 2.12 as well. * build(harness): update the AI SDK harness packages @ai-sdk/harness 1.0.74 pinned ai 7.0.67, so the workspace carried a second copy of ai next to the root one; 1.0.138 depends on the same ai release. The Pi adapter no longer takes a model: HarnessAgent does. The settings were spread from untyped records, so the compiler could not reject the stale key and the chosen model would have been dropped; they are plain literals now. PiAuthOptions is now PiAuthenticationMode, and auth accepts an environment record. Pass the gateway key that way instead of writing it into the process-wide environment while a session is created. Derive the thinking level from the adapter's settings, which adds 'max'. * build: hold vue-tsc at 3.3.11 vue-tsc 3.3.12 no longer sees a v-slot binding inside a component that also has an event listener, so check:vue reports "Cannot find name 'control'" in MCPConnectionEditor and ProfileEditor. 3.3.11 checks them cleanly. * fix(ai): keep retryability for provider errors reported mid-stream From ai 7.0.80 a provider error after the response stream starts is a StreamProviderError rather than an APICallError, so classifyAIChatError lost its isRetryable. * feat(desktop): accept updates only when signed for their version Tauri CLI 2.12 records the app version in each updater signature, and updater 2.13 checks it against the version latest.json announces. With requireSignedVersion it also rejects signatures that carry no version, so a tampered manifest cannot pair a newer version number with an older, still validly signed bundle. Release assembly now fails when a signature does not name the version being released, instead of shipping one that installed apps would reject. * docs: note the dependency update's security fixes in the changelog * feat(ai): recommend the latest models The provider packages now know Claude Sonnet 5.5 and Opus 5.5 and the GPT-6 series. Make Sonnet 5.5 and GPT-6.1 Sol the defaults, list Opus 5.5, Fable 5.1, GPT-6 Astra and GPT-6 Luna, and replace the two free OpenRouter models that OpenRouter no longer serves. * build: align the fig package's valibot with the workspace
2026-10-04 12:48:24 +00:00
"valibot": "^1.5.0",
"yoga-layout": "npm:@open-pencil/yoga-layout@3.3.0-grid.3"
},
"devDependencies": {
"@types/bun": "^1.3.14",
"@types/culori": "^4.0.1",
"@types/diff": "^8.0.0",
"@types/opentype.js": "^1.3.10",
perf(canvas): rebuild navigation rendering (#591) * perf(canvas): add traced navigation benchmarks - Record and replay timestamped pan and zoom gestures through DOM and CDP input paths\n- Correlate input, viewport, render, long-task, and retained-backing events in Chromium traces\n- Report frame pacing, latency, jump, anchor drift, and crisp-settlement metrics * perf(canvas): stabilize navigation comparisons - Separate low-overhead metric runs from optional CPU-profile traces\n- Warm scenarios before recording and use a consistent SwiftShader browser configuration\n- Add a canonical momentum-pan reversal gesture alongside pinch reversal * fix(canvas): require hardware GPU navigation benchmarks - Run macOS performance captures through Metal-backed ANGLE and reject accidental SwiftShader fallback\n- Record the GL renderer and reserve software GPU mode for portable correctness smoke runs * perf(canvas): cache shadow rasters for crisp backing - Rasterize local drop and inner shadows only while constructing retained scene backing\n- Bound native image memory and invalidate cached entries with node and renderer lifecycle changes\n- Quantize zoom-aware raster resolution and reuse nearby scales without lowering normal scene quality * test(canvas): verify retained shadow raster fidelity - Compare settled retained-backing shadow output with direct CanvasKit rendering\n- Keep backdrop blur on the picture fallback and exercise graph-driven cache invalidation\n- Cover updates, deletion, and reparenting through actual SceneGraph events * perf(canvas): benchmark real FIG fixtures - Serve exact local fixture bytes through an isolated Playwright route for production preview runs\n- Wait for document loading and page population before zooming to fit and recording navigation\n- Record the resolved fixture path in benchmark environment artifacts * fix(canvas): preserve nested effect subtree pictures - Keep deeply nested shadow documents on one retained subtree picture instead of exploding them into per-node image draws\n- Restrict shadow raster acceleration to effect-bearing page children\n- Cover nested shadow fallback and restore gold-preview FIG pinch performance to master levels * refactor(canvas): share recorded wheel sample type * perf(canvas): defer backing settlement across zoom reversals - Track explicit navigation phases and gesture generations instead of inferring idle from viewport timing\n- Cancel or defer retained backing construction while pan, zoom, momentum, or tentative settlement is active\n- Add a repeated short-pause pinch reversal fixture based on the user trace * perf(canvas): index bounded render chunks - Split oversized painter subtrees into self-paint and bounded descendant chunks without dropping container visuals\n- Bulk-load chunk visual bounds into RBush for selective world-space queries\n- Cover bounded updates and gold-preview build/query complexity before tile rendering consumes the index * refactor(canvas): namespace render chunk coverage * perf(canvas): model chunk paint context - Preserve ancestor transform and clip dependencies for independently renderable chunks\n- Keep opacity, blend, blur, and mask isolation subtrees atomic until command-level splitting exists\n- Report oversized atomic chunks and lock gold-preview to bounded painter units * perf(canvas): record pixel-correct render chunks - Record interruptible chunks in world coordinates with ancestor transforms, clips, and chunk-local culling bounds\n- Draw opacity, blend, blur, and mask isolation chunks directly into destination surfaces in painter order\n- Compare composited chunk output with direct CanvasKit rendering instead of relaxing visual thresholds * perf(canvas): render selective world tiles - Map world regions to fixed 256-device-pixel tile targets and quantized sharpness levels\n- Query only intersecting render chunks and preserve atomic destination compositing\n- Match multi-tile CanvasKit output against direct rendering and measure gold-preview tile cost * perf(canvas): cache chunk pictures across tiles - Reuse world-space chunk command pictures for every intersecting tile\n- Pool 256-pixel tile surfaces and expose allocation, draw, flush, and snapshot timings\n- Keep expensive atomic foreground blur visible as an over-budget scheduler constraint * perf(canvas): schedule cached tile rendering - Bound tile images with an LRU cache and reuse pooled CanvasKit surfaces\n- Plan mandatory holes, stale visible refreshes, and overscan by navigation and content generation\n- Stop jobs at a strict deadline while reporting fallbacks, stale work, overruns, and over-budget effects * perf(canvas): integrate progressive tiled rendering - Keep retained scene output as the interaction fallback while exact tiles refine only after navigation becomes idle - Centralize runtime URL flags and pass renderer selection through the typed Vue canvas API - Replace benchmark sleeps with explicit mode-aware renderer settlement and report exact tiled coverage - Preserve bounded scheduler metrics, generation cancellation, native resource cleanup, and shared visual-bounds logic * refactor(app): centralize runtime query configuration - Parse collaboration, recent-files, benchmark, presentation, and renderer flags in one typed app module - Remove ad hoc URL parsing from workspace and collaboration runtime consumers - Cover supported values and production-safe defaults without adding a repository lint rule * fix(canvas): replace fallback pixels with exact tiles - Render opaque page-background tile cells and install them with source replacement instead of double-compositing translucent scene content - Exercise the live progressive controller against direct rendering across masks, effects, blend isolation, images, fallback text, transforms, and clipping - Preserve the bounded reversal path with zero Long Tasks and exact settlement near 128 ms on gold-preview.fig * perf(canvas): invalidate tiled content selectively - Index chunk dependencies across contained nodes and transform or clipping ancestors - Re-record affected chunk pictures and invalidate tiles intersecting old or new visual bounds - Advance unaffected cached tiles to the new scene generation instead of rebuilding the full chunk index and tile cache - Keep structural graph mutations on the safe full-rebuild path and cover selective refresh end to end * perf(canvas): bound atomic blur tile refresh - Render atomic blur chunks with tile-local isolation bounds and blur halos instead of replaying full-subtree layers - Keep content refresh behind the retained fallback, cap GPU submissions to four tile jobs per frame, and adapt estimates from measured work - Preserve large-radius CPU over-budget visibility while preventing Metal-backed refresh bursts and deferred GPU overload - Add deterministic node-mutation benchmarks and summarize scheduler throughput, job duration, overruns, and exact content settlement * perf(canvas): cancel obsolete tile refresh generations - Count and report queued jobs removed by content or navigation generation changes - Add deterministic mutation-then-reversal benchmark support without sleeps - Assert exact tile work remains suspended during navigation and resumes for the final viewport - Summarize cancellation alongside scheduler throughput, overruns, and settlement metrics * test(canvas): cover live tiled blur settlement - Load gold-preview.fig through the real tiled canvas surface and wait on explicit renderer settlement - Commit the settled radius-210 large-blur browser snapshot - Replay the canonical zoom reversal during refresh and require byte-identical final canvas convergence * fix(canvas): harden renderer resource lifecycle - Release tiled surfaces, images, pictures, and queued work across surface, font, graph, page, structure, and renderer lifecycle boundaries - Restore pooled canvas, viewport, and backing state through exception-safe native recording and raster paths - Rebuild tiled chunk topology only when isolation requirements actually change, preserving selective blur mutation performance - Document deterministic active-renderer settlement and add lifecycle, graph replacement, cache failure, and surface replacement regressions * test(canvas): remove source-matching renderer claims - Delete the autopsy suite that inferred runtime correctness from source text, regexes, line placement, and symbol counts - Keep renderer ordering, cache cleanup, effect behavior, and pixel fidelity covered by executable behavioral and lifecycle tests * perf(canvas): present retained backing during tiled navigation - Profile production reversal traces and attribute tiled p95 cost to GPU command-buffer flushes from full-scene fallback replay and tile presentation - Use the retained backing as the moving fallback while tile scheduling and cached lookup remain allocation-free - Defer tile image presentation until idle and expose visible versus presented tile counts in navigation telemetry - Reduce tiled reversal render p95 from about 8ms to 0.3ms while preserving exact idle replacement and visual parity * perf(canvas): prioritize visible tile settlement - Profile per-tile allocation, draw, flush, snapshot, and chunk costs through scheduler telemetry - Defer overscan until all visible exact tiles are covered - Replace the four-job idle cap with a higher safety ceiling while the measured five-millisecond deadline controls cheap work - Reduce mutation-plus-reversal exact settlement from about 272ms to 160ms without Long Tasks, overruns, or over-budget jobs * refactor(canvas): clarify renderer lifecycle boundaries - Extract retained backing state types and navigation preview timing\n- Isolate tiled scheduler telemetry from frame orchestration\n- Document settlement and CanvasKit ownership invariants\n- Preserve hot drawing loops, budgets, cache limits, and rendering decisions * fix(canvas): preserve current label rendering Retain the merged paragraph-label cache lifecycle and substituted-font readiness while reconstructing the renderer stack on current master. * test(canvas): keep tile benchmark assertions deterministic Keep performance timing in benchmark telemetry while asserting structural tile selectivity and cache behavior in CI. * feat(canvas): expose experimental tiled rendering - Persist retained or tiled canvas mode in General settings\n- Keep retained rendering as the default and apply changes after reload\n- Preserve URL overrides for deterministic benchmarks and support reproduction * refactor(app): centralize renderer preference state Expose renderer override provenance from runtime configuration and keep the settings control's derived state separate from its explicit persistence action. * refactor(app): share settings layout anatomy Reuse slot-based section headers and bordered groups while keeping each settings control row explicit. * fix(canvas): harden tiled renderer boundaries - Bound low-zoom tile planning and handle failed tile surface allocation\n- Preserve effect raster dependencies, runtime-safe clocks, and navigation timing contracts\n- Keep benchmarks deterministic, backward compatible, and accurately localized * fix(canvas): invalidate dependent node pictures Track first-child shadow dependencies for retained node pictures so child geometry updates cannot leave stale parent shadows.
2026-08-31 10:39:40 +00:00
"@types/rbush": "^4.0.0",
2026-09-30 17:18:20 +00:00
"typescript": "~5.8.3",
"unplugin-raw": "^0.7.0"
}
}