Jian
A Rust-native cross-platform UI framework. An .op file is an app.
Ask AI about Jian
Powered by Claude ยท Grounded in docs
I know everything about Jian. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Jian ยท ็ฎ
One .op file. A native window. AI in the loop. Pure Rust.
Jian loads a single declarative document and turns it into a real, interactive, hot-reloading, AI-controllable application โ without a JS runtime, without a DOM, without an Electron tax.
Quick start ยท Why Jian? ยท Architecture ยท AI surface ยท Roadmap
โจ Highlights
- ๐ฆ Pure-Rust runtime โ
winitยทskia-safeยทtaffyยทrstar. No JS, no DOM, no V8. - ๐ One file is the app โ state, layout, bindings, events, AI capabilities โ all in
.op. - โก Solid-style reactivity โ
Signal<T>+Effect, fine-grained, single-threaded, allocation-light. - ๐ฏ Real gesture arena โ Tap ยท LongPress ยท Swipe ยท Scroll ยท multi-pointer Pinch & Rotate, with bubble-style hit dispatch.
- ๐จ Pixel-stable rendering โ Skia raster, per-corner radii, gradients, shadows, image cache, Lucide icons; opt-in
textlayoutfor full Paragraph shaping. - ๐ค AI-native by design โ every interactive node derives a
<scope>.<slug>_<hash4>action (Tap stays unprefixed; DoubleTap / LongPress / Submit / Set / Open / LoadMore / Swipe* / Confirm / Dismiss carry verb prefixes);jian dev --mcpexposes them over a real MCP stdio server. - ๐ Typed cold-start pipeline โ three-stage
StartupDriver(DataPathpre-window ยทVisualfirst-redraw ยทBackgroundpost-paint), per-platform budget tests,jian perf startup+jian perf compareregression gate, and AOT initial-layout pre-bake viajian pack --aot. - ๐ Hot reload that keeps state โ
jian dev app.opreparses on save without losing your counter / form / scroll position. - ๐ก๏ธ Capability-gated I/O โ declared up-front in
app.capabilities; the gate refuses anything the document didn't ask for. - ๐ค Agent Shell Protocol โ two surfaces โ
jian-aspships a wide dev surface (Tap / Type / Scroll / Swipe / Find / Inspect / Snapshot / Audit + state writes) for AI-driven UI testing AND a lean prod surface (Handshake / ListActions / Tap / Type / Scroll / Swipe / Exit) for token-efficient AI driving against shipping apps โjian player --asp <path>over a Unix socket / Windows Named Pipe with a real per-user DACL, file-based token revoke + rotate,--asp-permission <observe|act|full>, and a~3.65รsmaller wire than MCP on a 50-action screen. Each surface is a separate cargo feature (dev-asp/prod-asp); CI asserts neither leaks into a release build that didn't ask for it. - ๐งช
cargo test --workspaceis the source of truth โ full matrix covers macOS / Linux / Windows ร {default, dev-asp, prod-asp, textlayout} + a per-platformstartup-budgetregression gate (15% threshold, 1 ms noise floor).
๐ฌ Hello, Counter
Jian apps are JSON. This one renders, lays out, hit-tests, and is hot-reloadable the moment you save:
{
"formatVersion": "1.0",
"id": "demo.counter",
"app": { "name": "Counter", "version": "0.1.0", "id": "demo.counter" },
"state": { "count": { "type": "int", "default": 0 } },
"children": [{
"type": "frame", "id": "root", "width": 480, "height": 320,
"fill": [{ "type": "solid", "color": "#f5f7fa" }],
"children": [
{ "type": "text", "id": "label", "x": 40, "y": 60,
"width": 400, "height": 60, "fontSize": 40, "fontWeight": 700,
"content": "Count: 0",
"bindings": { "content": "`Count: ${$app.count}`" } },
{ "type": "rectangle", "id": "btn", "x": 140, "y": 180,
"width": 200, "height": 64, "cornerRadius": 12,
"fill": [{ "type": "solid", "color": "#1e88e5" }],
"events": { "onTap": [{ "set": { "$app.count": "$app.count + 1" } }] }
}
]
}]
}
cargo run -p jian -- dev counter.op # live-reload window
cargo run -p jian --features mcp -- dev counter.op --mcp # + AI over MCP
No build step. No bundler. No transpiler. The CLI parses the file, builds the runtime, hands it to a real
winitwindow, and starts watching the file for saves.
๐ค Why Jian?
| Electron / Tauri + React | Flutter / Compose | Jian | |
|---|---|---|---|
| Distribution unit | bundled JS / wasm | compiled binary | single .op JSON |
| Reactive model | VDOM diff | rebuild + keys | fine-grained signals |
| Authoring loop | bundle โ reload | rebuild โ restart | save โ reparse, state preserved |
| AI integration | bolt-on per app | bolt-on per app | derived MCP surface, every release |
| Renderer | webview / Impeller | Skia / Skia | Skia (raster today, GPU staged) |
| Runtime cost | JS engine + DOM | Dart VM + framework | Rust binary, ~1 process |
Jian sits where "fast tools" meet "fast UIs": you ship the runtime once, then
distribute applications as content (.op files), not as bundles. The same
runtime is staged to embed into the OpenPencil canvas (via napi-rs) and
into the browser (via WASM) โ the document is portable, the host is not.
๐ Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ .op (Pen Schema) โ
โโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ parse
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ jian-ops-schema โโ Pen Schema v1, JSON Schema + ops.ts โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ jian-core โ
โ โข Runtime โข Signal/Effect โข StateGraph (6 scopes) โ
โ โข Tier-1 expressions โข Tier-2 Action DSL โ
โ โข Capability gate โข R-tree spatial โข Gesture arena โ
โ โข taffy flexbox โข MeasureBackend (estimate | Skia) โ
โโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ jian-skia โ โ jian-action-surface โ
โ raster + GPU* โ โ derive ยท list ยท execute โ
โ paragraphโบ โ โ state-gate ยท audit โ
โโโโโโโโโโฌโโโโโโโโ โ rate-limit ยท MCP (rmcp) โ
โ โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ jian-host-desktop (winit ยท softbuffer ยท muda ยท arboard) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ jian player โ โ jian dev โ โ jian dev โ
โ (window) โ โ (+hot reload) โ โ --mcp (+AI) โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
* GPU surface factories (Metal / D3D12 / GL / Vulkan) are scaffolded
behind feature flags โ raster + softbuffer covers all three desktop OSes
today.
โบ Real Paragraph shaping is opt-in via the textlayout feature; a 1 px
drift gate pins the estimate path against it on every CI run.
๐ Quick Start
# 1. clone + build
git clone https://github.com/zseven-w/jian && cd jian
cargo build --release
# 2. scaffold
cargo run -p jian -- new my-app && cd my-app
# 3. validate a document
cargo run -p jian -- check app.op
# 4. run it in a real window
cargo run -p jian -- player app.op
# 5. author loop โ hot-reload on every save, runtime state survives
cargo run -p jian -- dev app.op
# 6. AI in the loop โ same as `dev`, plus stdio MCP for tools/list + tools/call
cargo run -p jian --features mcp -- dev app.op --mcp
Embedding the runtime directly:
use jian_core::Runtime;
let mut rt = Runtime::new();
rt.load_str(&std::fs::read_to_string("app.op")?)?;
rt.build_layout((800.0, 600.0))?;
rt.rebuild_spatial();
let hits = rt.spatial.hit(jian_core::geometry::point(50.0, 50.0));
Plug real font metrics in:
use jian_skia::SkiaMeasure;
rt.build_layout_with(SkiaMeasure::new(), (800.0, 600.0))?;
๐ฆ Crates
| Crate | What it does |
|---|---|
jian-ops-schema | Canonical Pen Schema for .op / .op.pack. Round-trips legacy v0.x byte-for-byte; ships v1.0 additive Jian extensions. Generates bindings/ops.schema.json (Draft 2020-12) + bindings/ops.ts consumed by OpenPencil and other editors. Hosts the pack::initial_layout AOT format (Plan 19 D1) + font_plan codepoint scanner (D2). |
jian-core | Runtime kernel. Runtime composition root, Signal<T> + Effect, StateGraph ($app / $page / $self / $route / $storage / $vars), Tier-1 expressions, Tier-2 Action DSL, capability gate, gesture arena, taffy flexbox, R-tree spatial index, MeasureBackend trait, typed three-stage StartupDriver + HostAgnosticBootstrap for the DataPath cold-start phases. |
jian-skia | RenderBackend over skia-safe. Raster + per-corner radii + linear gradients + shadows + image cache + Lucide icons. Optional textlayout feature wires real Paragraph shaping pinned by a 1 px drift gate. |
jian-host-desktop | winit 0.30 + softbuffer 0.4 host. Scale-factor-aware pointer / key translators, in-memory router + storage, arboard clipboard, muda native menus, binding-aware scene walker. Visual-stage bootstrap runs Splash / FirstFrame / Present / EventPumpReady inside the first RedrawRequested after resumed() (Plan 19 capstone B2.2 / B4). Per-platform deep-link trait-routing seams ship in app_delegate (macOS) / win_deeplink (Windows). |
jian-asp | Agent Shell Protocol โ NDJSON over an arbitrary byte stream. Two opt-in cargo features: dev-asp (full debug verb set, including find / inspect / snapshot / audit / state writes) and prod-asp (lean production surface โ handshake / list_actions / tap / type / scroll / swipe / exit, with selectors restricted to list_actions ids and the aiHidden filter applied). Listener transports: stdio, Unix domain socket (0700 parent / 0600 socket, refuses TCP / host:port), Windows Named Pipe (protected DACL, calling user's SID only). jian player --asp <path> wires the live runtime via an AspBridge (mpsc + sync-reply rendezvous; drained in about_to_wait). File-based token validator supports operator revoke (rm <token>) + rotate (echo new > <token>) without restarting the player. Plan 18 + post-audit hardening. |
jian-action-surface | AI Action Surface (spec ยง3โยง10). Derives stable <scope>.<verb>_<slug> actions, evaluates RuntimeStateGate against live bindings, dispatches synthesised pointer events, and serves list_available_actions / execute_action over an rmcp stdio bridge. Audit + rate limit + concurrency caps + swipe throttle baked in. |
jian (CLI) | check ยท pack [--aot] [--aot-viewport WxH] ยท unpack ยท new ยท player ยท dev (+--mcp) ยท perf startup [--runs N] [--format json] ยท perf compare BASELINE CURRENT [--threshold 0.15] [--noise-floor-ms 1.0] [--format markdown]. |
๐ค AI Action Surface
Jian advertises a derived, gated, audited action surface to any AI client.
Two delivery channels share the same <scope>.<verb>_<slug>_<hash4> action
ids (so a client can swap channels without re-learning names):
# MCP โ wide schemas per tool, ~9.2 KiB per `tools/list` on a 50-action screen.
cargo run -p jian --features mcp -- dev app.op --mcp
# ASP prod โ flat `[{id, events}]` rows, ~2.5 KiB per `list_actions` (3.65ร
# smaller); local-only Unix socket / Named Pipe; explicit revoke + rotate.
cargo run -p jian --features prod-asp -- player app.op --asp auto
# Then point your agent at the printed socket path + `<socket>.token`.
Under the hood, every interactive node becomes a tool. Names follow
<scope>.<slug>_<hash4> โ <hash4> is four hex chars derived from
(node.id, BUILD_SALT) and is dropped when the author sets
semantics.aiName:
| Node | Action name shape |
|---|---|
events.onTap on <button id="signup-cta"> | home.signup_cta_a3f7 |
bindings["bind:value"] = $state.email on <text-input> | home.set_email_b012 |
events.onScroll / onReachEnd on <list> | home.load_more_c4d5 |
events.onPanStart + onPanEnd on a card | home.swipe_{left,right,up,down}_e6f7 (4) |
events.onSubmit on a <form> | home.submit_<slug>_<hash4> |
route = { push: "/checkout" } on a link | home.open_checkout_<hash4> |
semantics.aiName = "checkout" on the same link | home.checkout (no _<hash4>) |
- Static availability comes from the schema (
AvailabilityStatic::Available/ConfirmGated/StaticHidden).confirm:/fetch DELETE|POST/storage_clear/storage_wipeflip a node toConfirmGateduntil the author opts back in withsemantics.aiHidden: false. - Live state-gate (
RuntimeStateGate) drops actions whose source node or any ancestor evaluatesbindings.visible == falseorbindings.disabled == trueagainst the liveStateGraphโ so the AI never sees an action it would then bounce offstate_gatedon execute. - Authorship overrides (
aiAliases) survive bothlistandexecute; alias hits are audited withalias_used: trueand stay transparent to the client. - Phase 1 dispatch coverage: Tap / Confirm / Dismiss / SetValue / OpenRoute
are wired against the live
Runtime. DoubleTap / LongPress / Submit / Swipe* / LoadMore are listed inlist_available_actionsbut currently returnExecutionFailed(handler_error)until their host-driver paths land. - Pointer dispatch synthesises a real
PointerDown+PointerUpat the layout centre of the source node โ the same code path a human cursor takes. - Audit log + rate limit (10 calls/sec/session) + same-action concurrency cap + swipe 400 ms same-direction throttle are first-class.
- The
RuntimeDispatcherwraps&mut Runtime, while aSinkDispatcherkeeps unit tests free ofwinit.
Build-time stable names: the
_<hash4>suffix comes fromBUILD_SALTbaked in bycrates/jian-core/build.rs(priority:JIAN_BUILD_SALTenv override โ<git-short-16>-<cargo-semver>(e.g.1a2b3c4d5e6f7890-0.0.1) โ<cargo-semver>alone).jian dev --mcpprints the resolved source string on attach so prompt caches can key on it.
See crates/jian-action-surface/README.md
and openpencil-docs/superpowers/notes/2026-04-24-ai-action-surface-client-guide.md.
๐ Development
cargo test --workspace # default features, 0 failures
cargo test --workspace --all-features # adds mcp + textlayout
cargo test -p jian-asp -p jian --features dev-asp # full debug ASP surface
cargo test -p jian-asp -p jian --features prod-asp # lean prod ASP surface (incl.
# the 50-action byte-budget bench
# and prod-acceptance suite)
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --check
cargo run -p jian-ops-schema --bin export_schema
cargo run -p jian-ops-schema --features export-ts --bin export_ts
# Cold-start instrumentation
cargo run --release -p jian -- perf startup app.op --runs 20
cargo run --release -p jian -- perf startup app.op --runs 20 --format json > current.json
cargo run --release -p jian -- perf compare baseline.json current.json \
--threshold 0.15 --noise-floor-ms 1.0 --label macos-aarch64
# AOT pre-bake (writes aot/initial_layout.bin + aot/default_state.bin
# into the .op.pack โ runtime preloads both to skip ComputeFirstLayout
# and re-seed StateGraph defaults from the canonical snapshot)
cargo run --release -p jian -- pack --aot --aot-viewport 800x600 app.op out.op.pack
CI runs on macOS / Linux / Windows; the textlayout job needs Python 3.11
because Skia's text shaping build pulls it in. The startup-budget workflow
collects per-platform jian perf startup JSON on every push and gates PRs
against main's most recent green baseline (15% regression threshold,
1 ms noise floor, single rolling PR comment with the diff table).
๐บ Roadmap
Shipped in v0.0.1:
- โ Plan 1 ops-schema ยท Plan 2 core ยท Plan 3 Tier-1 expressions ยท Plan 4 Tier-2 Action DSL
- โ Plan 5 gesture arena (Tap / LongPress / Swipe / Scroll + multi-pointer Pinch & Rotate)
- โ Plan 6 capability gate (dev-asp gated)
- โ
Plan 7
jian-skia(raster + gradients + image cache +ParagraphBuilderfeature) - โ Plan 8 desktop host (winit / softbuffer / muda menu spec)
- โ
Plan 9 CLI (eight subcommands incl.
devhot-reload +perf startup/perf compare) - โ
Plan 22
jian-action-surfacePhase 1 + MCP stdio server (rmcp) +jian dev --mcp - โ
Plan 18 Agent Shell Protocol โ full dev verb set (Tap / Type / Scroll / Swipe / Find / Inspect / Snapshot / Audit + state writes via
dev-asp) AND prod surface (prod-asp: handshake / list_actions / tap / type / scroll / swipe / exit) wired intojian player --asp <path>over a Unix socket / Windows Named Pipe with explicit user-SID DACL, file-based token revoke + rotate,--asp-permission <observe|act|full>, and a 3.65ร smaller wire shape than MCP on a 50-action screen. Codex-reviewed across C0โC6 + post-audit fixes;asp-features ร {linux,macos,windows} ร {dev-asp,prod-asp}matrix runs on every push. - โ
Plan 19 cold-start capstone โ typed three-stage
StartupDriver(DataPath/Visual/Background),HostAgnosticBootstrapfor DataPath, visual-stage runner for the firstRedrawRequestedafterresumed(),jian playertwo-stage launch with unified-launch-epoch report timeline - โ
Plan 19 D1
.op.packAOT initial-layout writer + reader (OPL1little-endian SoA format,jian pack --aot) plus runtime preload (LayoutEngine::preload_initial+HostAgnosticBootstrap::install_data_path_with_aotshort-circuitComputeFirstLayoutwhen coverage is total + viewport bit-matches); AOT default-state writer + reader (OPS1framed canonicalised JSON for app/page/self/route/storage/vars scopes;StateGraph::dump_default_state/restore_default_statereuse Signal slot identity so binding subscribers survive); AOT expressions writer + reader (Plan 19 D2 โOPE1little-endian frame with wire-stablePackedOpCodeu8 tags 0..=32 mirroring everyjian_core::expression::bytecode::OpCodevariant;Runtime::warm_expression_cachepopulates the cache fromDeferredBindingQueuebefore dump;install_data_path_with_aot_fullrunsPackedChunk::verify(string/scope index bounds + forward-only jumps in [0, ops.len()]) beforeExpressionCache::install_precompiled; bootstrap drops the whole snapshot to JIT on verify failure; VM haschecked_sub/checked_muldefense in depth so a malformed AOT chunk that bypasses verify still surfaces as avm_bugdiagnostic instead of panicking); D2 font subsetter wiring (FontPlan::scan_subtreespopulatesBootstrapHandles::take_core_font_plan); D3 per-platform startup budget tests; D4jian perf compareCI diff bot + 15% threshold gate + single rolling PR comment - โ
Plan 8 ยงT7 native menu bar ยท ยงT8 deep-link trait-routing seam (
app_delegate.rsmacOS /win_deeplink.rsWindows) plus macOSkAEGetURLApple-Event receiver (apple_event_receiver.rsโ JianAppleEventReceiverNSObjectsubclass registered withNSAppleEventManager; main-thread asserted viapthread_main_np;extern "C"IMP wrapped incatch_unwind+mem::forget(payload)+ panic-safewriteln!(io::stderr(), โฆ)so handler panics never cross the FFI frame) AND WindowsWM_COPYDATAreceiver + named-mutex single-instance (win_deeplink_receiver.rsโLocal\namespace mutex+event paired with HWND_MESSAGE session scoping;try_acquire_singletonreturnsPrimary(Guard)/Secondary;install_receiver_window(&Guard)registersJianDeepLinkReceiverclass viaOnceLock<Result<โฆ>>-memoised result;forward_url_to_primarywaits on the ready event thenSendMessageTimeoutW(SMTO_BLOCK, 5s)returning typedForwardOutcome::{Delivered, NoPeer, SendTimedOut, SendFailed{last_error}, PrimaryRejected}; receiver validateslpData!=NULL,cbData โค 4 KiB, alignment,dwData == 'JDL1'tag); cross-platformdeeplink::install_deeplink_handlershim ยท ยงT9 updater trait +selfupdatefeature ยท ยงT10 packaging configs (cargo bundlemacOS .app ยทcargo wixWindows MSI โ URL-scheme registration uncommented and pointed atjian.exe player "%1"sojian://clicks route intotry_acquire_singleton's forward-and-exit path ยทcargo deb+ AppImage Linux ยท.icnsgenerator ยท Sparkle appcast template ยท AppImageUpdate metadata) - โ ยง3.3 CJK transliteration ยท ยง3.4 collision detection ยท ยง6.3 swipe throttle ยท ยง8.1 AuditLog
- โ
ยง3.1
BUILD_SALTbuild-time injection (crates/jian-core/build.rsโ env override โ git+semver โ semver fallback; mac.gitworktree resolved; FNV-1a double-hash โ 16 bytes) - โ Bubble-style event dispatch ยท binding-aware scene walker
- โ
macOS Dock icon at runtime via
NSApp.setApplicationIconImage:(set_macos_dock_icon_from_png) so unbundledjian player/jian dev(or any host that callsDesktopHost::with_icon) shows the schema'sapp.iconinstead of the default exec icon - โ
Action Surface protocol docs โ
crates/jian-action-surface/README.md(embedding + threat-model anchors) +openpencil-docs/superpowers/notes/2026-04-24-ai-action-surface-client-guide.md(Claude Desktop / raw-stdio Python clients, error-handling policy, build-salt awareness)
Up next (each warrants its own session):
- โ
Plan 19 D2 follow-up โ typed doc-walk extractor (
jian_core::expression::warm_cache_from_document) now compiles every expression-typed schema field into the AOT cache: per-nodebindingsmaps +NumberOrExpression/BoolOrExpressionunion variants + the 21 typed event hooks + the 4+4+2 app/page/node lifecycle action lists. Action bodies recurse structurally with aPushScopeRef + Returnpost-compile filter to drop bare-id pollution;event_handler_lists_match_struct_field_countexhaustively destructuresEventHandlersso any future hook addition forces a compile error in the test. Codex-reviewed across 5 rounds (1 BLOCK + 6 CONCERNs + 2 NITs all closed). - โ
Plan 8 ยงT8 follow-up A โ
RuntimeDeepLinkHandlerbuffering DeepLinkHandler installed on every platform (Apple-Event registry / Windows pipe-listener / Linux argv);DesktopHost.pending_deeplinksqueue drained once perabout_to_waittick viadispatch_url_into_runtime(nav.push+ per-query-keystate.route_set). Drain-timeexpected_app_idfilter resolved fromruntime.document.schema.app.idrejects OS-level cross-app misroutes; emptyapp.idcollapses toNoneso unset ids don't silently drop every URL. - โ
Plan 8 ยงT8 follow-up B โ Windows transport upgraded from
FindWindowExW+WM_COPYDATA(class-name peer auth โ same-session attackers could intercept) to per-user named pipe\\.\pipe\jian-deeplink-<user_sid>with explicit user-SID DACLD:P(A;;GA;;;<sid>)(mirror ofjian-asp::transport::named_pipe's security model).PIPE_REJECT_REMOTE_CLIENTSblocks off-box peers;FILE_FLAG_FIRST_PIPE_INSTANCEpairs with the named-mutex singleton for exactly-one-listener invariant. Listener thread reads URL lines from the pipe andPostMessageWs the receiver HWND withWM_USER_DEEPLINK_FORWARDcarrying a heap-leakedBox<String>pointer; receiverWindowProcrecovers the Box and feeds the URL intodispatch_url. Cold-start message-pump latency gap (round-1 known limitation) eliminated โ listener thread runs independently of main-thread cold-start work. Codex-reviewed across 4 rounds; final pass CLEAN. - โณ Plan 8 / 11 / 12 โ GPU surface factories (Metal ยท D3D12 ยท OpenGL / WebGL ยท Vulkan); each backend warrants its own session against real hardware (CAMetalLayer drawable lifecycle, IDXGI swapchain present cadence, GL context current, Vulkan surface/swapchain). Existing
surface/{metal,d3d,gl}.rsskeletons returnErr("โฆnot yet implementedโฆ")with full implementation outlines. - โณ Plan 11 โ OpenPencil canvas swap (replace
pen-renderervianapi-rs) - โณ Plan 13 โ Electron โ Tauri migration
- โณ Plan 14 โ
pen-mcpRust port (byte-level parity gate) - โณ Plan 15 โ
pen-ai-skillsRust + 3-backend split (MCP / ActionSurface / ASP) - โณ Plan 16 โ
pen-codegenRust (9 codegen targets) - โณ Plan 17 โ
pen-figmaRust + Stage E/F/G - ๐ Plan 24 โ
.op.packprotect Phase 2 (calendar-locked behind โฅ 3 months Phase 1 production)
๐ Spec
The full design lives next to the code:
- Specs:
openpencil-docs/superpowers/specs/ - Plans:
openpencil-docs/superpowers/plans/(2026-04-17-jian-plan-*and2026-04-2x-jian-*)
๐ License
MIT โ see LICENSE.
winit, skia-safe, taffy, and one stubborn .op file.
