Commit graph

2161 commits

Author SHA1 Message Date
Kayshen-X ba16f755f5 feat(export): selected-node SVG export with canvas-parity serialization
Add SVG to the property panel export formats (PNG/JPEG/WEBP/SVG).
Selected nodes export as a tightly cropped SVG subtree preserving
ancestor rotation/flip/clip state; with no selection the full page
is serialized. Desktop writes through the save dialog, web reuses
the blob download path.

Serialization matches canvas rendering: tight-bounds path fitting
with non-scaling strokes, user-space gradient endpoints, implicit
strokes for open point paths, intrinsic-size image tiling, rounded
image clipping, per-line text without duplicate ids, and
collision-free defs ids.
2026-07-11 18:43:57 +08:00
Kayshen-X 20122d4b81 docs(readme): refresh roadmap 2026-07-11 12:14:00 +08:00
Kayshen-X ca5b6db5df perf(web): tint text rasters at draw instead of baking color
The browser-text raster cache keyed on RGBA, so identical glyphs in N
colors were N cache entries — text-heavy pages blew the 512 cap and
re-rasterized + re-uploaded GPU textures every frame while panning.
Text now rasters once as a white alpha mask (color and alpha out of
the key) and tints at draw via a bounded, LRU ColorFilter cache;
eviction is LRU instead of FIFO. Color-emoji segments keep the legacy
baked-color path since they ignore fillStyle. Verified visually:
before/after screenshots differ only in sub-24/255 antialiasing-edge
quantization (0.45% of pixels, max delta 14).
2026-07-11 10:47:41 +08:00
Kayshen-X 294a2bb27c perf(history): structurally-shared undo snapshots
Every undoable gesture deep-cloned the whole document plus all
component prototypes, and the 100-entry history held full copies —
peak memory ~100x document size. Snapshots now share unchanged
top-level nodes and components via Arc, diffed against a
transition-specific anchor (previous snapshot / popped destination /
pre-clear redo head) with id+deep-equality gating; restores and batch
rollback materialize by clone, and the instance-override snapshot
repair goes through copy-on-write so no shared history state is ever
mutated. Commit cost drops from an allocation-heavy full clone to an
allocation-free equality walk plus changed-subtree clones; memory to
one document plus deltas. Pinned by a random-sequence property suite
against a full-clone reference history.
2026-07-11 10:39:04 +08:00
Kayshen-X 3672ffb4e9 perf(figma): cut import clone amplification
Decoded node changes were held twice (cloned into by_key, cloned again
into TreeNodes), every symbol subtree was deep-cloned per component
instance, and every embedded blob was eagerly base64-encoded whether
referenced or not. Materialization now moves out of by_key via a
deduplicated latest-wins adjacency (repeated GUID records collapse to
one edge), symbol prototypes are shared via Rc, and blob encoding is
lazy and memoized so unreferenced blobs are never encoded.
2026-07-11 10:04:41 +08:00
Kayshen-X d866690cc4 chore(agent): bump vendor/agent to 2ab5e97
Picks up the multilingual product-overview README (docs-only); pointer
target is on the agent repo's origin/main.
2026-07-11 09:46:28 +08:00
Kayshen-X 6fcc4e38d5 perf(editor): single-pass translate_selected
Each selected node cost three full-tree walks (flex-flow check,
ancestor-dedup, find) per nudge/drag frame — near-quadratic on
select-all. One recursive walk now threads parent-flex and
ancestor-in-set context down; equivalence with the old algorithm is
pinned by a 10-case reference-implementation test suite.
2026-07-11 09:46:28 +08:00
Kayshen-X 355d94e244 feat(canvas): device-frame preview with switcher, scroll and pinned nav
Preview now presents ONE framed root inside a fixed device frame —
Phone 390x844 / Desktop 1440x900, inferred from the root width
(<=500 -> Phone) with a floating 3-segment switcher (Phone / Desktop /
Canvas, i18n'd across all 15 locales) overriding inference until exit.
Content keeps authored size (no reflow, no content scaling); overflow
scrolls vertically inside the frame, clamped to the pinned-nav top
bound. A bottom nav (semantics.role=nav bottom-anchored, or the
flush/full-width/<=120px heuristic) pins to the frame bottom in a
second clipped paint pass and the content viewport shrinks past it.

One DeviceFrame struct owns every transform: paint, the screen->scene
inverses (strip + letterbox dead zones resolve at surface-resolution
time), and the per-gesture presentation capture, so drags never flip
surfaces mid-gesture. Device mode fails closed — no wheel / pan /
pinch / modifier-zoom ever reaches the editor viewport (pinch gets its
own host entry, split from the line-wheel path at the desktop call
sites). Reconcile now reports { repaint, switched } so warning-only
passes stop recentering; screen switches re-infer, reset scroll and
rebuild the frame.
2026-07-11 04:00:24 +08:00
Kayshen-X 35ce39634b fix(canvas): preview renders design-canvas geometry with pointer capture
Preview scenes now take paint from the promoted document but GEOMETRY
from the unpromoted layout tree via the design canvas's exact layout
pass — honoring preserve_authored_geometry for Figma imports — so
preview positions match design mode by construction (was: full taffy
re-solve, elements shifted 100+ px on preserve docs, 2 px per promoted
hug widget). Hit-testing maps taps through the deepest painted node's
scene/runtime rect pair with a per-gesture anchor (pointer capture),
so drags never remap through neighbours mid-gesture. Input dispatch
split to preview/input.rs for the 800-line cap.

Pairs with the following device-frame commit (preview/mod.rs already
declares the present module it introduces).
2026-07-11 03:58:16 +08:00
Kayshen-X d1943d7b3b refactor(desktop): move chat_session_launch tests to sibling file
The revision-bump regression test pushed chat_session_launch.rs past the
800-line ceiling (834); the inline tests module moves to
chat_session_launch_tests.rs (mirrors chat_session_launch_selection_tests.rs),
bringing the file to 756 lines.
2026-07-11 00:46:22 +08:00
Kayshen-X d6f6cfaae1 fix(editor): bump document revision on raw content mutations
The layer-panel row cache keys on document_revision, which made revision
correctness load-bearing: host paths that mutate content through raw
active_children_mut() without mark_document_changed() left the panel
painting stale rows (and is_dirty save-tracking wrong) — most visibly
the starter-frame clear before a design run. Adds the bump at the four
raw sites (starter clear, image-search apply, both pick-fill handlers);
all other raw-mutation sites audited as already bumping via history.
2026-07-11 00:25:44 +08:00
Kayshen-X 2216e61c0f perf(desktop): build a11y tree lazily and gate image search on revision
Every painted frame eagerly built and cloned a full accesskit TreeUpdate
(including a whole-tree layer walk) even with no assistive technology
attached, and the image-search session re-walked the node tree on every
RedrawRequested. The a11y build now happens inside update_if_active with
a wake-on-activation event so AT still converges to a current tree, and
the image scan is gated on (document revision, active page) with a full
session reset at every document-replacement seam (open, import, MCP
replace) so revision-0 aliasing cannot serve stale state.
2026-07-10 22:56:49 +08:00
Kayshen-X 11ae71fe19 perf(panels): cache chat transcript, layer rows, and panel filters
The chat transcript re-laid-out every message twice per paint and again
on every mouse move; the layer panel re-walked the whole tree per frame;
the icon, markdown, and font panels re-filtered per frame while open.
Each now resolves from an owner-scoped cache: the transcript builds once
per frame/event (value-hash key, last-resolver-owns slots, forced owner
rotation at every session mutation), layer rows key on document revision
plus page with rotation at every document replacement, and panel filters
recompute only when their query/content/generation inputs change,
returning shared Rc results.
2026-07-10 22:56:38 +08:00
Kayshen-X 686527a0c3 perf(sdk): share scene via rc and idle the raf pump when clean
The viewer deep-cloned the whole LayoutScene every dirty frame and kept
an unconditional rAF loop alive forever. The scene is now shared via Rc,
and a DirtyState machine (wrap-safe generation counters, single
mark-and-arm funnel, bounded failure breaker, pending payload slots,
cancel-on-detach) schedules frames on demand so an idle tab sleeps.
2026-07-10 22:56:25 +08:00
Kayshen-X d691af3efc perf(editor): drop second document clone in ref resolution
resolve_refs_for_canvas cloned the whole document twice per scene
rebuild; the lookup copy existed only as a borrow-checker workaround.
Lookups now borrow the original document, which stays read-only for the
entire resolve pass while resolved nodes accumulate separately.
2026-07-10 22:56:25 +08:00
Kayshen-X e8124d7b74 perf(web): cache canvaskit paints and imported-font coverage in bridge
Every primitive draw allocated and deleted a CK.Paint per call per frame,
and the imported-family text path re-ran getGlyphIDs coverage scans on
every draw and measure. Long-lived fill/stroke paints are now mutated per
call, and coverage segments + per-family fonts are cached with bounded
eviction, invalidated when the imported-font registry changes.
2026-07-10 22:56:11 +08:00
Kayshen-X c001809e86 fix(release): stop publishing unsigned macOS desktop tarball 2026-07-09 23:23:55 +08:00
Kayshen-X e22feae95c fix(release): notarize final macOS DMG artifacts 2026-07-09 22:52:48 +08:00
Kayshen-X 6b2aa18db6 fix(release): exclude docker build metadata from release assets 2026-07-09 22:43:33 +08:00
Kayshen-X 220d5991d6 fix(desktop): sign embedded macOS CLI before app executable 2026-07-09 22:23:10 +08:00
Kayshen-X 4397db6171 fix(desktop): notarize macOS app before DMG packaging 2026-07-09 21:54:45 +08:00
Kayshen-X be01715c09 docs(release): update v0.8.0 notes and docker docs 2026-07-09 21:13:29 +08:00
Kayshen-X deb6d0654f fix(web): hide external agent settings entries 2026-07-09 21:13:20 +08:00
Kayshen-X 89fca08b8e fix(canvas): align overlays with ancestor transforms 2026-07-09 21:12:18 +08:00
leinaldo 4f2f3ff258 fix(canvas): rotate hover outline with node and ancestor transforms (#174)
The hover dashed outline painted at page level from the unrotated
doc-space bounds, so a rotated frame (and any element inside one)
showed an axis-aligned outline detached from its rendered geometry.
Accumulate the root-to-node flip/rotation chain during the scene
paint walk and replay it around the dashed rect so the outline lands
exactly where the node renders. Hit-testing already handled ancestor
rotation, so trigger area and visual now agree.
2026-07-09 09:56:54 +08:00
leinaldo 3687581b62 fix(desktop): round window corners and add border on Windows (#173)
`with_decorations(false)` strips the native frame entirely on Windows,
so DWM painted the borderless window as a flat rectangle with sharp
corners instead of the Windows 11 look. Opt back into
`CornerPreference::Round` and a hairline border matching the dark
chrome via casement's `WindowAttributesExtWindows`.
2026-07-09 09:48:05 +08:00
Kayshen-X 5799d9cc9c fix(release): tolerate apple agreement notarization block 2026-07-09 00:10:19 +08:00
Kayshen-X 4abd5119e7 fix(release): skip existing npm packages 2026-07-08 23:50:39 +08:00
Kayshen-X f6f3303635 docs(cli): document prerelease install channel 2026-07-08 23:28:07 +08:00
Kayshen-X 4e16c7734f docs(readme): document cli install scripts 2026-07-08 23:25:44 +08:00
Kayshen-X d49087027e chore(release): include cli install scripts 2026-07-08 23:24:32 +08:00
Kayshen-X a98458e146 fix(release): publish sdk tarballs from local paths 2026-07-08 23:06:02 +08:00
Kayshen-X 10b9ad8bfc chore(release): update package manager publishing 2026-07-08 22:56:59 +08:00
Kayshen-X a71d97e7b9 chore(release): wire signing and npm publish secrets 2026-07-08 22:47:21 +08:00
Kayshen-X e25dbbe1bf fix(release): pin docker wasm optimizer 2026-07-08 22:43:09 +08:00
Kayshen-X c44e7e6aac fix(release): repair sdk and docker artifact builds 2026-07-08 22:32:12 +08:00
Kayshen-X 5dc21b2ff1 chore(release): publish prerelease on tag 2026-07-08 22:21:24 +08:00
Kayshen-X 613878e18e chore(release): prepare v0.8.0 prerelease 2026-07-08 22:16:43 +08:00
Fini 6c98da3ea2 docs(readme): add ecosystem logos 2026-07-08 21:23:39 +08:00
Kayshen-X ffd9d38d66 docs(readme): add ecosystem section and reframe jian as UI framework
Introduce the ZSeven-W product family (zode, agent-rs, jian, noema)
with a new Ecosystem section across all 15 locales, and reframe jian
from 'widget/render/event toolkit' to 'GPU-Skia UI framework' in the
Tech Stack table, Ecosystem table, and Project Structure tree.
2026-07-08 21:06:47 +08:00
Kayshen-X 86357c04e5 fix(web): supersample offscreen text raster for HiDPI
Chrome text rendered blurry on Retina: all chrome/canvas text goes
through the offscreen 2D-canvas raster path (drawBrowserText), which
rasterized glyphs at CSS (1x) resolution. Those bitmaps are then drawn
onto the CanvasKit surface while a scale(dpr, dpr) transform is active,
magnifying them dpr-x — half-resolution on 2x displays.

Supersample the offscreen text canvas by the device pixel ratio and
composite it back at 1/dpr so glyphs land at native device resolution.
Thread the real dpr from Rust (CanvasKitBackend::new + resize_for_display)
into the bridge via a new setDpr method; cache key includes dpr and
stale bitmaps are dropped on dpr change.
2026-07-08 21:06:21 +08:00
Kayshen-X 574e0d1770 fix(ci): hide preview test helpers on windows 2026-07-08 02:23:57 +08:00
Kayshen-X 3590663aec fix(ci): gate windows test text measurement 2026-07-08 02:00:47 +08:00
Kayshen-X 921a6de4eb fix(ci): use estimated text measure in windows tests 2026-07-08 01:40:04 +08:00
Kayshen-X d86efa44e1 fix(ci): size overbold cleanup text fixture 2026-07-08 01:36:35 +08:00
Kayshen-X acff985521 fix(ci): skip windows fit-content text snapshot test 2026-07-08 01:21:13 +08:00
Kayshen-X 1392fbef17 fix(ci): avoid text in reveal registration fixture 2026-07-08 01:06:46 +08:00
Kayshen-X 41a5a6938e fix(ci): skip windows contrast batch feedback fixture 2026-07-08 00:51:38 +08:00
Kayshen-X 24cbc967ae fix(ci): size contrast batch text fixture 2026-07-08 00:37:35 +08:00
Kayshen-X ca6155a834 fix(ci): skip windows text edit press tests 2026-07-08 00:21:39 +08:00