Commit graph

2171 commits

Author SHA1 Message Date
Fini f47c092247 feat(canvas): theme-adaptive image placeholder art
The missing/failed-image fallback derives its dash + glyph grey from the
slot's own fill luminance (one fixed grey was invisible on dark
designs); the search-failure sentinel src routes here so a failed
enrichment reads as an intentional placeholder.
2026-07-12 02:56:43 +08:00
Fini e26637debd feat(desktop): resilient agent runtime and cross-launch connections
CLI provider connections persist (connected flags only) and replay as
silent probes on launch; GUI launches graft the login-shell PATH onto
the process so CLI agents and API keys resolve without a terminal;
provider rate limits ride an adaptive throttle with longer retries and
a human-readable terminal error; quota errors fold into the transcript
as a sentence instead of raw JSON. Design turns keep the artboard in
view (fit on first sized root, refit only when growth pushes it out),
run the structural finalize backstop even when a turn dies early, and
image enrichment fills small and anonymous media slots with junk-free,
session-deduplicated, artifact-word-stripped searches - failures land a
theme-adaptive placeholder instead of a bare grey box.
2026-07-12 02:56:26 +08:00
Fini ebc30e3ed9 feat(ui): agent identity in chat transcript and chrome polish
Sub-agent turns carry a name + colour header in the transcript (hashed
into the canonical-build fingerprint so a mid-run identity arrival
relayouts), tool calls read as verb pills, the top-bar agent chip counts
ready built-in agents and sizes its icon cluster off the icons actually
painted, and the streaming stop control is a clear filled red square.
2026-07-12 02:56:26 +08:00
Fini 7a13421460 feat(canvas): Pencil-parity generation visuals
The generation language measured frame-by-frame from Pencil's hero
media: a fixed periwinkle skeleton blue independent of the design
palette, tall smooth placeholder sweep on queued shells only (dominant
empty regions stay plain until engaged), wireframe-ghost
materialization before each node's pop-in, a slow breathing border on
the element being output, and a larger pencil cursor that eases
node-to-node (ease-in-out flights with a micro-dwell, plus a full
flight lead on cross-batch reveals so it never teleports). Agent
identities rotate name and colour per run, and the cleared starter
frame paints as a ghost until the design's sized root arrives.
2026-07-12 02:56:02 +08:00
Fini d79604f9ae feat(editor): property edits on component-instance children
Selecting a node INSIDE a component instance now routes property-panel
writes (color, stroke, size) through descendant overrides on the owning
Ref via virtual child anchors, instead of silently doing nothing.
Scope-time history snapshots are repaired against the routed Ref (both
the ref id and the routed display id) on the Arc-shared snapshot store,
so undo never resurrects a detached instance copy.
2026-07-12 02:55:42 +08:00
Fini 6240f2b462 feat(orchestrator): geometry-driven contract repairs for weak-model output
New deterministic passes measured against real failing runs: avatar and
row-thumbnail slots squared and clipped (pill, fill-width and
avatar-named-image variants), empty twin stubs beside images removed,
fill-sized images inside layout:none containers pinned to the parent
rect, slightly-short fixed frames grown to cover their children,
oversized images clamped to their slot, empty bottom-tab-bar shells
filled with a standard 3-tab set, nav normalization freed from the
resolved-height gate (fit_content roots were silently skipped) and its
x:0 absolute pin dropped so the nav stays in flex flow. The scaffold
presets a full artboard by device class, chart/scroller guards keep the
self-check's hands off intent-class structures, and the finalize suite
runs on the loop path too. Adds the env-gated forensic harness that
replays any .op through the real layout with full diagnostics.
2026-07-12 02:55:42 +08:00
Fini 7de4233aa8 feat(agent): type-routed sonar loop with per-batch canvas feedback
Design requests route by type (mobile/landing to the agentic loop,
desktop to the orchestrator; env force-flags keep both reachable). Every
write batch echoes what the real layout proves wrong - geometry
diagnostics, contrast, icon glyph misuse, duplicate roots, hairline
rings, icon-only header rows, unbound image slots and an empty-shell
countdown - and the root seed guard pre-inserts mobile chrome, replaces
hand-built status bars with the canonical one and sweeps nested
duplicates every batch. The pristine-starter clear now hands off to a
visual ghost until the design's sized root lands.
2026-07-12 02:55:16 +08:00
Fini 4ca9977f13 feat(ai): design-agent skill supply, contracts and canvas context brief
The loop's system prompt now carries the same domain skill depth the
orchestrator injects per subtask, plus the protocol contracts distilled
from measured failures: skeleton-first shells with numeric estimated
heights, host-inserted status bar (never build one), avatar/row-thumb
square slots, thick progress rings, single-row mobile headers, explicit
x/y/w/h inside layout:none containers, and G() image-fill discipline.
design_context_brief injects the live canvas inventory (screens, fonts,
saturated accents, copyable chrome ids) so screen 2+ reads as the same
product.
2026-07-12 02:55:16 +08:00
Fini 2755c84c71 feat(mcp): transactional batch_design with weak-model parse tolerance
Any failing operation now rolls back the whole batch and returns
applied:false with a resend hint, so a partial tree never lands; the
orchestrator's program_gen keeps best-effort semantics via an internal
line policy. The normalize layer additionally absorbs the measured
weak-model dialects: stroke objects without the required thickness
(aliased from width/weight, defaulted to a hairline), empty strokes,
structured layout objects, and Figma/Pencil auto-layout field names -
each of these previously rejected one node and cascaded into
parent-not-found drops for its whole subtree.
2026-07-12 02:54:54 +08:00
Kayshen-X 42c50a42f8 style(editor-core): rustfmt reflow in color_picker and history snapshot 2026-07-11 19:38:59 +08:00
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