Commit graph

2208 commits

Author SHA1 Message Date
Fini be8fb65c0e fix(canvas): feather the cursor halo
A single wide 28% band read as a dirty grey ring - the glow is now three
concentric strokes with falling alpha, approximating a soft blur with
the primitives available.
2026-07-14 00:29:35 +08:00
Kayshen-X 20bf8f123b refactor(cli): split app control tests 2026-07-13 21:41:23 +08:00
Danny Ahn f8cfcab7fd fix(cli): validate document before starting headless MCP server
Preflight headless document loading so malformed or binary archives fail with a clear, actionable error before the MCP server starts.

Keep the CLI parser dependency lightweight by disabling op-pen-loader default features and include the updated lockfile plus regression coverage.
2026-07-13 14:29:48 +08:00
Kayshen-X bb0e85761b docs(readme): sync cli and skill guidance 2026-07-12 19:53:05 +08:00
Kayshen-X 7ec373c9a7 feat(cli): export pages nodes and live selection 2026-07-12 17:52:36 +08:00
Kayshen-X 1215633e54 feat(mcp): export pages nodes and live selection 2026-07-12 17:48:45 +08:00
Kayshen-X 6fc717546a feat(export): render resolved pages and nodes to bytes 2026-07-12 17:42:52 +08:00
Kayshen-X 4542d62a98 fix(web): handle pencil cursor settings selection 2026-07-12 15:02:05 +08:00
Kayshen-X a2c26855df chore(agent): update vendor agent submodule 2026-07-12 14:39:30 +08:00
Fini 2ed6f512ee feat(canvas): halo outline and fattened rounded pencil
User-picked O4 treatment: a wide translucent slate halo OUTSIDE the
white rim keeps the cursor silhouette readable on light designs while
the white edge stays crisp on dark ones (contact shadow relaxed to
compensate). The default rounded silhouette is additionally fattened
1.28x across the pencil axis with the tip hotspot fixed.
2026-07-12 13:21:34 +08:00
Fini 1875248224 fix(ui): normalize narration markdown after design-block extraction
Stripping backticks before the extractor destroyed the json fences it
keys on - three transcript hit tests caught it.
2026-07-12 13:11:16 +08:00
Fini c7931fb9a2 feat(mcp): apply_design_system tool and readable narration prose
apply_design_system applies one of the bundled presets (full variable
table + Mode theme axis) as a single undoable batch on both the MCP and
design-agent surfaces. The transcript additionally normalizes streamed
narration markdown - emphasis/backtick markers stripped, glued bold
headings re-broken onto their own lines, dash bullets rendered as
bullets - so the design-loop commentary reads as prose instead of
asterisk soup.
2026-07-12 13:10:15 +08:00
Fini 0c02e957fc feat(ai): bundle four built-in design-system variable presets
Complete shadcn-vocabulary token tables (background/card/primary/muted/
sidebar families plus font and radius tokens) with Light+Dark theme
values, parsed once from a bundled asset and exposed with a
set_variables-ready payload per preset. Groundwork for the
apply-design-system tool and shadcn-aligned variable naming.
2026-07-12 12:59:57 +08:00
Fini 208327e8c3 fix(orchestrator): search-shell normalizer no longer strips real search bars
The nested-shell pass misfired on a search bar whose children are bare
icon/text leaves (the bar IS the input): its authored background was
stripped, the search glyph painted white and the filter glyph re-inked
with a dangling $color-accent that rendered the fallback blue. The pass
now requires container children and, for the legit nested case, moves
the button's own demoted accent hex onto the glyph instead of a symbolic
ref.
2026-07-12 12:59:57 +08:00
Fini e63eb05bba feat(ui): user-selectable pencil cursor styles and Pencil-style narration flow
Settings > System gains a pencil-cursor picker - five silhouettes
(classic, rounded, chubby with a pink eraser, crayon, round-nib marker)
drawn as live swatches, rounded as the default, choice persisted in
~/.openpencil/ui.json and restored on launch. Design-loop narration
additionally streams as visible prose instead of folding into the
collapsed thinking area, and every tool call stamps the content offset
where it landed so the transcript can interleave prose with per-call
verb chips.
2026-07-12 12:32:59 +08:00
Kayshen-X bd7e28dadc fix(desktop): parse login shell paths consistently 2026-07-12 10:26:18 +08:00
Kayshen-X 206bae5b2b test(renderer): satisfy clippy for glyph coverage 2026-07-12 09:15:49 +08:00
Kayshen-X a6bb3b24ac test(editor): cover explicit center alignment controls 2026-07-12 09:14:49 +08:00
Kayshen-X 7a6f11a7f9 fix(web): refresh text rasters for effective scale 2026-07-12 09:13:49 +08:00
Kayshen-X 689c7cfd45 test(export): cover selected-node svg routing 2026-07-12 09:12:49 +08:00
Kayshen-X fb95d6b8b8 fix(editor): preserve scoped instance history states 2026-07-12 09:11:49 +08:00
Kayshen-X cb0842a5c9 feat(panels): reorder multiple fill layers 2026-07-12 09:10:49 +08:00
Kayshen-X df5a9aa8b2 test(i18n): preserve explicit locale across restart 2026-07-12 09:09:49 +08:00
Kayshen-X 4b96ac6bf0 fix(ai): surface custom provider connection failures 2026-07-12 09:08:49 +08:00
Kayshen-X 3a825cbfe1 feat(canvas): paste clipboard images as nodes 2026-07-12 09:07:49 +08:00
Kayshen-X 4fb6510ce0 test(renderer): cover Cyrillic design text fallback 2026-07-12 09:06:49 +08:00
Kayshen-X 0e15433239 fix(panels): keep layer actions clear of long names 2026-07-12 09:05:49 +08:00
Fini 0e10996674 feat(canvas): rounded pencil cursor silhouette
User-picked variant B: round shoulders at the eraser butt, a curved
collar seam and a soft tip wedge - the quadratic arcs are baked as
dense polygon samples so the existing polygon painters render them
smoothly with no new backend primitive.
2026-07-12 04:19:01 +08:00
Fini c447fcf998 feat(canvas): queued shells stay invisible until their turn
Waiting skeleton shells painted their author-given dark fills as odd
slabs below the section being worked. They now keep their layout slot
but paint nothing until they become the on-deck shell (Pencil shows
plain canvas where work has not reached). The agent colour pool also
swaps golden yellow and pale mint for cobalt and emerald - the white
pill label was unreadable on both.
2026-07-12 04:13:52 +08:00
Fini 518a51a9c7 fix(panels): readable layer hover icons and a quieter globe button
The eye/lock hover glyphs drew straight over long layer names - they
now sit on a locally rebuilt row surface (panel bg + the row's own
wash). The locale globe drops its chevron and paints like its icon
siblings.
2026-07-12 04:04:22 +08:00
Fini 5ec0b7102b fix(ui): design turns wear the run's agent persona
A DeepSeek turn was labelled 'Codex CLI' - built-in models no longer
wear a CLI's name (they show their provider group label), and a design
run restamps the streaming bubble with its assigned persona name and
colour, matching the canvas cursor pill and badge.
2026-07-12 04:04:22 +08:00
Fini 57cbb5dabc fix(canvas): scan follows pure work order across regions
The size-based exclusion kept the dashboard's main column dark even
while its own subtask was running - content then popped in with no
skeleton at all. Work order alone expresses both measured expectations:
a later region stays plain while an earlier shell is unfilled, and the
big column washes the moment it becomes the first empty shell.
2026-07-12 04:04:22 +08:00
Fini 075b1f25eb refactor(ui): retire the fixed 'Pencil it out' checklist panel
The pinned checklist duplicated what the transcript already renders
inline (action steps, subtask cards, verb chips, agent narration - the
Pencil-style reading flow), while eating a third of the panel's height.
The transcript is now the single progress surface; the checklist
widget, its hit/scroll wiring on both hosts and its ChatState fields
are removed.
2026-07-12 03:34:36 +08:00
Fini 2586f06cc3 fix(orchestrator): stretch the empty content column to the artboard
The two-column scaffold's Main Content was fit_content and collapsed to
its own padding (a 940x64 strip beside a full-height sidebar) until the
first subtask landed. With the root now presetting a full artboard
height the empty column can safely fill it; the finalize height-adjust
still sizes the root off real content.
2026-07-12 03:16:15 +08:00
Fini 6fe4c8f5e6 fix(agent): salvage duplicate-echo scripts and gate scan to work order
DeepSeek V4 sometimes echoes a whole script-gen source a second time
glued mid-line, and the re-declared consts threw 'invalid redefinition'
- a valid section then burned its retries. A new repair rung detects the
first declaration recurring and runs the first copy alone. The
placeholder scan additionally follows work order: within each container
only the first empty shell (the one on deck) washes, so a queued right
column never glows while the sidebar is still being output.
2026-07-12 03:01:28 +08:00
Fini b61a859396 chore(vendor): bump agent runtime submodule 2026-07-12 02:56:43 +08:00
Fini 3173524f7b chore(smoke): audit rubric and loop-vs-orchestrator A/B harness
Headless audits now report chrome completeness, node-kind vocabulary and
density alongside the issue counts; scripts/ab-g3 runs the same prompts
through both generation paths and tabulates the rubric for routing
decisions.
2026-07-12 02:56:43 +08:00
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