* 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.
- Replace the fork-era Markdown integration with Comark and an explicit Shiki extension\n- Centralize OpenPencil theming, parser lifecycle, controls, and URL hardening\n- Remove Mermaid stubs and bundled math or diagram dependencies\n- Address contextual composer review findings and extend browser coverage\n\nCo-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
- Add a typed, modular custom Oxlint rule package with direct regression coverage
- Replace complex conditional object spreads with explicit construction across the repository
- Preserve all existing custom rule registrations and diagnostic behavior
* 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.
* refactor(app): isolate system clipboard adapters
- Split browser and Tauri clipboard behavior into focused adapters\n- Inject browser clipboard capabilities into unit-testable operations\n- Remove navigator and document mutation from headless clipboard tests
* refactor(app): delegate browser clipboard fallbacks
- Use copy-to-clipboard for modern rich MIME writes and execCommand fallback\n- Keep OpenPencil-specific HTML and plain-text payload construction at the adapter boundary\n- Remove hand-rolled browser capability and selection handling
* test(clipboard): verify rich browser menu round-trip
- Exercise copy from the browser Edit menu under a user gesture\n- Verify text/html and text/plain ClipboardItem formats\n- Paste the system clipboard payload back into the canvas
* refactor(clipboard): reduce adapter surface
- Expose only command dispatch and the injectable system clipboard contract\n- Keep browser and Tauri copy/paste operations private to their adapters\n- Rename the in-memory DataTransfer fallback and share design HTML recognition
* fix(clipboard): harden format and fallback handling
- Require complete OpenPencil or Figma clipboard markers\n- Await browser writes so adapter failures resolve false\n- Write plain-only Tauri payloads as text and reject unrelated clipboard text
* fix(clipboard): reject unrelated current browser data
* fix(clipboard): bind fallbacks to copied selection
- Match cached rich HTML to the current Tauri plain-text fallback\n- Preserve nodes when selection changes during an asynchronous cut\n- Reject unrelated current browser HTML before consulting memory
* fix(clipboard): reuse the shared memory payload type
* fix(clipboard): scan design markers linearly
* fix(clipboard): distinguish unavailable and empty reads
* style(clipboard): use includes for marker closure
* test(clipboard): avoid wall-clock marker assertions
* refactor(canvas): adopt immutable CanvasKit paths
- Upgrade CanvasKit to 0.41.1 across app, Core, CLI, and Vue peers
- Build mutable geometry with PathBuilder and detach immutable paths for drawing
- Replace in-place strokes, transforms, and boolean operations with immutable results
- Update renderer mocks and path construction tests for the new API
* test(canvas): model immutable path ownership
- Return detached path instances from CanvasKit builder mocks
- Assert shadow ring and combined path disposal
- Preserve recorded vector operations across ownership transfer
* fix(build): align CanvasKit workspace versions
- Upgrade direct model chat providers and transports to AI SDK 7.\n- Keep the local ACP execution path unchanged.\n- Preserve chat, tool, vision, and provider behavior across the adapter boundary.
- Update vue-stream-markdown to 1.0.4.\n- Pass OpenPencil's resolved theme to Shiki rendering.\n- Keep code backgrounds and syntax colors readable in light and dark modes.
- Extract the release body from the changelog section matching the pushed tag.\n- Keep the GitHub Release title identical to the tag.\n- Document signing, updater, publication, deployment, and Homebrew handoff.
* feat(code): isolate Design JSX execution
- Transform JSX with the existing Sucrase dependency and execute it in a disposable opaque-origin iframe worker
- Block ambient network capabilities and enforce source, timeout, output, depth, and element limits
- Validate that only bounded plain structured data returns to the application
* feat(code): add editable Design JSX
- Add a lazy CodeMirror editor with JSX syntax support, completion, diagnostics, and bounded scrolling
- Convert validated sandbox output into trusted Design JSX helpers before rendering
- Apply or insert JSX as one undoable graph transaction while preserving dirty drafts
* feat(code): localize JSX editor actions
- Add translated-message fallbacks for editing, applying, inserting, and draft state
- Document the editable JSX workflow in the unreleased changelog
* fix(code): satisfy typed sandbox validation
- Keep the sandbox document terminator literal and preserve optional selection handling under type-aware lint
* test(code): resolve sandbox probes through app aliases
* fix(code): bound sandbox results before cloning
- Enforce string, array, object, depth, element, and byte limits inside the disposable worker
- Retain host-side validation as a second structured-data boundary
* fix(code): keep JSX and HTML editing modes separate
- Switch generated Tailwind output back to OpenPencil JSX before editing
- Close the JSX editor when opening HTML/CSS import and avoid stacking both editors
* feat(code): support authored Design JSX programs
- Allow local constants, function components, arrays, conditionals, fragments, and multiple roots
- Preserve replacement positions for multiple selected roots and reject mixed-parent or locked selections
- Cover multi-root undo, redo, and all-or-nothing rollback
* feat(code): add explicit JSX view mode
- Let authors leave CodeMirror without applying a draft
- Keep the editable surface and HTML/CSS importer mutually exclusive
* feat(code): diagnose unknown JSX vocabulary
- Warn on OpenPencil elements and properties that are absent from the canonical schema
- Surface diagnostics inline through CodeMirror lint markers
* test(code): accept WebKit isolation diagnostics
- Cover the sandbox architecture against Playwright WebKit
- Accept engine-specific wording while preserving the same unavailable-window assertion
* refactor(code): consolidate Design JSX vocabulary
- Drive renderer warnings, completion, and diagnostics from one supported-property schema
- Recognize locally declared components and add focused schema and transform tests
- Replace CodeMirror basicSetup with an explicit feature set and remove the umbrella package
* fix(code): support Design JSX variable helpers
* refactor(code): unify JSX sandbox validation
* fix(code): account for complete sandbox output
* fix(code): preserve locked JSX descendants
* fix(code): preserve JSX sibling order
* fix(code): recompute JSX parent layouts
* feat(code): add live code previews
* test(code): centralize graph assertions
* fix(code): harden live preview sessions
* docs: describe live code editing
* fix(code): update editor accessibility labels
* fix(code): use theme-aware error colors
* fix(dev): stop Vite disconnect error loops
* fix(code): clarify live preview status
* fix(ui): avoid tooltip attribute warnings
* test(code): assert semantic preview status
* refactor(code): remove obsolete editor messages
* fix(code): harden preview concurrency and isolation
* fix(code): cancel stale reset previews
- Route copied English MCP, CLI, technical reference, shortcut, and useNumberField pages to their canonical English sources
- Repair remaining mixed-language user-guide and SDK labels
- Detect cross-locale placeholder copies and substantial English content in localized Markdown during documentation integrity checks
- Replace the ambiguous Guide section with explicit overview, reference, and development routes while preserving legacy URLs with redirects
- Route missing localized content to maintained canonical pages and emit SEO alternates only for real translations
- Add parser-backed documentation integrity checks and make the optimized local build the default while retaining a complete production build
- Load Prism JSX only after exposing the Prism runtime
- Treat unavailable MCP automation as optional during startup
- Connect the desktop automation bridge only after MCP is ready
- Export text and basic shapes as editable PowerPoint elements
- Rasterize unsupported geometry, effects, masks, and clipped content for fidelity
- Support app and CLI exports across multiple pages
Co-authored-by: TKman <102001532+greekr4@users.noreply.github.com>
- Replace regex-based list and error parsing with xmldom
- Decode entities through the parser and support namespaced pagination responses
- Treat malformed listing documents as empty pages
- Store desktop secrets in native OS credential services through a narrow Tauri bridge
- Provide session-only and encrypted remembered browser stores with explicit switching
- Migrate legacy plaintext keys only after verified writes and cover failure recovery
- Prefer private Unix sockets with TCP fallback for local MCP clients
- Unify HTTP and WebSocket lifecycle, authentication, and cleanup
- Discover transport details from an owner-only runtime file
- Index component property definitions and variable asset references once per export or override context\n- Skip converged instance fill and text propagation and use native binary hex encoding\n- Add a non-populating parse mode for raw fixture validation\n- Reduce the Material 3 round trip from minutes to about twenty seconds
- Pin websocket-driver 0.7.5 across the Trystero Firebase dependency chain\n- Restore a clean critical dependency audit\n- Reuse the shared font family/style shape exposed by scene-graph
- Move style references, plugin metadata, text values, and font feature conversion into @open-pencil/fig\n- Add a public node-change subpath with package-local and packed smoke coverage\n- Keep core conversion callers on compatibility exports during the staged migration
- Move ZIP canvas and image discovery from Kiwi into @open-pencil/fig\n- Keep Kiwi focused on raw fig-kiwi payload decoding\n- Rewire core and fixture consumers through the public Fig package API
- Remove ScrubInput aliases, app wrappers, test hooks, and translated legacy references
- Share a Tailwind NumberField demo between Storybook and VitePress
- Generate component API tables from Vue metadata and type-check examples with Twoslash
- Upgrade the docs stack to VitePress 2
- Use VueUse for object URLs, timers, and clipboard state
- Replace custom collection and equality helpers with es-toolkit
- Use ofetch and safeDestr at remote API and JSON boundaries
- Introduce Nuxt UI-style Tailwind Variants themes and 26px panel primitives\n- Align section and field action rails across labeled property rows\n- Add Storybook with dark/light states, accessibility tooling, and CI build coverage\n- Standardize UI acronym casing across app and Vue SDK types