Commit graph

183 commits

Author SHA1 Message Date
Danila Poyarkov 35667d84b5
fix(canvas): edit section labels inline (#608)
* fix(canvas): edit section labels inline

- Vertically center shaped section titles using cached paragraph metrics\n- Add generalized canvas-label edit state and a reusable inline label control\n- Match dark and light label presentation while editing and commit renames with undo

* fix(canvas): align label contrast handling

Use shared WCAG contrast selection for rendered and edited canvas labels while retaining exact node-fill presentation in the editing overlay.

* fix(canvas): composite translucent label colors

Choose label foreground contrast after compositing translucent section fills against the active canvas background.
2026-08-30 22:24:08 +03:00
Danila Poyarkov 0f64cecc49
fix(text): finalize font readiness and label shaping (#593)
* fix(text): prepare browser fonts atomically

- Fetch approved Fontsource resources directly in browsers with bounded responses and retryable provider failures
- Limit page font resolution concurrency and retain live Inter substitution paragraphs after baked glyph invalidation
- Shape frame, section, and component labels through a bounded native Paragraph cache
- Cover real Geist, Geist Mono, and Roboto Mono browser loading plus substitution and cache lifecycle behavior

* test(canvas): cover substitution and label shaping

- Capture baked missing-font text before editing, live Inter substitution on first input, and visible undo output
- Assert text-picture and derived-glyph invalidation with finalized substituted readiness
- Cover shaped frame, rotated frame, section, component, component-set, ellipsis, kerning, and zoom label presentation

* fix(text): preserve same-origin fetches during font resolution

- Route same-origin application and fixture requests through native fetch while Unifont temporarily proxies global HTTP requests
- Keep the external provider HTTPS allowlist enforced for cross-origin font resources
- Cover the production race discovered while loading gold-preview.fig during provider initialization

* fix(text): preserve substituted path glyphs

- Keep imported derived curved glyphs for text-on-path layers when exact fonts finalize as substituted
- Cover substituted path rendering through the runtime renderer and refresh the corrected visual oracle
- Update shaped Inter measurement badges and merged typography panel snapshots after visual inspection
- Search virtualized font catalogs explicitly and restore the canvas screenshot helper used by broad E2E coverage

* fix(text): use browser font transport without desktop warning

- Keep the browser provider implementation aligned with current settings behavior after splitting from preparation

* test(text): inject same-origin browser font context

- Keep the transport test deterministic outside a Window global

* fix(text): preserve final browser font transport hardening

- Carry the same-origin large-document bypass and bounded cross-origin provider checks from the preserved integration snapshot

* fix(text): initialize font transport outside Window contexts

- Keep unit and headless module imports safe while browsers use their current origin

* test(text): satisfy async visual fixture contract

- Return from the resolver setup continuation after requesting render

* test(canvas): include paragraph cache lifecycle

* fix(text): cancel queued browser font loads

- Race serialized provider work against preparation cancellation\n- Release queue slots after cancelled waiters without disturbing active requests\n- Reuse one section-title paragraph cache entry for measurement and drawing

* fix(text): close font queue cancellation races

- Release reserved proxy queue slots when cancellation lands after queue acquisition\n- Skip paragraph work for zero-width section labels

* fix(text): abort active provider resolution

- Race active provider resolution against its preparation signal and restore the temporary fetch proxy promptly\n- Forward cancellation through proxied provider requests\n- Align the renderer font-readiness facade with substituted text
2026-08-30 14:33:32 +03:00
Danila Poyarkov 2bc89c311d feat(canvas): add Figma guide feedback parity 2026-08-20 14:02:33 +03:00
Danila Poyarkov 3497aef818 refactor(canvas): normalize guide domain naming 2026-08-20 08:47:33 +03:00
Danila Poyarkov 27ad48b365 refactor(canvas): separate guide and overlay pipelines 2026-08-20 08:41:16 +03:00
Danila Poyarkov 103e4ac151 test(canvas): fix nested guide renderer coverage 2026-08-19 20:28:10 +03:00
Danila Poyarkov c141663291 fix(editor): address guide authoring review
- Dispose CanvasKit dash effects and render nested frame guides
- Validate imported guide GUIDs and invalidate stale raw guide metadata
- Resolve frame owners through nested hit ancestry and require primary-button ruler drags
- Share guide preview types through a neutral editor module
2026-08-19 20:13:57 +03:00
Danila Poyarkov adaf6dacb9 fix(canvas): keep guide renderer fixtures complete 2026-08-19 18:10:36 +03:00
Danila Poyarkov 73f0883521 Merge remote-tracking branch 'origin/master' into feat/configurable-snapping-guides 2026-08-19 13:20:21 +03:00
Danila Poyarkov 0332b062c5
refactor(canvas): adopt immutable CanvasKit paths (#554)
* 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
2026-08-18 23:09:45 +03:00
Danila Poyarkov 91e759d7fd feat(editor): add configurable snapping and guides
- Snap vector points, moved layers, and resized edges to geometry, objects, guides, and pixels
- Add persistent snapping preferences with browser and native menu controls
- Normalize canvas and layout guides across Scene Graph and .fig conversion
- Clear transient snapping feedback across interrupted interactions
2026-08-18 19:11:48 +03:00
rcoenen be272dc4dc
feat(fig): support text on path 2026-08-17 12:00:01 +03:00
Danila Poyarkov 6193b6da7e
feat(code): add live JSX and HTML/CSS editing (#525)
* 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
2026-08-15 09:48:42 +03:00
Danila Poyarkov c2103ef722
feat(canvas): measure distances between layers (#515)
* feat(canvas): measure distances between layers

- Show temporary Figma-style guides while Option or Alt is held

- Support deep nested targets with Command or Control plus Alt

- Measure transformed world bounds and container padding

* fix(canvas): anchor diagonal measurement guides

- Join diagonal distances at the nearest object corners

- Separate horizontal and vertical value badges

- Crop visual coverage tightly around the measurement overlay

* fix(canvas): cover measurement edge cases

- Draw transformed target outlines and center value pills on guides

- Suppress conflicting hover overlays during measurement mode

- Cover containment, overlap, multi-selection, rotation, and fractional gaps

* fix(canvas): suppress conflicting measurement overlays

- Hide auto-layout hover visuals while distance measurements render

- Assert fractional measurement geometry with numeric tolerance
2026-08-14 18:18:55 +03:00
Danila Poyarkov 6f73b28f3d
fix(core): preserve inline SVG primitives (#485)
* fix(core): preserve inline SVG primitives

- Convert parsed circle, ellipse, rect, line, polyline, and polygon children through the shared SVG path pipeline
- Preserve nested presentation attributes, transforms, and JSX-style SVG attribute names
- Cover mixed and primitive-only inline SVG renders

* chore: format merged mobile navigation

* fix(core): disambiguate xmldom document types

- Alias the xmldom Document type so clean CI does not resolve it as the browser DOM type
- Guard the generated SVG document root before collecting paths

* fix(core): preserve inline SVG root styles

- Carry root presentation properties into parsed SVG child conversion
- Apply nested SVG transforms before creating vector networks
- Cover inherited root fills and transformed primitive geometry

* fix(core): scale transformed SVG strokes
2026-08-12 16:02:45 +03:00
Victor Wads 54abfca334
fix(fig): address instance rendering review 2026-08-10 05:09:03 -03:00
Victor Wads e159893ec4
fix(fig): preserve component instance rendering 2026-08-10 04:30:06 -03:00
Danila Poyarkov afc5305e8c fix(canvas): report retained backing failures
- Warn once with the rejected surface dimensions and original CanvasKit error
- Disable repeated cache allocation attempts until the renderer surface is replaced
- Keep direct scene rendering as the visible fallback
2026-08-05 19:10:41 +03:00
Danila Poyarkov 82ef49aa9e fix(canvas): bound retained backing allocations
- Scale retained margins to a fixed device-pixel budget on large viewports
- Fall back to direct scene rendering when CanvasKit rejects an offscreen surface
- Cover the reported wide HiDPI geometry without coupling rendering to a WebGL context
2026-08-05 18:54:18 +03:00
Danila Poyarkov f047b0bcb4 fix(svg): preserve explicit none paints
- Normalize SVG paint sentinels before creating icon vector nodes
- Keep inline outline artwork transparent instead of falling back to black
- Cover fill and stroke none values through the Design JSX renderer

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-08-01 15:42:46 +03:00
rcoenen 80cebe0767
fix(tools): document inline SVG path rendering
Document the supported inline SVG path route in the render tool prompt.

Keep coverage focused on separate open and closed stroked vector paths.
2026-08-01 15:34:51 +03:00
Danila Poyarkov a7d7b71995 fix(fig): preserve multi-color vector fills
- Resolve Figma path style overrides into format-neutral geometry fills
- Render and export per-path paints across normal and pattern drawing
- Preserve path fills through copying, instance scaling, and derived geometry
- Cover import, serialization, scaling, and CanvasKit output

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-28 11:45:58 +03:00
Danila Poyarkov 57eb59769d
feat(components): match Figma asset browsing (#424)
* feat(components): match Figma asset browsing

- Add thumbnail grid and list views grouped by source page
- Support component drag insertion and main-component navigation
- Keep asset previews working across document pages
- Cover views, context actions, and drag-to-canvas behavior

* fix(components): remove redundant Assets heading

* fix(components): render crisp asset thumbnails

- Render preview images at twice their display dimensions
- Preserve the existing grid and list thumbnail sizes

* fix(render): exclude ancestors from selection exports

- Reparent selected export roots directly under the extracted page
- Preserve absolute positions without drawing ancestor backgrounds
- Cover transparent selection export around nested components

* fix(components): address Assets panel review

- Handle thumbnail export failures without stale previews
- Share page lookup and thumbnail sizing across asset views
- Make list actions keyboard accessible and honor requested export pages
2026-07-26 01:18:27 +03:00
Danila Poyarkov 0cd0ee6356
fix(text): center glyphs within line height (#422)
Enable CanvasKit half-leading for solid and gradient paragraph rendering while preserving the existing font fallback system.\n\nCo-authored-by: jongwong <jongwong@aliyun.com>
2026-07-25 23:52:01 +03:00
Danila Poyarkov 3cfc86371d feat(design-jsx): masks, inline <svg> vectors, and instance overrides
Fill the three biggest gaps that blocked authoring real designs in JSX:

- mask prop on any node: <Ellipse mask> / mask="luminance" / mask="vector"
  sets isMask + maskType so sibling content clips (Figma's mask model)
- <svg> element rendering inline SVG markup into vector nodes, reusing the
  iconify path pipeline (extractPaths + parseSVGPath + scalePathInfos)
- Instance overrides: <Instance of="X" overrides={{ 'childName:prop': v }} />
  applies child overrides by name and records them so component sync keeps them

Adds gap tests and the shared scalePathInfos/finishIconRender helpers to
avoid duplicating the iconify pipeline.
2026-07-21 11:40:13 +03:00
Danila Poyarkov e704343f13 fix(fig): honor node-scoped variable modes
- Import and round-trip per-node variable mode overrides

- Resolve fill and stroke aliases through the nearest mode scope

- Preserve mode maps across cloning and instance synchronization
2026-07-21 00:23:00 +03:00
Danila Poyarkov cf857dbf80 fix(text): preserve local font rendering (#395)
- Reject text pictures captured before the current font generation
- Keep text visible when CanvasKit must synthesize a missing italic face
2026-07-20 14:07:47 +03:00
Danila Poyarkov 86d6a63d0f fix(fig): restore strict parse validation
- Reject corrupt compressed Kiwi chunks instead of accepting raw garbage\n- Tolerate legacy source metadata without editedFields in renderer fallbacks\n- Align font, derived glyph, shared style, renderer mock, and ownership tests with current contracts\n- Restore clean quick and heavy unit quality gates
2026-07-18 03:58:18 +03:00
Danila Poyarkov 85c3c8fad1 refactor(fig): own NodeChange export policy
- Move SceneGraph-to-NodeChange conversion, text payload assembly, and blob encoding into @open-pencil/fig\n- Inject core glyph outline lookup through an explicit runtime service\n- Centralize neutral font naming in scene-graph and retain core IO/runtime orchestration
2026-07-18 02:41:35 +03:00
Danila Poyarkov 2bd2304bcb refactor(fig): own instance interpretation
- Move component properties, symbol overrides, derived symbol data, and clone synchronization into @open-pencil/fig\n- Add the public instance-overrides subpath with package tests and packed smoke coverage\n- Remove cross-package forwarding modules and enforce direct owner imports in architecture checks
2026-07-18 02:06:34 +03:00
Danila Poyarkov db056317a8 refactor(fig): extract paint import policy
- Move paint/effect normalization and derived glyph conversion into the Fig package\n- Rewire core import and instance paths through the public node-change boundary\n- Keep static renderer evidence pointed at the new format-policy source
2026-07-18 01:36:00 +03:00
Danila Poyarkov 0bf74a418f feat(text): deepen typography controls
- Add case, justification, vertical alignment, truncation, max-lines, and OpenType controls

- Apply visual text case and measured vertical offsets in CanvasKit rendering

- Preserve nullable preview values, shared text styles, font demand, and .fig metadata

- Add panel, engine, and canvas visual coverage
2026-07-17 22:40:52 +03:00
Danila Poyarkov 47fe43c3ec feat(text): harden font resolution lifecycle
- Gate ingest rendering until required faces and script fallbacks resolve
- Key CanvasKit artifacts by font registration generation and invalidate affected nodes
- Load character-aware remote subsets with cumulative coverage and exact render aliases
- Use BCP-47 language hints for shaping and CJK fallback order
- Keep baked .fig glyphs as an exhaustion-only fallback
2026-07-17 14:52:35 +03:00
Danila Poyarkov 4b3d97ce0d feat(text): add demand-driven font resolver
- Resolve exact faces through registered, local, cache, and remote sources with deduplicated state transitions\n- Use CanvasKit notdef glyphs to request script fallbacks and repaint after resolution\n- Make CJK coverage analysis codepoint-safe across supplementary characters and style runs
2026-07-17 13:00:09 +03:00
Danila Poyarkov 5a89b520b2 fix(text): load CJK fallback only when needed 2026-07-01 22:06:19 +03:00
Danila Poyarkov 3a5b6a5c37 test: share scene variable helper 2026-06-30 10:55:05 +03:00
Danila Poyarkov 4c26536e69 test: align render shard with package split 2026-06-30 10:55:05 +03:00
Danila Poyarkov 898431e646 feat: split SceneGraph and Pen packages 2026-06-30 10:54:32 +03:00
Danila Poyarkov 7d27cac5ab refactor(kiwi): remove redundant core shims 2026-06-30 10:50:30 +03:00
Danila Poyarkov 6877516f06 refactor(kiwi): consume standalone Kiwi package 2026-06-30 10:49:14 +03:00
Danila Poyarkov 8983c11f45 feat(design-jsx): support structured effects 2026-06-30 10:45:15 +03:00
Danila Poyarkov cc1167eed5 feat(design-jsx): support structured paints 2026-06-30 10:44:51 +03:00
Danila Poyarkov 4b65e64c18 feat(design-jsx): support variable refs 2026-06-30 10:44:28 +03:00
Danila Poyarkov 568cdf91ef Merge remote-tracking branch 'joey/feature-overlapping-element-analysis-tool' into pr352-local-merge
# Conflicts:
#	tests/engine/clipboard/fixtures/gold-preview-roundtrip.test.ts
#	tests/engine/io/fig/import/group-reclassify.test.ts
#	tests/engine/io/fig/roundtrip/glyph-blob.test.ts
#	tests/engine/layout/auto-layout/text/measurement.test.ts
2026-06-30 09:47:07 +03:00
Joseph Cumines dc9638ac3e
fix(export): prevent GUID collisions and file corruption on .fig round-trip (#333)
* fix(export): prevent GUID collisions and file corruption on .fig round-trip

Nodes sharing the same imported source.id (component instance children,
cloned subtrees) silently overwrote each other on export because the
GUID assignment reused imported GUID values without checking for
duplicates.  This caused data loss on reimport — only the last node
with a given GUID survived.

- Track all assigned GUID values in a Set for O(1) collision detection.
- Scan imported source.ids for both sessionID 0 and 1 before assigning
  any new GUIDs, so the counter starts past every imported value.
- Fall back to counter-based GUIDs when source.id collides with an
  already-assigned value.

Additional fixes in the same change set:

- cloneTree now deep-copies source.fig via structuredClone, preventing
  mutations on a clone from corrupting the original node's kiwi payload.
- Removed decompressFigKiwiData sync wrapper (zero callers) and the
  silent try/catch fallback in parseFigKiwiContainer that masked
  corrupt data as raw bytes.
- buildFigKiwi uses Bun.zstdCompressSync when available, matching the
  zstd decompression path already used on import.
- Fixed setSavedVersion ordering in read.ts — must run after
  requestRender to capture the post-bump version, preventing spurious
  dirty-state immediately after file reload.

Tests: GUID collision (2 and 3 node), clone isolation, parse failure,
text export zstd compatibility, gold-preview round-trip.

* fix(export): handle EXCLUDE boolean operation and BOOLEAN_OPERATION node type

The internal representation uses EXCLUDE for exclude boolean operations,
but Figma's kiwi schema uses XOR. Map EXCLUDE back to XOR on export so
round-trips through .fig files don't fail. Also add BOOLEAN_OPERATION to
VALID_NODE_TYPES and increase timeout for heavy material3 fixture test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* style: format export-node.ts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test: add type guard after null assertion in guid-collision test

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clipboard): detect zstd-compressed data before zlib inflate

fflate's inflateSync silently accepts zstd-compressed data and returns
garbage instead of throwing. Check for the zstd magic bytes (28 b5 2f
fd) before attempting zlib decompression. Also revert the EXCLUDE enum
addition to the kiwi schema since the export-node.ts mapping is
sufficient.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(clipboard): add length guard before zstd magic byte check

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(scene-graph): group clone regression coverage

* ci: retrigger CI checks

* test: increase timeouts for heavy .fig fixture tests on slow CI runners

Gold-preview.fig and material3.fig parsing/export tests consistently
exceed the 5s bun:test default timeout on GitHub Actions runners.
Increase to 30s for: beforeAll codec init, clipboard roundtrip,
glyph blob roundtrip, group reclassification, and text measurement.

* test: add individual test timeouts for heavy .fig fixture tests

The beforeAll timeout helped but individual test() calls also need
explicit 30s timeouts since bun:test applies the 5s default per-test.
Fixes remaining CI flakes in glyph-blob roundtrip and clipboard
roundtrip tests.

* test: increase beforeAll timeout for render cache test

The canvas/render cache test loads gold-preview.fig AND initializes
CanvasKit (Skia WASM), which is much slower than the other fixture
tests. Use 60s timeout to account for slow CI runners.

* fix(export): reserve document GUID to prevent 0:0 namespace collision

- Add docGuid (0:0) to assignedGuidValues before processing imported
  node source.ids, preventing an imported node with source.id "0:0"
  from reusing the document's GUID slot
- Add regression test using session-0 source.ids to verify nodes
  survive roundtrip without document GUID collision
- Remove unnecessary async keyword from synchronous component
  metadata test

* fix(export): guard canvas GUID reuse with assignedGuidValues check

- Mirror getOrCreateNodeGuid() collision logic in buildCanvasEntries():
  if an imported page's source.id maps to a GUID already in
  assignedGuidValues, generate a fresh counter-based GUID instead
- Prevents canvas-level last-write-wins when multiple pages share
  the same source.id or a page uses 0:0

* fix(test): use explicit little-endian writes and fix misleading test title

- Replace host-endian Uint32Array writes with DataView.setUint32(offset, value, true) in parse-failures.test.ts to ensure platform-independent fig-kiwi container assembly
- Rename test title from "clone clears source.id from the original" to "clone clears source.id from the clone" to accurately reflect what the assertions verify

* test(io): use file-level timeout for heavy fixture

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-06-23 18:05:23 +03:00
Joseph Cumines fa5c072cad test: extend timeout for slow gold-preview fixture tests
Port the timeout fixes from PR #351 that resolved the unit-test CI
timeouts. Add HEAVY_TEST_TIMEOUT_MS (30s) in tests/helpers/test-utils.ts
and apply it to the slow gold-preview.fig fixture tests/hooks:
- clipboard roundtrip
- group reclassification
- glyph blob preservation
- auto-layout text measurement
- render/canvas/cache
2026-06-19 11:05:25 +10:00
Danila Poyarkov 05e4a29a08 feat(design-jsx): support components and instances 2026-05-31 18:33:56 +03:00
Danila Poyarkov 22ff3acdb5 Merge remote-tracking branch 'origin/master' into figma-compat-render-gaps
# Conflicts:
#	CHANGELOG.md
2026-05-31 13:59:19 +03:00
Danila Poyarkov 6ee0e5f9e8 fix(kiwi): preserve imported boolean geometry 2026-05-31 13:28:41 +03:00
Danila Poyarkov f9bd0c7be9 fix(canvas): render complex text fills as outlines 2026-05-30 12:32:55 +03:00
Danila Poyarkov 6ae425ee3b fix(core): address compatibility review findings 2026-05-28 09:57:46 +03:00
Danila Poyarkov 5fcd8e0e9c fix(canvas): support stretched layout grids 2026-05-28 05:39:40 +03:00
Danila Poyarkov 64e8b21949 fix(canvas): render imported page guides 2026-05-27 19:00:23 +03:00
Danila Poyarkov 42fcb37f4d fix(canvas): render imported layout grids 2026-05-27 17:57:41 +03:00
Danila Poyarkov 033326cffb fix(canvas): render raw noise effect fallback 2026-05-27 10:53:12 +03:00
Danila Poyarkov 4224179501 fix(canvas): render derived text decoration styles 2026-05-27 10:11:06 +03:00
Danila Poyarkov 94dd6cf3aa fix(canvas): tune Figma pattern origin 2026-05-26 21:21:49 +03:00
Danila Poyarkov e02782d1b5 test(canvas): record Figma visual oracle diffs 2026-05-26 20:44:18 +03:00
Danila Poyarkov c1532610db fix(canvas): tighten Figma text and pattern fidelity 2026-05-26 18:30:08 +03:00
Danila Poyarkov d208cc326e fix(canvas): render Figma pattern fills 2026-05-26 17:33:45 +03:00
Danila Poyarkov 1e1d78c7f6 fix(canvas): render Figma leading trim 2026-05-26 16:23:59 +03:00
Danila Poyarkov c2a0de5f0c fix(kiwi): support Figma OpenType variant fields 2026-05-26 15:14:23 +03:00
Danila Poyarkov 80daa0d1e9 fix(canvas): render Figma text decoration styles 2026-05-26 13:22:56 +03:00
Danila Poyarkov 84cf18ba80 fix(kiwi): preserve schema paint fields 2026-05-25 09:19:25 +03:00
Danila Poyarkov 5c09ca0299 test(core): stabilize engine unit tests
- Update EffectType schema assertion for modern Figma enum values
- Treat unsupported OpenType font buffers as unavailable
- Skip CJK outline fallback coverage when the LFS font fixture is not materialized
2026-05-25 01:41:59 +03:00
Danila Poyarkov afd571341b fix(ai): render common generated JSX aliases 2026-05-24 12:45:42 +03:00
Danila Poyarkov abd795bd9a chore: format codebase 2026-05-24 12:15:29 +03:00
Danila Poyarkov c337905a02 fix(canvas): preserve text OpenType toggles 2026-05-23 01:43:00 +03:00
Danila Poyarkov f36d6b94b7 fix(canvas): apply affine image fill transforms 2026-05-23 01:31:04 +03:00
Danila Poyarkov 762c86e094 Revert "perf(canvas): defer backing rebuilds while zooming"
This reverts commit 21a79d4cd5.
2026-05-23 01:17:48 +03:00
Danila Poyarkov 21a79d4cd5 perf(canvas): defer backing rebuilds while zooming 2026-05-23 01:17:07 +03:00
Danila Poyarkov 0d5db35147 perf(canvas): bound blend and text mask layers 2026-05-23 01:10:24 +03:00
Danila Poyarkov f07d26c50b perf(canvas): bound effect render layers 2026-05-23 01:01:38 +03:00
Danila Poyarkov 7184bc1b06 Revert "perf(canvas): cap retained backing size"
This reverts commit 7b62c8acca.
2026-05-23 00:45:13 +03:00
Danila Poyarkov 7b62c8acca perf(canvas): cap retained backing size 2026-05-23 00:30:30 +03:00
Danila Poyarkov 8c85d2b953 fix(canvas): improve Figma mask and text fidelity 2026-05-23 00:18:33 +03:00
Danila Poyarkov 3dc0904466 fix(canvas): support luminance masks and tile transforms 2026-05-22 23:44:10 +03:00
Danila Poyarkov 98616c8610 fix(canvas): render Figma-style corner smoothing 2026-05-22 23:05:24 +03:00
Danila Poyarkov 76ee122dee fix(canvas): render smoothed corners and effect blend modes 2026-05-22 22:50:58 +03:00
Danila Poyarkov 0ce57ea0fa fix(canvas): render Figma mask stacks 2026-05-22 21:05:35 +03:00
Danila Poyarkov 8e1d5d40e7 fix(canvas): render Figma blend modes 2026-05-22 21:00:34 +03:00
Danila Poyarkov 11c3cfe73e test(canvas): drop brittle shadow source check
- Rely on behavioral effect tests for stroked container shadow coverage
2026-05-22 14:44:16 +03:00
Danila Poyarkov 8f4f7a47e9 fix(canvas): filter retained backing previews
- Keep stale scene backings available during zoom for smooth interaction

- Draw scaled backings with linear filtering to avoid blocky text artifacts
2026-05-22 14:44:16 +03:00
Danila Poyarkov a49f626e3e fix(canvas): render stroked container shadows from bounds
- Use container bounds for stroked frames with drop shadows

- Keep stroke-geometry shadows for childless stroke-only shapes

- Cover the shadcn dropdown menu case
2026-05-22 13:39:29 +03:00
Danila Poyarkov 1c22b3f7a9 test(canvas): align shadow cleanup checks
- Keep explicit color filter deletion checks compatible with cleanup guards

- Verify text inner-shadow restore balancing through the restore-count loop

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 13:17:04 +03:00
Danila Poyarkov f6e31be707 fix(canvas): delete renderer label resources
- Dispose parent outline paint during renderer teardown

- Dispose section and component label fonts with other renderer-owned fonts

- Cover renderer teardown for label resources

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 13:15:35 +03:00
Danila Poyarkov 420c61e004 fix(canvas): guard retained backing surfaces
- Fall back to live rendering when CanvasKit cannot allocate the backing surface

- Match retained backing metadata against the current graph preview version

- Cover null-surface and stale-preview backing regressions

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:51:00 +03:00
Danila Poyarkov 9f67a1086d fix(canvas): restore shadow render state on errors
- Restore canvas save layers and shared paints from shadow effect paths when rendering fails

- Delete temporary paths and color filters through error paths without suppressing failures

- Cover drop-shadow and text inner-shadow cleanup regressions

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:47:33 +03:00
Danila Poyarkov 0b4fcc9f77 fix(canvas): render shadows from path shapes
- Use polygon, star, and vector paths for shadows when geometry blobs are unavailable
- Apply shadow spread to copied geometry paths without mutating caches
- Clip and cut out inner shadows with the same path geometry

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:37:00 +03:00
Danila Poyarkov a48b23129f fix(fig): stabilize engine test suite 2026-05-21 14:54:17 +03:00
Danila Poyarkov 213db6373a refactor(kiwi): group fig format internals
- Move codec, NodeChange conversion, and instance overrides under kiwi/fig
- Flatten the codec entrypoint to kiwi/fig/codec
- Keep schema-runtime as the generic Kiwi parser/compiler boundary
2026-05-21 14:54:13 +03:00
Danila Poyarkov 54310308dc refactor(kiwi): split schema text from runtime
- Move the Kiwi runtime under schema-runtime to match folder naming
- Load the Figma schema from a .kiwi text asset with static validation
- Assert Figma clipboard-derived field numbers for fragile layout/text fields
2026-05-21 14:54:12 +03:00
Danila Poyarkov 957db338ba fix(fig): sync lazy instance override clones
- Re-propagate resolved overrides after lazy instance population
- Preserve Figma showShadowBehindNode on effects
- Mask unfilled stroke shadows behind their fill geometry
2026-05-20 13:12:16 +03:00
Danila Poyarkov 4603bbf81b fix(canvas): shadow stroked shapes without fills
- Use stroke geometry for drop shadows on unfilled stroked nodes
- Avoid filling the interior of outline-only image icons
2026-05-20 12:52:21 +03:00
Danila Poyarkov 779e0e493f fix(mcp): improve agent-rendered JSX 2026-05-19 17:57:43 +03:00
Danila Poyarkov 26fb9b6a0b fix(canvas): render background blur as backdrop 2026-05-19 13:07:46 +03:00
Danila Poyarkov f466946c1c fix(canvas): render derived text underlines 2026-05-18 20:28:15 +03:00
Danila Poyarkov eb7a663c1c fix(fig): preserve scene node defaults during overrides 2026-05-18 19:50:34 +03:00
Danila Poyarkov f3649550f2 chore: enable stricter oxlint rules 2026-05-18 18:58:30 +03:00
Danila Poyarkov 6d8920a496 fix(canvas): tune derived glyph coverage 2026-05-18 18:21:26 +03:00