Repository navigation
Releases
OpenPencil v0.8.5 — Design on Desktop, Android, and iOS
v0.8.5 brings the Rust editor to Android and iOS, alongside a redesigned
Studio Home and a more complete path from a brief to an editable design and
exported code. This release also improves multi-screen generation, reference
images, interactive previews, and the tools available to external agents.
Highlights
- Android and iOS editor shells. Touch editing, native file and account
flows, and lifecycle-aware generation use the shared Rust engine. - Studio Home and design workspaces. Start from a prompt or reference,
compare design directions, and inspect generation results and quality reports. - More faithful AI output. Planning and repair better preserve requested
screens, supplied copy, image intent, and the geometry of repeated layouts. - Interactive previews. Preview authored interactions, scrolling, and motion
alongside the editable canvas. - Websites and brands as starting points. Website import and brand
extraction help turn existing visual material into editable design context. - Code export for agents. Deterministic code export is available through
MCP and the CLI; a lean MCP profile exposes a focused design workflow. - Kimi Code integration. Desktop and daemon hosts can run text-only
generation through the Kimi Code CLI, alongside existing provider integrations.
Android and iOS
The mobile shells share document rendering and editor logic with the desktop
app while using platform-native file pickers, sign-in screens, and lifecycle
handling. Touch selection, panning, pinch zoom, keyboard insets, and model-picker
gestures receive dedicated handling rather than relying on mouse input.
User-started generation can continue through supported background transitions:
Android uses a foreground service, and iOS uses the operating system's
background-processing allowance. Completion and cancellation are coordinated
with the engine lifecycle. These paths remain subject to system time limits,
power policy, and process termination; force-quitting does not preserve a
running generation task.
Android distribution uses a signed APK for direct installation and an AAB for a
later Play Console submission. Both are published with checksums in the GitHub
prerelease. The iOS release lane uploads to App Store Connect for TestFlight
processing. Neither lane automatically publishes an app to Google Play or
submits an App Store review.
AI Generation and Agent Workflows
- Multi-screen fallback planning keeps declared screens separate instead of
silently folding them into one composition. Image prompts carry more precise
subject, aspect, and label intent. - Layout repair handles more repeated-row and calendar overflow cases, as well
as text or glyphs hidden behind shapes. These checks supplement the model's
output rather than treating a completed response as proof of a usable design. - Chat attachments follow provider capability checks. Unsupported attachments
produce an actionable error while preserving the draft and its images. - Mobile chat work is bound to its document, page, tab, and account session, so
late output from a replaced document or cancelled session is rejected. - Codex sessions can continue reconnecting after a stream interruption, and
Kimi Code gains a dedicated generation transport. - MCP and CLI users can export code directly from the document. The lean MCP
profile offers a smaller sequence for inspecting, generating, checking, and
finalizing a design.
Editing and Reliability
The home screen's recent-file rows, mobile model picker, and touch cancellation
paths have been refined. Collaboration verification accepts valid signed
policy windows up to ninety days while retaining expiry and signature checks.
The release also updates runtime and TLS dependencies and tightens production
authentication archive verification.
Hosted Model Availability
The Hosted text-model runtime is shared by desktop, daemon, Android, and iOS,
including account-session checks and cancellation of stale requests. Publishing
v0.8.5 with Hosted enabled requires a reviewed, complete, signed ABI 4
authentication matrix and adoption of its release policy. Release and TestFlight
checks must verify that matrix and the ABI selected for each final link before
publication.
Hosted use also requires an active eligible plan, an available provider route,
and sufficient credits. An ABI 3 archive supports sign-in and collaboration but
cannot enable Hosted. Local Debug authentication overrides remain limited to
development builds. Hosted image input remains disabled under the current
billing capability contract.
Upgrade Notes
- Android and iOS artifacts follow their respective GitHub Release and
TestFlight channels; TestFlight availability follows Apple's processing. - Mobile builds use the same
.opdocument model, but platform-specific export
and background-execution limits still apply. - CLI-based agent integrations run on native desktop or daemon hosts; the
mobile engine does not launch desktop CLI processes. - Source builds must use the adopted, signed authentication artifacts for
production login and collaboration. Missing or mismatched release inputs
fail validation rather than falling back to a local Debug archive.
Web Docker Image
- Image:
ghcr.io/zseven-w/openpencil-web:v0.8.5 - Digest:
sha256:cde598b84c61410991b4eae80e792f12780027905b755b96f2e70f5d76e1e514
Verify Your Download
Every asset is listed in SHA256SUMS.txt and carries a signed build-provenance attestation tying it to this repository, commit, and CI run:
gh attestation verify <downloaded-file> --repo ZSeven-W/openpencilSome antivirus engines heuristically flag low-prevalence installers — see docs/security/antivirus-false-positives.md.
OpenPencil v0.8.4 — The Relay Works, and Agents Can Reach the Rest
v0.8.4 has two halves.
The first is corrective. v0.8.3 shipped collaboration end to end, but in the
published builds the public relay could never start: every attempt — China
region or Global, owner or guest — ended with "the public relay is temporarily
unavailable." The service was healthy the whole time. The binaries were not.
The cause was a single space character, and this release fixes it along with
the three separate reasons that one character was able to reach users and stay
invisible: a build that could not detect it, an error that lied about it, and a
diagnostic path that erased it.
The second half closes a gap of a different kind. v0.8.3's presentation
workflow, scene-template catalogue and asset centre were reachable only from
the desktop's own menus, so an agent driving OpenPencil over MCP — or a script
driving it through the CLI — could build a deck and then had no way to hand it
to anyone, could not start from a template, and could not see the style guides
the user had imported. Six tools close that, and the CLI grows the matching
commands.
A third, unrelated failure goes with them: the in-app update check reporting
"cannot reach the release server, check your network connection" on networks
that were working fine.
Highlights
- Public relay works in published builds. The hub endpoints baked into the
release binaries were malformed; corrected at the source. - A malformed hub endpoint now fails the build. It can no longer ship.
- Relay errors tell the truth. A refused sign-in, a rate-limited hub, an
unreachable network and a broken build are four different messages now. - Decks, templates and style assets reach MCP and the CLI. Export a deck to
PowerPoint, HTML or PDF; start from any shipped scene template, including the
16:9 decks; list the style guides the user imported; batch-export every frame
on a page. The MCP catalogue grows from 123 tools to 129. - Update checks survive shared IP addresses. The probe falls back to the
releases Atom feed when GitHub's anonymous API quota is exhausted.
The Relay Fix
What happened
The production hub URLs are deliberately absent from the open-source tree. The
release pipeline injects them at compile time from repository secrets, and
relay_bootstrap_select.rs reads them with option_env!.
Both secrets had been saved with a leading space:
" https://op.zseven.cn/api/v1/collaboration/bootstrap"
" https://op.zseven.tech/api/v1/collaboration/bootstrap"
option_env! bakes the value in exactly as stored, space and all. The runtime
endpoint policy is deliberately strict — it rejects any value where
value.trim() != value — so the injected endpoint parsed as no usable hub,
and every relay attempt failed before a single packet left the machine.
Because both secrets carried the space, switching regions changed nothing. And
because the bad character is invisible in every log, every dashboard, and every
strings dump of the binary, nothing pointed at it.
Why it shipped
A guard for exactly this already existed —
injected_bootstrap_urls_pass_the_endpoint_policy_or_stay_absent — and it
passed, vacuously. Repository secrets are not exposed to the CI test job, so
the assertion took its "no hubs injected, nothing to validate" branch on every
run. The release job is the one that receives the secrets, and it ran no
such assertion.
The fix moves the check where neither job can miss it: a build script on
op-collab-host validates the injected endpoints at compile time and fails the
build with an actionable message.
error: failed to run custom build command for `op-collab-host`
OPENPENCIL_BUILD_COLLAB_BOOTSTRAP_URL_CN is not a usable collaboration hub URL
(the value has leading or trailing whitespace). Expected exactly
`https://<host>/api/v1/collaboration/bootstrap` with no surrounding
whitespace; check the repository secret for a stray space or trailing newline.
An absent variable stays valid — open-source and fork builds legitimately carry
no production hub, and continue to build.
Honest Failure Reporting
The single space was hard to find because the code actively hid it. Three
changes fix that, and they outlive this particular bug.
- A broken build no longer poses as an outage. An injected endpoint that
fails the policy now reports as not configured rather than temporarily
unavailable. The old copy invited the user to wait for a condition that could
never resolve on its own. - Control-plane failures are classified. Every call to the relay locator —
route publication, pairing-code publication, pairing-code claim — used to end
inmap_err(|_| RelayUnavailable). An expired collaboration ticket, a
rate-limited hub, an unreachable network and a malformed response all reached
the user as the same sentence. A refused ticket (HTTP 401/403) is now a
sign-in problem, a rate-limited hub (HTTP 429) is now a retry-later problem,
and only genuine transport and protocol faults remain "relay unavailable".
This also givescollab.error.rateLimited, translated in all 15 locales since
v0.8.3, its first real producer. - Stage diagnostics, without credentials. Control-plane failures write one
line naming the stage and the failure class. Only the failure enum — which
carries no payload — and a&'static strvariant tag are ever formatted; the
error's ownDisplayis deliberately never used, so a future payload field
cannot leak into a support log. A test enforces that every tag stays a bare
variant name.
Decks, Templates and Assets for Agents
Everything below already existed in v0.8.3; none of it was reachable except
by hand, from the desktop app's own menus. An agent could build a deck and not
deliver it, or be told a template catalogue existed and be unable to open it.
Deck export. export_deck { format, outputPath } writes the active page's
boards as an editable PowerPoint, one self-contained HTML file, or a
slide-per-page PDF — op export-deck --output PATH [--format pptx|html|pdf]
from the CLI. It writes a file rather than returning base64: a deck is a
multi-megabyte artifact and the caller wants something shareable. The
destination argument is outputPath, because filePath means "the .op
document this call targets" everywhere in this API.
Scene templates. list_scene_templates and use_scene_template
(op templates, op use-template <id>) open the shipped catalogue, the six
16:9 deck templates included — which makes it the entry point to the
presentation workflow rather than a convenience. On an untouched starter page a
template takes the page over; anywhere else its boards are appended to the
right of what is already there.
Style assets. list_style_guides (op styles) merges the shipped corpus
with the DESIGN.md files the user imported, imports first, as the Asset
Centre paints them. The imports were the gap that mattered: get_style_guide
searches the shipped corpus only, so the user's own material was invisible to
MCP entirely. Passing id returns one guide with its markdown, which is what
closes the loop for an import.
Batch export and deck inspection. export_frames { outputDir, format }
(op export-frames --output-dir DIR) writes one image per top-level frame
using the editor's own file naming — collisions resolved, long AI-authored
names capped, hidden frames skipped — and reports per-frame failures instead of
discarding the files that did land. get_deck_boards lists the boards a deck
export will walk, so a deck can be verified before one is written.
Slideshow control is deliberately not part of this: entering preview is a host
mode transition rather than document state, and a file-backed MCP session has
no window to present in.
The three file-writing tools (export_deck, export_frames,
list_style_guides) are local-filesystem surfaces and are denied on the online
multi-tenant /mcp, for the same reason save_document is.
Update Check
The in-app update check reported "cannot reach the release server, check your
network connection" for users whose network was fine. GitHub's anonymous API
allows 60 requests per hour per source IP, so anyone behind a shared egress
— corporate NAT, a VPN, most China-region proxies — can find the quota already
spent by strangers:
403 {"message":"API rate limit exceeded for <shared-egress-ip>."}
The probe now falls back to the releases Atom feed, which is served by
github.com rather than api.github.com and is not on that quota. The JSON API
stays the first choice for its richer response; the feed only has to cover the
case where the API refuses to answer at all. Drafts never appear in the feed,
which is the same rule the API path already applied.
Fixed
- Public relay unusable in all published
v0.8.3builds, in both service
regions, for owners and guests alike. - Update check failing with a network error on shared egress IP addresses.
- A misconfigured relay build reporting as a temporary service outage.
- Expired collaboration tickets, rate-limited hubs and network faults sharing
one indistinguishable relay error. - Deck export, the scene-template catalogue, imported style guides and batch
frame export being unreachable from MCP and the CLI.
Upgrade Notes and Compatibility
- Upgrade to restore the public relay. No server-side change is needed and
no action is required from you beyond installing this release — thev0.8.3
hubs, regions and pairing codes were correct throughout. Local-network
collaboration was never affected. - Pairing codes and sessions are unchanged. The 10-character region-tagged
pairing code, the wire protocol, and the bootstrap document format are
identical tov0.8.3; av0.8.4peer and av0.8.3peer interoperate on any
path av0.8.3peer could already reach. - Sign-in prompts may replace relay errors. With ticket rejection now
cl...
OpenPencil v0.8.3 — Design Together, Present Anywhere
v0.8.3 is the release where OpenPencil stops being a single-seat tool. Real-time
collaboration arrives end to end — authenticated peer-to-peer sessions, a public
relay for peers that cannot reach each other directly, and built-in regional
hubs — joined alongside browser device login and an online multi-tenant web mode
authenticated against the op-hub. For the first time, two people (or a person and
an agent) can sit in the same document, see each other's cursors, and reconcile
divergent edits without leaving the canvas.
Around that foundation the release grows a full presentation workflow: six 16:9
deck templates, an AI planner that lays out one slide per screen at projector
size, a live slideshow presenter, and export to PDF, self-contained HTML,
editable PowerPoint, and a video composition. A new scene template center lets
you start from a real layout instead of a blank frame, the prompt and asset
centers mature into full-window surfaces, and an official Chrome web-capture
extension snapshots any live page into OpenPencil.
Under the surface the web bundle gets lighter by fetching templates, the icon
catalog, and preview art at runtime instead of embedding them; theme becomes a
per-device preference; and the account/collaboration stack ships prebuilt
op-auth libraries with safe production trust-root rotation. This document walks
through each area, what problem it solves, how to use it, and who benefits.
Highlights
- Real-time collaboration — authenticated P2P with a public relay fallback
and built-in regional hubs, joined with a 10-character region-tagged pairing
code. Live remote cursors, cross-account sessions, and a conflict panel that
replays discarded edits. - Online multi-tenant web mode — one
--serve-webdeployment can host many
tenants, authenticated against the op-hub, with cross-account tenant sharing,
eviction persistence, and a capability-scoped online/mcpsurface. - Device login — sign in from the browser through the serve-web daemon, with
a runtime account gate and authenticated profile avatars and usernames. - Presentation decks — six 16:9 templates and a picker, AI planning at
projector size, a slideshow presenter, and PDF / HTML / PowerPoint / video
export, backed by agent geometry validation of every board. - Scene template center — a browsable catalogue of 58 templates across six
scenes, from File ▸ New from template, mounted in the browser host too. - Chrome web-capture extension — snapshot any webpage into OpenPencil with
faithful HTML, icon, and layout capture, delivered to your account's snapshot
inbox on the hub, or downloaded offline as a ready-to-open.opfile. - Lighter web runtime — scene templates, the icon catalog, and preview assets
are fetched at runtime instead of embedded in the wasm bundle. - Theme is now a device preference on the web host.
Real-Time Collaboration
Collaboration is the headline of this release, and it is built to work whether
your peers are across the desk or across the internet. The goal was a session you
can start in seconds, trust by default, and recover from cleanly when two people
edit the same thing at once.
Starting a session
A session can form three ways, and the client picks the best available path:
- Direct peer-to-peer. When peers can reach each other, they establish an
encrypted channel and talk directly — the lowest-latency path, ideal for a LAN
or a well-connected pair. - Public relay. When a direct connection is not possible (NAT, firewalls,
different networks), a public relay carries the encrypted traffic between peers.
The client tolerates public-relay handshake latency and reports join failure by
stage, so a slow or unreachable relay produces an actionable message instead of
an opaque hang. - Regional hubs. Built-in regional collaboration hubs give sessions a nearby,
known meeting point so peers do not have to discover each other manually.
Whichever path is used, joining is the same: a host shares a 10-character,
region-tagged pairing code that replaces the older open-invite scheme. The
region tag routes participants to the right hub; the short code is easy to read
aloud or paste. On the desktop the join field lives on the unified text input —
paste-to-replace, selectable, and clearable — so entering a code feels like every
other field.
Presence and live editing
Once joined, every participant is present on the canvas. Remote cursors are
painted with the agent pointer so you can see where collaborators are working in
real time, and their avatars are proxied through the daemon rather than fetched
directly by the browser — the browser never talks to an avatar host on its own.
Edits stream between peers as they happen, and the browser host gained
session-safe sync recovery and SSE fan-in so a reconnect re-syncs cleanly rather
than forking the document.
Resolving conflicts
Concurrent editing means occasional divergence, and OpenPencil surfaces it
instead of silently picking a winner. A conflict panel shows per-node,
per-field detail for the edits that collided and can replay the edits that were
discarded during a divergence, so a change that lost a race is recoverable
rather than lost. Queued actions are deferred until a gesture's capture closes, so
an in-flight drag on one side does not corrupt the other side's view of the scene.
Cross-account and hardening
Cross-account collaboration lets people signed in to different accounts share one
session — useful when a designer and a reviewer are on separate hub accounts. This
cycle also put substantial work into resilience: resource-exhaustion guards on the
p2p path, whole-second keepalive clamping, secure-relay transport-failure
classification, gesture-capture ordering fixes, an aligned reauthentication
budget, and — most importantly for a hosted deployment — safe rotation of
production trust roots, so the set of keys a client will trust can change
without breaking live sessions.
Who benefits: designers get pair-design and live review; agent users get a
shared canvas an AI can drive while a human watches the cursor move; teams get a
session model that degrades gracefully across networks.
Accounts, Device Login, and Online Hosting
Collaboration needs identity, so v0.8.3 brings account sign-in out of the earlier
prereleases where it was intentionally hidden.
Signing in from the browser
Browser device login runs through the serve-web daemon: a runtime account gate
governs access to account-scoped features, and once you sign in the editor shows
your authenticated profile avatar and username. The flow reports the machine name
to SSO for device identification. The desktop build links a prebuilt op-auth
library — shipped for Intel and Apple-silicon macOS, Linux, and Windows (MSVC
and arm64) — so the auth bridge is available without a separate build toolchain,
and it is linked to survive thin-LTO release builds.
Online multi-tenant mode
The --serve-web daemon can now run as a shared, multi-tenant host rather than a
single-user server. Tenants are authenticated against the op-hub, and the mode
supports cross-account tenant sharing whose membership persists across
evictions, plus session node creation, account-switch isolation, and tenant-aware
URLs so one deployment cleanly serves many accounts. The online /mcp surface
authenticates the live endpoint and enforces a capability profile and scope,
so a hosted MCP client only sees the tools and documents it is entitled to, and
the bootstrap cache degrades safely when the endpoint is unavailable.
Who benefits: developers and teams can stand up one hosted OpenPencil for a
group instead of one server per person, with per-tenant isolation and a scoped
automation surface.
Presentation Decks
Decks are a first-class document type in v0.8.3, closing the loop from "generate a
layout" to "stand up and present it."
Templates and planning
Start from one of six 16:9 deck templates through the template picker, or
describe a deck and let the AI plan it. The planning corpus learned that a
projector board differs from a page: the agent plans a deck at projector size
with one slide per screen, scaffolds the screen roots in a single insert, and
wraps multi-board templates onto rows on the canvas. Crucially, the agent now
judges each board by its geometry as well as its prompt — pinning boards to the
projector aspect, centering board content instead of stacking it at the top, and
reporting row overflow rather than clipping it — so generated decks come out
presentation-ready.
Presenting
A deck can be presented as a slideshow directly in preview, with presenter
controls to drive it forward and back. A dedicated slides rail is the deck's
single navigator, replacing ad-hoc scrolling with a predictable slide list.
Exporting
When a deck is done, export it to the format the audience needs:
- PDF — one page per slide.
- Self-contained slideshow HTML — a single file that plays anywhere a browser
is available, no assets to ship alongside. - Editable PowerPoint (
.pptx) — hand off to anyone who lives in PowerPoint. - Hyperframes video composition — emit the deck as a motion composition.
Who benefits: designers can produce a real deck without leaving the tool;
developers and PMs get portable output (PDF/HTML/PPTX) that drops into existing
workflows.
Scene Templates, Prompt Center, and Asset Center
Three surfaces matured this release to make starting and iterating faster.
- Scene template center — a browsable catalogue that grew to 58 templates
across six scenes, opened from File ▸ New from template, mounted in the
browse...
OpenPencil v0.8.2 — Whole Apps, Faithful Imports
v0.8.2 is a prerelease focused on higher-fidelity Figma and HTML imports,
multi-screen AI design generation, lower transient memory use, smoother
large-document workflows, safer .op persistence, and backward-compatible
schema evolution.
This update expands both the data OpenPencil can preserve and the controls
available for editing that data. It also separates expensive conversion and
save work from the interactive UI, tightens overwrite behavior, and documents
where memory is reduced versus where the complete canonical document must
still remain available.
Highlights
- Figma imports preserve substantially more of the authored component,
geometry, compositing, image, text, and page data that previously required
flattening or approximation. - Component instances keep their backing component information, instance
properties, swap targets, overrides, authored geometry, and style
references. - Masks, layer and fill blend modes, image tiling, and page backgrounds now
round-trip through the schema, renderer, web host, and property inspector. - Desktop conversion runs outside the UI thread and reuses prepared values,
source text metrics, image lookups, instance assignments, and component
style references. - Large documents use an active-page editor scene. Native page switching drops
the previous scene before building the next; native and web both fit and
center the newly active page. - Desktop Save and Save As run as serialized background jobs, while native
publication uses atomic writes and source revalidation. - Known legacy
.opformats can be upgraded in place, saved as a numbered
copy, or opened without modifying the file on disk. - HTML import accepts complete pages, multi-file projects, and ZIP packages
with local resources, nested CSS imports, and common text encodings. - The design agent generates multi-screen apps: screen groups can run in
parallel, shared navigation is unified across screens, and app-mode screen
navigation is wired into the generated document. - Panning and zooming very large documents uses layer caching and
level-of-detail so gestures stay responsive instead of dropping to a few
frames per second.
Figma Import Fidelity
Components, Instances, and Swaps
- Component property definitions are retained as structured component backing
data instead of being reduced to only the visible instance result. - Instance property assignments and overrides keep their relationship to the
backing component so later edits can distinguish inherited and authored
values. - Instance-swap properties preserve the selected component target and filter
invalid candidates instead of silently substituting unrelated symbols. - Swapped subtrees retain their authored size, transform, paint, and style
references. Instance scaling is restricted to component-space branches so it
does not rescale ordinary descendants a second time. - Foreign and nested component sessions reuse resolved assignments and style
information, reducing differences between repeated instances of the same
source component. - The property inspector exposes component and swap configuration for imported
instances instead of leaving the imported metadata inaccessible.
Geometry, Layout, and Text
- Authored absolute positioning is preserved for layers that should not be
reflowed by an inferred container layout. - Child order and paint order follow the Figma source more closely, including
mixed container, vector, and mask content. - Boolean operations recover usable child geometry when the preferred result
stream is empty, while genuinely empty geometry stays invisible instead of
becoming a filled placeholder block. - Expanded strokes, open vector networks, fill rules, vector bounds, rounded
vertices, and squircle-like smoothing have more accurate fallbacks. - Image-fill transforms and crop geometry are applied when mapping source
images into their authored bounds. - Source text metrics and baselines are reused consistently, while temporary
glyph, baseline, and font-resolution caches are released after their import
stage. - Text, vectors, image fills, and layout positioning now share more of the same
resolved geometry between interactive rendering and export paths.
Masks, Compositing, Images, and Pages
- Alpha, vector, and luminance masks render through the shared native and web
paint model. - Layer blend modes and individual fill blend modes are represented separately
so compositing does not need to be flattened into a single approximation. - Page background color is preserved in the document and can be edited from
the page section of the property inspector. - Tiled image fills keep their tile scale, while cropped and transformed image
fills retain the source mapping needed for closer visual parity. - Image resolution deduplicates repeated references and transformed assets
instead of decoding or embedding the same source for every occurrence. - The property inspector adds the previously missing controls for masks,
compositing, image tiling, page backgrounds, and component-instance data. - New schema fields are optional, so v0.8.2 can continue reading older
documents and TypeScript object literals that omit them. This does not claim
that every older OpenPencil version can read every v0.8.2 document.
Figma Conversion Performance
- Import preparation decodes and normalizes reusable source values once before
node conversion begins. - Figma-provided text metrics are reused across the relevant conversion stage,
and glyph, baseline, and font-resolution scratch data is released when that
stage completes. - Image lookup and decoded-image work are shared across repeated image
references and instance subtrees. - Component resolution caches instance assignments, swap decisions, style
references, and prepared component data. - The component registry keeps shallow lookup metadata instead of cloning every
master subtree into a second document-sized registry. - Image caches are budgeted by decoded bytes rather than only by entry count,
preventing a handful of very large images from bypassing the cache limit. - Shared image assets are deduplicated into the document image table on save
paths instead of being repeated by each consumer. - Desktop conversion runs in a background import session while the UI
continues processing input and repaint work. Cancellation prevents later
stages and result installation; an already-running, non-interruptible decode
finishes before its worker exits. - Heavy conversion workers are serialized so cancelling and starting another
import does not intentionally overlap two peak conversion workloads. - Large conversion payloads use shared or indirect ownership where possible,
reducing queue copies and temporary allocation amplification. - After a successful desktop conversion, the proposed
.opoutput sits beside
the imported.figsource instead of being kept only in a temporary
directory. - If that sibling
.opalready exists, OpenPencil asks before replacing it.
Replacing, keeping both with a numbered copy, and cancelling the import are
separate user choices. A detected existing target is not replaced without
that decision.
Large Documents, Memory, and Page Switching
- Desktop
.oploading memory-maps the source instead of first copying the
complete file into a second byte buffer. - Preserve-authored documents use a fast loader after validating that the
current shape is safe, avoiding the generic full compatibility DOM on the
common path. - The interactive native and web editor scenes materialize the active page
rather than building render trees for every page at once. - On native page switches, the previous page scene is dropped before the next
scene is built. The web host rebuilds and replaces the active scene. - Switching to a different page automatically fits and centers that page.
Selecting the already active page does not unexpectedly reset the current
viewport. - Non-active pages remain available to the editor but do not keep a full
interactive render scene alive. - This is scene-level memory reduction, not document-level page streaming. The
canonical document still retains the data for every page while the file is
open. - Import, save, and clean-copy paths use streaming or indirection where
practical to reduce duplicated buffers, queue size, and peak transient
allocations.
Canvas Performance on Large Documents
- Pan and zoom on very large documents (tens of thousands of nodes viewed
zoomed out) are substantially smoother. Each change below was measured
against a live profiling session rather than inferred. - The SVG path cache is budgeted by bytes instead of entry count, so a working
set of many thousands of visible paths no longer re-parses its own contents
every frame. - Text below roughly three device pixels skips shaping and paints a
representative bar, and leaf content below sub-pixel size skips painting
entirely. - Shadows and blurs that would render below one pixel skip their save-layers,
avoiding render-pass breaks and forced command submits that were expensive on
GL-backed Metal. - Pan gestures blit a retained offscreen layer with in-place scroll strips and
an approximate scaled zoom. The layer survives across gestures, and the
gesture-end frame restores full quality progressively, one tile per frame. - The event loop places periodic wait deadlines on a fixed grid so elapsed
deadlines are not re-armed immediately, removing an idle timer spin. OP_SLOW_FRAME_LOG=1prints frames over 32ms with blit, scroll, and build
attribution for diagnosing future regressions.
.op Saving and Overwrite Safety
- Desktop Save and Save As are seri...
v0.8.1-enhance
OpenPencil v0.8.1
v0.8.1 is a pre-release update for the Rust OpenPencil stack. It expands native agent and MCP integrations, makes the AI-assisted design loop more reliable, adds richer preview and export workflows, improves editor responsiveness and web rendering clarity, hardens web credential handling and host-local configuration isolation, and centralizes product-version management.
Highlights
- Antigravity and Grok Build are now first-class native CLI providers, with executable and authentication probes, model discovery, branded settings and model-picker entries, subprocess chat routing, and MCP configuration support.
- The design agent now uses transactional batch updates, four bundled design systems, bounded geometry-aware repair, stronger image-slot handling, and progress-ring preservation to produce more reliable layouts without unbounded retries.
- Desktop Preview adds Phone, Desktop, and Canvas presentation modes, scrolling inside fixed device frames, phone-only pinning for detected bottom navigation, and geometry-accurate painting and pointer mapping.
- Desktop and web SVG export can tightly crop one selected node, while CLI and MCP export pages, arbitrary nodes, or the live selection as PNG, JPEG, WebP, or PDF.
- CanvasKit caches, on-demand SDK animation frames, cached transcript and layer layouts, structurally shared undo history, and fewer document clones improve active and idle performance.
- CanvasKit uses the browser's full display scale with a 2x quality floor, keeping small text and one-pixel UI details sharper when an embedded browser reports DPR 1.
- Browser deployments keep web-entered credentials in same-origin storage by default, while trusted private deployments can explicitly opt into a server-persisted shared copy.
- The web host no longer imports local
~/.zodeprovider configuration; native desktop startup retains Zode discovery for local workflows. - Rust crates, SDK packages, installers, bundled CLI metadata, and release publishing now derive from or are checked against the root Cargo workspace version.
Native Agents and MCP
Antigravity and Grok Build
- Native Agent settings and the chat model picker now include Google Antigravity and xAI Grok Build with dedicated branding and provider identities.
- OpenPencil resolves the
agyandgrokexecutables across supported platforms, probes installation and authentication state, and provides actionable setup guidance when a provider is unavailable. - Model discovery queries
agy modelsandgrok modelswith bounded execution, parses their supported text and JSON catalog shapes, and falls back to a provider default when an installed CLI does not expose a usable catalog. - Chat sessions route through hardened subprocess parsing and safety rules. Canvas-agent chat turns and tool-free orchestrator, subtask, and code-generation turns use separate subprocess policies, preventing canvas MCP permissions and automation guards from leaking into structured generation.
- The MCP integration grid now includes Antigravity and Grok Build alongside Claude Code, Codex, Gemini, OpenCode, Kiro, and GitHub Copilot. Enabling or disabling OpenPencil updates the relevant client configuration while preserving unrelated servers and settings.
Generation Experience
- Design-loop narration, thinking, and tool activity now appear chronologically in the transcript instead of being grouped out of order.
- Streamed Markdown, clearer tool chips, stable agent identity, and unified generation feedback make native and CLI-backed runs easier to follow.
- Canvas generation uses sequential placeholders, animated agent presence, and five selectable Pencil-style cursors to show which area is being produced without obscuring completed content.
Design Agent Quality
- Transactional batch updates keep a failed design operation from leaving a partially applied document.
- Four built-in shadcn-vocabulary design systems—Halo, Lunaris, Nitro, and shadcn—can install complete Light and Dark variable tables in one undoable step.
- Repair is explicit and bounded. Geometry-aware passes handle overlaps, undersized content, radial stacks, image slots, and common scaffold defects without entering an unbounded retry loop.
- Image repair keeps one image per intended slot, reconnects stray photos to their containers, and avoids stretching controls or treating oversized decorative plates as image intent.
- Progress rings and other radial compositions retain their arc semantics and are recentered against final resolved geometry across platforms.
Preview, Canvas, and Editing
- Desktop Preview provides Phone, Desktop, and Canvas modes with device-frame clipping, vertical scrolling, accurate hit mapping, and phone-only pinning for recognized bottom navigation.
- Desktop clipboard paste accepts image data directly into the document.
- Multiple fills can be reordered without rebuilding unrelated paint layers.
- Component-instance child property edits are stored as overrides with undo-safe history.
- Web text rasterization accounts for display scale, and the CanvasKit backing store now has a 2x minimum render scale for sharper text and chrome in browsers or webviews that report DPR 1.
- Web startup no longer reads local Zode provider settings, preventing native-only model configuration from appearing as partially synchronized browser state.
- Jian updates normalize text line-height semantics and treat
designMdandconversionas known top-level schema fields.
Export and Automation
- Desktop and web SVG export tightly crop exactly one selected node and otherwise export the full active page. SVG is also available in the property-panel export controls.
- CLI and MCP export pages, arbitrary node IDs, or the live selection as PNG, JPEG, WebP, or PDF.
- Headless MCP startup validates the target
.opdocument before serving, so malformed or unsupported input fails early instead of creating a broken automation session.
Performance and Web SDK
- CanvasKit paint objects and fonts are cached instead of being recreated across frames.
- The web SDK requests animation frames only while work is pending, reducing idle CPU use.
- Transcript and layer-panel layout caches avoid repeating text measurement and tree layout for unchanged content.
- Undo snapshots share unchanged document structure, and editor mutation paths avoid several whole-document clones.
- The React and Vue adapters ship with the base
@zseven-w/op-web-sdkpackage family; the public SDK remains a read-only viewer surface.
Web Credential Persistence
Browser-entered built-in provider, image-generation, and Openverse credentials are stored separately from ordinary preferences in same-origin localStorage. By default, built-in provider credentials are attached only to AI requests that need them, and the daemon does not persist the browser credential snapshot to settings.json. At startup, browser-only mode removes browser-owned credentials left there by an earlier configuration.
Browser POSTs to credential and AI endpoints must pass an origin check, provider targets are validated, and upstream error bodies are not returned directly to browser clients. Public reverse proxies must list exact browser origins in the comma-delimited OPENPENCIL_WEB_ALLOWED_ORIGINS setting.
Trusted private deployments can enable server persistence with:
OPENPENCIL_PERSIST_WEB_CREDENTIALS_SERVER=trueThis creates a deployment-wide shared credential copy and is intended for an access-controlled deployment with one active administrator profile. It does not permit unrestricted outbound requests. Internal provider origins must be listed separately in OPENPENCIL_WEB_AI_ENDPOINT_ALLOWLIST. Because same-origin scripts can read localStorage, deployments must also protect the web origin from untrusted scripts and XSS.
The web host continues to expose built-in API-key agents only. CLI and ACP agents, including Antigravity and Grok Build, remain native-only and are not exposed through web connect routes.
Web startup also does not import provider credentials or model entries from the host user's ~/.zode configuration. Zode discovery remains available to the native desktop host, where the configuration is local to the running application. This keeps browser and native provider catalogs intentionally separate instead of presenting unsynchronized local entries in the web model picker.
Release Engineering
- Root
Cargo.tomlis the canonical product version source. Rust crates inherit it through workspace metadata, and release/installer paths consume the same value. scripts/sync-version.shrefreshes managed version copies and runs the guard;tools/check-version-sync.shrejects drift across Rust metadata, the bundled CLI, SDK packages, installers, and release publishing.- The explicit
.opformatVersionand stable test-fixture versions remain independent of product releases and are intentionally excluded from product-version synchronization. - CI now runs native builds and tests on Linux, macOS, and Windows; cross-architecture compile checks for macOS and Windows; Android and iOS compile checks; plus
wasm32compile and real CanvasKit bundle guards.
Release Artifacts
- Native desktop installers and standalone
opCLI archives for macOS, Windows, and Linux. ghcr.io/zseven-w/openpencil-web:v0.8.1for the Rust web host.@zseven-w/op-web-sdk,@zseven-w/op-web-sdk-react, and@zseven-w/op-web-sdk-vueunder the npmnexttag, with package tarballs attached to the GitHub prerelease.- Updated Homebrew and Scoop manifests after the prerelease is published.
Compatibility
- The supported
.opformatVersionremains1.1, unchanged from v0.8.0. - The public web SDK remains a read-only viewer surface.
- The retired TypeScript application workspace is not part of this release.
...
v0.8.0-Second Vow
OpenPencil v0.8.0
v0.8.0 is a pre-release for the Rust OpenPencil stack. It marks the first release line where the Rust desktop, CLI, web host, and wasm-backed SDKs are the actively shipped OpenPencil product surface.
Highlights
- Rust desktop app is now the primary OpenPencil experience, with installer artifacts for macOS, Windows, and Linux.
opCLI ships as standalone release artifacts for the same desktop target matrix.- Rust web host is published as a GHCR Docker image for tagged releases.
- Web SDK packages are published to npm and attached as tarballs for
@zseven-w/op-web-sdk,@zseven-w/op-web-sdk-react, and@zseven-w/op-web-sdk-vue. - Homebrew tap and Scoop bucket entries are updated after the GitHub pre-release is published.
- Desktop update checks can discover pre-release GitHub releases, so
v0.8.0can be offered before it is promoted to a stable release. - Issue triage for this release reviewed 19 open GitHub issues: 5 are expected to close with v0.8.0, and 3 are partially covered but should remain open unless split into follow-ups.
What's New
Rust Editor
- The Rust editor shell is the release target for the canvas, panels, toolbar, property inspector, AI chat surface, agent settings, and desktop/web hosts.
- Canvas painting, hit-testing, and editor chrome now share the layout-resolved
LayoutScenepath, reducing stale scene lookups during hover, selection, pen editing, and reveal paint. - Rotated canvas elements now keep editor chrome aligned with rendered geometry:
- hover outlines follow the hovered node's root-to-node flip/rotation chain;
- single-selection and multi-selection outlines inherit rotated/flipped ancestor transforms;
- selected path editor handles and arc-edit handles inherit the same transform chain;
- fallback behavior still preserves direct node rotation for callers that do not have traversal-captured transforms.
- Canvas interaction paths continue to support pan/zoom, selection, handle hit-testing, rotation handles, pen/path overlays, smart guide overlays, layer hover state, and reveal animation paint.
- The widget layer remains platform-clean: native and web rendering go through the shared
RenderBackendfacade rather than Skia or browser APIs in widget code.
Desktop App
- Desktop artifacts are built from the Rust native host for macOS, Windows, and Linux.
- The desktop app can detect release availability from GitHub, including pre-release builds when the pre-release channel is enabled.
- File opening, recent-file persistence, MCP/web-service integration, and editor chrome are shipped through the Rust app path.
CLI
- The
opcommand-line tool is distributed as a standalone binary alongside desktop artifacts. - Installer scripts support stable releases by default and can opt into the newest pre-release with
OP_PRERELEASE=1. - Package manager manifests are updated for both desktop and CLI distribution channels after the GitHub pre-release is published.
Web And SDK
- The Rust web host is published as a GHCR image tagged with the release version.
- The web host agent settings expose built-in agent profiles only; desktop/CLI-oriented provider connect cards, ACP agent setup, and the MCP tab are hidden from the web UI.
- The public web SDK remains focused on viewing
.opfiles, backed by the Rust wasm bundle. - React and Vue adapters are published with the base SDK so host apps can embed
.opviewers without depending on the retired TypeScript app workspace.
Rust vs. TypeScript v0.7.5
v0.8.0 is not a routine patch on top of the TypeScript app. It is the first release line where the Rust implementation replaces the retired TypeScript + Electron stack that ended at v0.7.5.
Feature Comparison
| Area | TypeScript + Electron (v0.7.5) |
Rust (v0.8.0) |
|---|---|---|
| Primary app | React 19 + TanStack Start web app packaged with Electron 35. | Rust editor shell shared by desktop, web host, and SDK-backed rendering paths. |
| Desktop runtime | Electron app with bundled Chromium and Node.js runtime. | Native winit + GPU Skia desktop binary; no embedded browser engine. |
| Canvas and editor UI | CanvasKit/Skia canvas driven from React, Zustand stores, and pen-* packages. |
Layout, hit-testing, painting, overlays, and editor chrome run through Rust LayoutScene and RenderBackend. |
| CLI | op CLI compiled from TypeScript and connected to the web/desktop server path. |
Standalone Rust op binary shipped for the same macOS, Windows, and Linux target matrix as desktop. |
| MCP | pen-mcp Node/Bun package with Node.js fallback behavior. |
Built-in Rust op-mcp path; desktop can expose stdio and live HTTP MCP endpoints without requiring Node.js for the main app path. |
| AI runtime | agent-native Zig NAPI plus TypeScript service wrappers for providers and agent orchestration. |
Rust agent runtime from vendor/agent, with provider integration in the Rust workspace. |
| SDK surface | pen-engine, pen-react, and related pen-* packages exposed a broader TypeScript embedding/editing surface. |
Public npm SDKs are intentionally narrower: read-only .op viewing through the wasm-backed op-web-sdk, plus React and Vue adapters. |
| Code organization | Root JavaScript/Bun monorepo with apps/* and packages/pen-*. |
Root Cargo workspace in crates/; JavaScript/Bun only remains under packages/ for web SDK publishing. |
Performance And Footprint Comparison
| Area | TypeScript + Electron (v0.7.5) |
Rust (v0.8.0) |
|---|---|---|
| Desktop footprint | Ships a full Chromium runtime and Node.js-backed desktop stack. | Native desktop artifacts per target, with no embedded browser engine; exact binary and installer sizes vary by OS, architecture, and packaging format. Current raw desktop binaries are roughly in the mid-50 MB range. |
| Web payload | JavaScript application plus CanvasKit/WASM payload. | Rust web build measured at 8.2 MB wasm / 2.18 MB gzip over the wire after icon catalog splitting. |
| Rendering consistency | Web and desktop behavior depended on the web app/Electron runtime boundary. | Native and web targets share the Rust render path: skia-safe on native, CanvasKit on WebGL2. |
| Interaction hot paths | React/store synchronization could put document serialization and state updates on interactive paths. | Pan/zoom no longer re-serializes the document every frame; wheel-zoom CPU was reduced from about 69% to about 0% on the measured hot path. |
| Large documents | No comparable large-document benchmark is published in this repository for v0.7.5. |
A 10,000-node nested auto-layout canvas writes, reads, and snapshots layout with no panics and about 0% idle CPU; a full layout snapshot returns in about 0.68 s. |
| Memory model | JavaScript garbage collection can introduce latency variance. | Rust ownership avoids GC pauses on editor-state and layout hot paths. |
These numbers are release-note level measurements from the Rust release line and are intended to explain the migration impact. They are not a full benchmark suite across every v0.7.5 workflow, and artifact sizes should be checked against the final release assets for each platform.
Issues Addressed
As of 2026-07-09, the GitHub issues page has 19 open issues. Based on the v0.8.0 feature set and the Rust replacement scope, this release is expected to close 5 of them after final release validation:
- #129 — completes the Rust rewrite tracked by the public planning issue.
- #123 — replaces the
@zseven-w/agent-nativechat crash path with the Rust agent runtime. - #148 — ships OpenCode support through the Rust agent settings and chat provider path.
- #163 — replaces the Docker image path that depended on a missing
@zseven-w/agent-nativeruntime package. - #164 — adds SVG export through the Rust export pipeline, including desktop/web host export and web SDK active-page SVG export.
The release also partially covers several open issues, but they should stay open unless the remaining scope is split into follow-up issues:
- #62 — Gemini support is present, but Stitch import is not covered by this release.
- #120 — Linux native artifacts are included, but the remote-file workflow request is broader than packaging.
- #162 — the Rust release addresses parts of the crash/export surface, but the issue also includes UI, clipboard, fill-layer, and text-quality requests.
Compatibility And Migration Notes
- The retired TypeScript apps and
pen-*packages are not included in this release line. - The repository root is now a Cargo workspace. JavaScript/Bun tooling for the SDK family lives under
packages/. - Consumers that previously depended on the retired TypeScript app packages should migrate to the Rust desktop app, the
opCLI, or the read-only web SDK depending on their use case. - npm packages for this pre-release are published under the
nextdist-tag rather than replacing the stable npm tag.
Release Artifacts
- macOS: notarized
OpenPencil-0.8.0-<arch>-mac.dmgfor the desktop app, plus standaloneopCLI archives. - Windows:
OpenPencil-0.8.0-<arch>-win-setup.exe, plus portable desktop andopCLI archives. - Linux:
OpenPencil-0.8.0-<arch>-linux.AppImage,OpenPencil-0.8.0-<arch>-linux.deb, plus raw desktop andopCLI archives. - Web SDK: published npm packages and attached npm tarballs for the base SDK, React adapter, and Vue adapter.
- Pa...
v0.7.5 — Quiet bugs, loud now
A maintenance pre-release focused on three quietly broken behaviors. All three are user-reported issues from 0.7.4. Binaries for macOS, Windows, and Linux are attached below once the build matrix finishes.
🐛 Fixes
AI providers — fetch failed is now actionable (#121)
Custom OpenAI-compatible providers used to surface Node's opaque TypeError: fetch failed for every network failure — DNS lookup, TLS handshake, connection refused, timeout — all collapsed into one useless string. The real reason was already on error.cause but never reached the UI.
formatFetchError() now walks the cause chain (including the AggregateError undici emits when multiple A records all fail) and prefixes the SystemError code, so the AI Settings dialog and chat stream show:
ENOTFOUND: getaddrinfo ENOTFOUND api.example.com
ECONNREFUSED: connect ECONNREFUSED 127.0.0.1:8080
self-signed certificate in certificate chain
…instead of fetch failed.
Electron — agent-native binary now ships on every platform
The Zig NAPI provisioner had a silent failure mode that bit any matrix entry without a matching prebuilt release: the source-build fallback dropped agent_napi.node at zig-out/napi/…, but electron-builder only ships from packages/agent-native/napi/. Affected installs (commonly Windows) launched fine but died at the dynamic @zseven-w/agent-native import the moment chat was used.
- Always source-build on the runner —
mlugg/setup-zigis provisioned for every workflow - Always copy the built binary into
napi/agent_napi.nodeso electron-builder packages it - Cross-compile per platform via `ZIG_TARGET` — `mac-x64` on arm64 runners now produces an x86_64 binary, not a wrong-arch arm64 one
- Strict mode (`OPENPENCIL_REQUIRE_AGENT_NATIVE=1`) plus a dedicated Verify agent-native binary workflow step fails the build loudly if the binary is missing
📚 Docs
| Issue | What changed |
|---|---|
| #116 | Removed obsolete `op export` references from 15 root READMEs, 15 `apps/cli/` READMEs, AGENTS.md, and CLAUDE.md. The export command was retired in favor of the multi-stage `codegen:plan / submit / assemble` pipeline. |
| #117 | Rewrote `packages/pen-mcp/README.md`. The previous `npx @zseven-w/pen-mcp` quick-start never worked — the package ships TypeScript source against workspace-only deps with no `bin` entry. New section explains how to run the server from the monorepo and how external MCP clients connect over HTTP at `http://localhost:3100/mcp\`. |
🧪 Verification
- 1525 / 1525 unit tests passing (Vitest, 151 files)
- 0 lint warnings (oxlint, 818 files)
- 0 TypeScript errors (strict mode)
- 14 new tests covering `formatFetchError` cause-chain unwrapping and AggregateError handling
⚠️ Pre-release notice
This build is published for early testing of the agent-native packaging fix — particularly on Windows where it most often regressed. If you're on a stable distribution channel and only want shipped releases, wait for v0.7.6 stable.
Full Changelog: v0.7.4...v0.7.5
v0.7.4-enhance
Summary
OpenPencil v0.7.4 focuses on reliable AI design generation on dark themes, smarter incremental edits, and
a hardened native agent runtime (MiniMax tool_use, Windows, openai-compat streaming).
Changes
AI / Design generation
fix(ai): stop white section bands on dark-themed pages — skipfixSectionAlternationwhen parent
fill luminance < 0.5, and strip staleSAFE_LIGHT_HEXESfrom earlier runsfeat(ai): design.md-driven background + sidebar color pipeline (orchestrator planning, sub-agent
prompts, and MCP all share the palette policy)feat(ai): append-intent detection — "continue"/"add more" prompts reuse the existing content root,
and sub-agents get an APPEND MODE preamble listing existing siblingsfeat(ai):snapshot_layoutnow emits anoverlapsarray; when the parent islayout: "none"the
reason points at absolute x/y stacking so agents fix the parent instead of resizing childrendocs(ai): horizontal scroll card-row pattern with fullclipContent+ nestedfit_contentexamplechore(ai): enable incremental-add skill in the generation phase
Canvas / Editor
fix(canvas): require explicitrole:'overlay'to escape auto-layout —badge/pill/tagare
inline roles again and flow normally instead of collapsing to (0,0).isBadgeOverlayNoderenamed to
isOverlayNode; a deprecated re-export keeps external consumers of@zseven-w/pen-corebuildingfix(canvas): render synchronously on resize to prevent the one-frame white flash when flex layout
shifts (e.g. right panel mount on first selection)feat(editor): paste anchors to the selected container (or as sibling) instead of always landing at
document root
Renderer
feat(renderer): enable local OS fonts with vector rendering and proper permission handling (#110)
Agent (native)
chore(agent): bumpagent-nativeto v0.4.0 — absorbs upstream v0.2.0/v0.3.0 (openai-compat
tool_calls streaming, HTTP error diagnostics), MiniMax tool_use 400 fix (placeholder text block when
assistant turn is tool_use-only), auto-detected MiniMax Anthropic-compat quirk, and Windows N-API symbol
export
MCP / Tooling
fix(mcp): runcodexvia shell on Windows so PATHEXT resolves.cmd/.batshims (works around the
Node CVE-2024-27980 execFileSync restriction)ci(publish): check-before-publish; package names derived from each manifest so workflow/manifest
drift is impossible — fixes the spurious CLI-step 404 on re-runsstyle(lint): clear 22 oxlint warnings across repochore: ignore.omx/
Type
-
feat— New feature -
fix— Bug fix -
docs— Documentation -
chore— Build / tooling / dependencies
Checklist
-
npx tsc --noEmitpasses -
bun --bun run testpasses - No unrelated changes included
- Commit messages follow Conventional Commits
v0.7.3-enhance
Summary
v0.7.3 introduces incremental "append mode" for AI design generation — when the user
asks the AI to add content to an existing canvas, the planner now detects append intent and
reuses the current content root instead of redrawing from scratch. Also ships local OS
font support via the Local Font Access API with vector rendering, a design.md-driven
background/sidebar theming pipeline, and a handful of editor, CLI, and cross-platform
fixes.
Changes
AI / design generation
feat(ai): append-mode detection beforegenerate_designdispatch —
detectAppendIntentparses continue/append prompts against the active pagefeat(ai): sub-agent preamble describes existing sibling sections so added nodes
integrate seamlesslyfeat(ai): planner reuses existing content-root in append mode instead of creating a new
root framefeat(ai):applyAppendContextToPlanhelper wires context into the orchestrator planfeat(types):AppendContext+SubTask.existingSectionLabelsfeat(ai): design.md-driven background + sidebar color pipeline; auto-derives neutral
page background when design.md has no explicit background rolefix(ai): stop white section bands on dark-themed pagesdocs(ai): horizontal scroll card-row pattern taught to the generation phase;
overflow.mdexample fleshed out
Fonts
feat(renderer): enable local OS fonts with vector rendering via the Local Font Access
API; includes permission handling (prompt/granted/denied/unavailable),
canvas-width heuristic for unknown local fonts, and blob-based registration into CanvasKit
(#110)
Editor
fix(canvas): render synchronously on resize to prevent a one-frame white flash when
RightPanelmounts on the first selection after idlefeat(editor):Cmd/Ctrl+Vnow pastes into the selected container (if it can hold
children) or immediately after the selected node as a sibling, falling back to the root
when nothing is selected
CLI / cross-platform
fix(mcp): on Windows, run the Codex CLI throughexecSyncso PATHEXT resolves
.cmd/.exe/.ps1shims (works around Node 18.20/20.12execFileSyncEINVAL from
CVE-2024-27980)
Code hygiene
style: apply oxfmt formatting drift across web, renderer, and AI modulesstyle(lint): clear 22 oxlint warnings (useless spread fallbacks, useless spread into
arrays, control-char regex →\P{ASCII}, unused catch params / imports, unnecessary
escapes,new Array(n).fill) — repo now lints with 0 warnings, 0 errorschore: ignore.omx/build artifact directory
Related Issues
- Merges #110 (local OS fonts with vector rendering and permission handling)
Type
-
feat— New feature -
fix— Bug fix -
refactor— Code refactoring (no behavior change) -
docs— Documentation
Checklist
-
npx tsc --noEmitpasses -
bun --bun run testpasses — 1515 tests inapps/web+ 47 inpackages/pen-mcp,
all green - No unrelated changes included
- Commit messages follow Conventional Commits
-
bun run lint— 0 warnings, 0 errors (added as a bonus of this rollup)
What's Changed
- Enable local OS fonts with vector rendering and proper permission handling by @1MochaChan1 in #110
New Contributors
- @1MochaChan1 made their first contribution in #110
Full Changelog: v0.7.2...v0.7.3
v0.7.2-bugfix
Summary
v0.7.2 is a stability release focused on multi-provider AI agent loops,
Mac CLI discovery across managed shells, and drag / reparent / clipping
correctness on the canvas. It also ships bounded AI codegen handoff so chat
payloads stop hitting provider request-size limits silently.
Changes
AI agent loops — multi-provider correctness
- OpenAI-compatible providers: fix the second turn. Before, the request
builder forwarded the message store's Anthropic-style content blocks
verbatim, so tool-result turns 400'd on GLM / dashscope / StepFun.
@zseven-w/agent-nativev0.3.0 now translatestool_use+tool_result
blocks into OpenAI'stool_calls+role="tool"form, injects
system_prompt, and drops unsupported thinking blocks. - Tool-call streaming for OpenAI-compat. The SSE parser now accepts
delta.tool_callsand emitscontent_block_start/tool_use_delta/
content_block_stopso tool invocations from GLM / DeepSeek / Qwen /
dashscope flow through the same pipeline as Anthropic. - StepFun
step_plan/v1support. Acceptdelta.reasoningalongside
reasoning_contentso StepFun's reasoning-heavy stream renders instead of
stalling the client-side first-text watchdog into an abort →std.http
panic → Bun segfault cascade. - HTTP 451 / content-safety surfacing. Map StepFun's 451 to
error.InvalidRequestwith a specific "Content blocked by provider safety
filter" message;/api/ai/chatnow forwardsresult.errors[0]so users
see the real reason instead ofProvider error: error_server. - firstTextTimeout relaxes on thinking activity. When the model is
streaming reasoning, the "no first text yet" watchdog stands down —
noTextTimeout+hardTimeoutstill bound genuinely runaway reasoning.
Orchestrator sub-agent resilience
- Minimal-skills fallback. After the full-skills attempt and its retry
both produce zero nodes, the orchestrator re-runs just the failing subtask
with a ~3KB kernel prompt (schema + jsonl-format only). Successful earlier
subtasks are preserved; only the failing one retries. - Skip deterministic refusals. Responses matching HTTP 400/401/429/451,
"content blocked", "censorship", or "authentication failed" short-circuit
the retry ladder so users aren't charged a second 4-minute StepFun safety
scan.
Local CLI discovery — Mac / managed-shell users
- Login-shell probe. New
probeViaLoginShell()asks$SHELL(or a zsh /
bash / fish fallback)-ilc 'command -v <cli>'to source the user's
real rc/profile. This catches nvm / fnm / pnpm / bun / mise / asdf / volta
shims that Electron's scrubbed PATH hides. - Expanded candidate paths.
posixUserBinDirs()now includes
~/.bun/bin,~/.volta/bin,~/Library/pnpm,~/.pnpm-global/bin,
~/.local/share/mise/shims,~/.asdf/shims,~/.cargo/bin, plus
dynamically enumerated~/.nvm/versions/node/<ver>/binand
~/.fnm/node-versions/<ver>/installation/bin. - Uniform ladder across every resolver.
claude/codex/opencode/
copilot/geminiall run the same PATH → login-shell → npm-prefix →
user-bin candidates sequence, each step logged to
~/.openpencil/logs/server-YYYY-MM-DD.logfor remote diagnosis.
Built-in providers
- Add "StepFun Coding Plan" preset (
https://api.stepfun.com/step_plan/v1).
Electron / dev-sync stability (#104)
- Stabilize Electron dev startup after the upstream sync.
- Keep localhost probing resilient without relying on proxy-friendly fetch
behavior. - Unblock incomplete local workspaces and keep Codex-related env passthrough
working.
Drag / reparenting / nested clipping (#104)
- Preserve absolute/world position when layer moves change parent containers
— nodes no longer jump visually after reparenting. - Stop nested frame / group / shape drags from auto-ejecting to root during
canvas drags. - Promote previously root-only frame clipping to explicit
clipContentwhen
nested, so corner radius and clip visuals stay intact.
AI handoff / codegen context quality (#104)
- Export bounded AI codegen asset bundles and structure bundles so chunk /
assembly prompts reference stable./assetspaths instead of inline
base64. - Enrich sanitized AI consumer views with reusable image / gradient / layout
/ component semantics. - Restore code-panel AI bundle and ZIP export affordances.
- Preserve cropped image fill transform metadata alongside original image
size through the Figma import path. - Guard oversized chat payloads with a client-side rejection before the
request leaves the browser.
Server / sync plumbing (#104)
- Harden MCP document sync behavior and related tests.
- Keep the server-side handoff path consistent with the richer AI bundle
payloads.
Type
-
feat— StepFun Coding Plan preset, login-shell CLI probe, consumer-view enrichment, minimal-skills fallback -
fix— OpenAI-compat tool-call streaming, turn-2 request shape, StepFun reasoning + 451, drag reparent, firstTextTimeout, Electron dev sync -
perf— Bounded AI chat payloads, retry short-circuit on deterministic refusals
Verification
npx tsc --noEmit -p apps/web✓bun --bun run test— 1492 / 1492 passed across 151 filesbun --bun run build✓bun run electron:build:mac-arm64✓ — produces signed DMG + zip +
latest-mac-arm64.yml- Manual: GLM-5 via dashscope
/chat/completionsend-to-end design flow,
StepFunstep_plan/v1reasoning stream, Mac login-shell CLI detection
against nvm / fnm / pnpm / bun / mise / fish
Submodule
packages/agent-native0.2.0 → 0.3.0
(feat(openai-compat): tool_calls streaming, content-block translation, reasoning + 451)
Workspaces bumped
All 14 workspace package.json files bumped 0.7.1 → 0.7.2.
Breaking changes
None.
What's Changed
New Contributors
Full Changelog: v0.7.1...v0.7.2