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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
`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`.
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.