moonviz

    Agent-Native 原型绘制引擎:.mbt.md 唯一事实源,人类画布与 Agent 声明共同演化,MoonBit 不崩谓词护航

    moonbit
    prototype
    design-engine
    ai-agent
    wasm
    svg
    Download zip
    Version
    0.1.8
    License
    MIT
    Last updated
    13 hours ago
    Downloads
    3

    #MoonViz — The Agent-Driven Prototype Design Engine for the AI Era

    #What's New in 0.1.8

    • Manifest migration to moon.mod — moon fmt across the repo (deprecated moon.mod.json removed). Root cause fix for mooncakes.io docs generation: moon doc rejects the deprecated manifest, so 0.1.7 shipped with "Documentation failed to generate" on the registry while installs worked. All package configs migrated; full three-target regression + ABI assertion green.
    • Code formatting pass (moon fmt) — behavior-neutral, 210 tests green.

    #What's New in 0.1.7

    • Official MoonBit native package — LIVE on mooncakes.io: moon add asdshuaishuai/moonviz installs 0.1.7, then embed the engine via the sdk/ facade:

      import {
      "asdshuaishuai/moonviz/sdk" @sdk
      }

      fn main {
      let p = @sdk.new()
      let r = @sdk.apply(p, "create home 390 844")
      let svg = @sdk.render_svg(p, artboard="home") // → SVG string
      }

      Package metadata is complete (license=MIT, keywords, repository, homepage) and the install → compile → render loop is verified against the published artifact. Publishing bypasses the moon CLI's HTTP/2 upload bug via direct multipart POST — see AGENTS.md.
    • Built with moonc ≥ 0.10.14 (version-gated in CI).

    #What's New in 0.1.6-moon

    • One-step final-size placement — place <ab> <comp> <id> [variant|-] [x] [y] [w] [h]: the gate evaluates the final bbox, eliminating the intermediate-state rejections (place at default size → get blocked → update to fix) that caused 111 rejections in a real LLM run.
    • In-product undo / time travel — session_history on the wasm surface (init/commit/log/undo/redo/checkout/diff), responses carry canonical MBT for host persistence.
    • unflow op — remove a single navigation edge instead of rebuilding the artboard.
    • Self-describing constrain errors — cannot_parse now returns the full intent vocabulary.
    • Toolchain — built with moonc ≥ 0.10.14; CI now runs check + full tests + example repro with a moonc version gate.

    🇨🇳 简体中文: README.zh-CN.md

    .mbt.md is the single source of truth, MoonBit is the unified compute kernel. Agents discover components, place elements, check quality, and fix violations through a tool API — all over a structured text protocol. This repository is 100% MoonBit with zero hand-written JS/Node.

    ┌─────────────────────────────────────────────────────────────┐ │ Agent (any LLM) │ │ discover components → create artboard → place → lint → │ │ fix → export │ └──────────────┬────────▲─────────────────────────────────────┘ │ Agent Tools API (52 tools, JSON in/out) ┌──────────────▼────────┴─────────────────────────────────────┐ │ Engine core/ + decl/ (pure MoonBit libraries) │ │ ┌────────────┐ ┌────────────┐ ┌───────────┐ ┌───────────┐ │ │ │ DesignTokens│ │ Components │ │ Project │ │ Agent API │ │ │ │ 17 colors/ │ │ 65 comps × │ │ multi- │ │ lint/diff │ │ │ │ 7 spacing/ │ │115 variants│ │ boards/ │ │ /suggest │ │ │ │ 6 radii/ │ │ │ │ flows/ │ │ │ │ │ │ 8 font sizes│ │ │ │ tokens │ │ │ │ │ └────────────┘ └────────────┘ └───────────┘ └───────────┘ │ │ ┌────────────┐ ┌────────────┐ ┌───────────┐ ┌───────────┐ │ │ │ Scene Graph │ │ Layout │ │ Non-crash │ │ Decl │ │ │ │ node tree │ │ solver │ │ preds │ │ round-trip│ │ │ │ │ │ Fixed/Fill │ │ P0–P4 │ │ .mbt.md │ │ │ └────────────┘ └────────────┘ └───────────┘ └───────────┘ │ │ ┌────────────┐ ┌────────────┐ ┌───────────┐ │ │ │ SVG output │ │ PNG pixels │ │ Terminal │ │ │ │ │ │ DEFLATE+AA │ │ canvas │ │ │ └────────────┘ └────────────┘ └───────────┘ │ └──────────────┬────────▲─────────────────────────────────────┘ │ .mbt.md fact source ┌──────────────▼────────┴─────────────────────────────────────┐ │ decl/login.mbt.md etc. (compiled & executed by moon check/test) │ └─────────────────────────────────────────────────────────────┘

    #Agent Tool List (52 tools)

    ToolSemantics
    list_componentsList all available UI components (with variants/descriptions/categories)
    list_tokensList design tokens (colors/spacings/radii/font sizes)
    create_artboardCreate a new artboard (name, width, height)
    list_artboardsList all artboards in the project with metadata
    place_componentPlace a component instance on an artboard
    query_nodesQuery nodes by kind/component/text content
    lint_designDesign quality checks (contrast/touch/spacing/consistency)
    get_violationsGet the non-crash predicate violation list
    suggest_fixActionable fix patches for violations
    export_svgExport an artboard as engine-derived SVG
    collab_mergeMulti-agent three-way merge: submit N agents' op sequences, get conflicts + auto-resolution
    historyDesign version control: init/commit/log/undo/redo/checkout/diff (time travel + semantic diff)
    animation_presets / animation_cssList the 6 animation presets / generate CSS @keyframes for a node
    protestRun a prototype test script (assertion-based navigation/inputs/render/violations)
    read_mbtRead and validate a complete .mbt.md source
    render_mbtRe-parse and render from .mbt.md
    ddp_viewRead-only DDP view and render contract
    export_reactReact TSX component stubs (code generation only, not a fact source)
    apply_templateGenerate a complete artboard from a template (one sentence → full page)
    fork_variantsFork design variants (parallel A/B exploration)
    score_variantsScore all variants (violations/lint/alignment/richness)
    merge_variantMerge the best variant back into the main branch
    auto_arrangeVertical equal-spacing auto-arrange
    snap_to_gridSnap to an N px grid
    center_in_parentCenter within parent
    suggest_alignmentDetect near-alignments and suggest snapping

    #Built-in Page Templates (14 complete pages)

    TemplateContents
    loginLogo + title + email + password + sign-in button + sign-up link
    signupTitle + name + email + password × 2 + sign-up button
    dashboardApp bar + stat cards 2×2 + chart + activity list
    profileAvatar + name + bio + stats + actions + content list
    settings4 groups (notifications/privacy/appearance/about) + sign-out button
    list_detailList page + detail page
    onboardingThree-page onboarding
    empty_stateIllustration + copy + CTA button
    web_landingWeb landing page: hero + feature cards + CTA
    web_loginWeb login: split layout with branding panel
    web_dashboardWeb dashboard: sidebar + topbar + stat cards + table
    pc_appDesktop app frame: sidebar navigation + content
    adaptive_landingAdaptive landing page for web widths
    login_v2Login page, second style variant

    #Built-in Component Library (65 components × 115 variants)

    ComponentCategoryVariants
    buttonactionsprimary / secondary / danger
    text_inputinputsdefault / filled
    cardlayoutelevated
    app_barlayoutsurface / primary
    dividerlayoutdefault
    headingdisplayh1 / h2 / h3 / h4
    body_textdisplaybody / caption
    badgedisplayprimary / success

    #Design Lint

    RuleSeverityChecks
    contrasterrorText contrast ≥ WCAG AA 4.5:1
    touch_targetwarningInteractive elements ≥ 44×44
    spacinginfoPadding inside containers ≥ 8
    empty_containerwarningFrame with no children

    #Quick Start

    #Environment Setup

    # 1. Install the MoonBit toolchain (moon ≥ latest stable) curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash moon version # Verify: ~/.moon/bin/moon is on PATH # 2. Clone the engine repository git clone https://github.com/asdshuaishuai/moonviz && cd moonviz # 3. (Optional, for DDP encrypted distribution) Build the Rust codec cd ddp && cargo build --release && cd .. # Produces ddp/target/release/ddp_codec (stdin JSON → stdout JSON) # Override the path with MOONVIZ_DDP_HELPER; the SDK searches ddp/target/{debug,release} automatically # 4. Full test suite (205 on the default target; 209 with --target native) moon test

    #First Run

    # A. Stateful CLI session: one command per stdin line → one JSON per stdout line moon run --target native cli template login t_login 390 844 # Create an artboard from a template create t_home 390 844 # Target artboard for navigation update t_login welcome_title text="Welcome back" flow t_login t_home login_btn # Sign-in button → navigate to home export-mbt-human # HumanGate validation + returns canonical .mbt.md exit # B. Stateless one-shot: render / validate (base64 carries multi-line MBT source) moon run --target native cli <<< "render-mbt-b64 $(base64 <<< "$MBT")" # C. MCP Server (stdio JSON-RPC, plugs into any MCP client) moon run --target native mcp # D. Prebuilt binaries (no toolchain, millisecond startup) moon build --release --target native mcp _build/native/release/build/mcp/mcp.exe # Self-contained executable (links libc only) # E. Interactive canvas / scripted demo moon run --target native playground # Interactive (`png` command emits a PNG) moon run playground # Scripted demo

    #MoonBit Package (mooncakes.io)

    The engine is also a native MoonBit package on mooncakes.io — embed it directly in any MoonBit project:

    moon add asdshuaishuai/moonviz

    // Use the SDK facade (sdk/) — same op surface as CLI/MCP/WASM
    let p = @sdk.new()
    let _ = @sdk.apply(p, "template login t_login 390 844")
    let _ = @sdk.apply(p, "place t_login button btn - 20 20 120 44")
    let svg = @sdk.render_svg(p, artboard="t_login") // engine raw output
    let mbt = @sdk.canonical(p) // canonical .mbt.md fact source

    Publishing is done from this repo with moon login + moon publish (mooncakes.io account required).

    #Repository Tour

    moonviz/ ├── core/ │ ├── node.mbt Node tree (scene graph) │ ├── layout.mbt Layout solver │ ├── predicates.mbt Non-crash predicates P0–P4 │ ├── policy.mbt Dual-route policy (human soft / agent hard) │ ├── patch.mbt Transactional patches │ ├── tokens.mbt Design tokens (Material 3 style) │ ├── component.mbt Component system (65 components × 115 variants) │ ├── project.mbt Multi-artboard project + navigation flows + lint + fix suggestions │ ├── agent_api.mbt Agent tool API (52 tools + list-ops op dictionary) │ ├── autofix.mbt Auto-fix engine (overflow shrink/overlap shift) │ ├── templates.mbt Page template library (login/dashboard/settings/profile/empty state…) │ ├── align.mbt Smart alignment (grid snap/centering/equal spacing/near-detection) │ ├── variants.mbt Variant exploration (fork/score/merge) │ ├── interaction.mbt Interactive prototypes (Trigger/Action/Transition/nav stack) │ ├── artifact.mbt Agent intermediate artifacts (.moonviz cross-agent handoff) │ ├── runtime.mbt Embedded runtime SDK (events/render plan/hot reload/input) │ ├── intelligence.mbt Design intelligence (page-type inference/missing detection/suggestions/scoring) │ ├── lineage.mbt Lineage tracking (token/component usage + change impact + design-system audit) │ ├── prototest.mbt Prototype testing (assertion-based verification of navigation/input/render/violations) │ ├── reasoning.mbt Layout reasoning (natural-language constraints → StackLayout/alignment/scaling) │ ├── responsive.mbt Responsive breakpoints (phone/tablet/desktop auto-adaptation) │ ├── collab.mbt Multi-agent collaboration (operational transform/conflict detection/three-way merge) │ ├── history.mbt Design version control (time travel/branching/change replay/undo-redo) │ ├── critique.mbt AI design critique (automatic review against 8 design principles) │ ├── annotate.mbt Design annotation (auto-generated spec docs/CSS variables/spacing-color-type annotations) │ ├── animation.mbt Property animation (keyframes/easing/timeline choreography/CSS export) │ ├── extract.mbt Design-system reverse extraction (infer tokens + component patterns from existing designs) │ ├── theme.mbt Theme system (6 predefined themes/auto dark/token-level switching/registry) │ ├── slots.mbt Component slot system (6 composable components/nested content distribution/recursive composition) │ ├── benchmark.mbt Performance benchmark engine (node stats/complexity analysis/anti-pattern detection/optimization advice) │ ├── diff.mbt Semantic diff (added/moved/resized/restyled) │ ├── export.mbt HTML prototype + React TSX export │ ├── svg.mbt SVG rendering │ └── agent_test.mbt Agent workflow end-to-end tests ├── decl/ Declaration DSL + .mbt.md round-trip ├── cli/ Agent CLI (newline-framed JSON-lines protocol; one process = one stateful session) ├── mcp/ MCP Server (stdio JSON-RPC; 52 tools mirroring the CLI) ├── wasm/ WASM boundary — dual builds: wasm-gc (JS hosts, JS String Builtins) + classic standard MVP; 11 stateless APIs + 27 session_* APIs (i32 handles, incl. session_history undo/redo) + _in slot variants ├── ddp/ Rust ddp_codec: DDP1 encryption (Argon2id+XChaCha20-Poly1305) / DDP2 keyless (zstd+CRC32) ├── sdk/ MoonBit SDK facade (mooncakes.io: `moon add asdshuaishuai/moonviz` → @sdk.new/apply/render_svg/canonical) ├── sdk/node/ Node SDK "moonviz-engine-sdk": sessions/Project builder/DDP bridge (pure transport) ├── sdk/wasm/ WASM SDK "moonviz-engine-wasm": in-process render/validate, zero toolchain (Node ≥22 / modern browsers) ├── npm/ npm distribution: moonviz-mcp (launcher) + moonviz-skill + moonviz-bin-<platform> (prebuilt platform packages) ├── playground/ Terminal canvas + PNG rendering + REPL ├── site/ Website (GitHub Pages: asdshuaishuai.github.io/moonviz/) ├── scripts/ publish-npm.sh and other release scripts ├── examples/ DDP2 parse/render replica samples (CI example repro) └── docs/ Design documents 01–11 + wasm-abi.md

    #Interactive Prototype System

    Prototypes are not static pictures — MoonViz has a complete interaction runtime:

    ConceptDescription
    Triggertap / long_press / swipe / keyboard / focus / blur
    Actionnavigate_to / back / toggle_state / set_text / submit_form / show_toast
    Transitionpush / pop / modal / sheet / fade
    ComponentStateComponent polymorphism (default / pressed / disabled / loading)
    NavigationStateNavigation stack (push / pop / back)

    #Agent Intermediate Artifacts (.moonviz)

    Agent A finishes a design → exports a .moonviz JSON file → Agent B reads it and continues.

    { "meta": { "version": "0.1.0", "created_by": "agent-abc", "context": "Food delivery app" }, "artboards": { "login": { "name": "Login", "size": [390,844], "decl": "..." } }, "flows": [{ "from": "login", "to": "home", "trigger": "tap:submit" }], "todo": ["Add form validation", "Create error state"], "notes": [{ "artboard": "login", "note": "Email needs regex", "priority": "high" }] }

    #Embedded Runtime SDK

    How other projects embed MoonViz:

    let rt = MoonVizRT::create(project, initial_artboard="login")?
    rt.set_input("email", "user@test.com")
    let changes = rt.handle_event(TapEvent(160.0, 422.0)) // → navigate to home
    let plan = rt.render_plan() // → RenderPlan (backend-agnostic display list)
    rt.hot_reload(new_decl) // → hot reload (keeps nav stack and input values)

    The RenderPlan is a backend-agnostic display list (CmdRect / CmdText / CmdLine / CmdClip) that any rendering backend (Canvas / Skia / SVG / terminal / OpenGL) can consume.

    #Design Intelligence

    The engine does not just execute designs — it understands them:

    CapabilityDescription
    infer_page_typeInfer page type from node structure (auth/dashboard/list/profile/settings…)
    infer_missingInfer missing elements from page type ("login page is missing a forgot-password link")
    suggest_improvementsSuggest improvements based on design principles (hierarchy/spacing/consistency/density)
    design_quality_scoreComposite grade A–D (hierarchy/consistency/stability/richness)

    #Lineage Tracking

    You changed one token — which nodes are affected?

    CapabilityDescription
    token_lineage("primary")Every node using the primary color (with artboard + field)
    component_lineage("button")Location and size of every button instance
    impact_analysis(patch)Preview a patch's impact (color contrast/size overflow/position)
    audit_design_systemAudit hardcoded colors → suggest nearest-token replacements

    #Prototype Testing

    A prototype is not just "looks right" — it is testable:

    let pt = ProtoTest::create(project, initial="login")?
    pt.tap_and_expect_navigate(160, 422, "home") // tap sign-in → home
    pt.back_and_expect("login") // back → login
    pt.set_input_and_expect("email", "a@b.com") // input value stored correctly
    pt.expect_no_violations() // no layout violations
    pt.expect_renderable() // render plan non-empty
    pt.result() // → {"status":"PASS","passed":5,"failed":0}

    #Layout Reasoning Engine

    The agent says "center the buttons", the engine infers parameters and executes — no StackLayout API knowledge required:

    p.apply_constraint("center align", artboard="login") // → center_in_parent
    p.apply_constraint("vertical stack", artboard="login") // → StackLayout(Vertical)
    p.apply_constraint("equal widths", artboard="login") // → all width = Fill
    p.apply_constraint("spacing 16", artboard="login") // → gap = 16
    p.apply_constraint("scale 1.5x", artboard="login") // → all sizes × 1.5
    p.apply_constraint("grid 8", artboard="login") // → snap_to_grid(8)

    14 layout intents in Chinese and English; numbers auto-extracted ("间距 16px" → gap=16.0).

    #Responsive Breakpoints

    One design adapts automatically to phone/tablet/desktop:

    p.generate_responsive(artboard="login")
    // → creates login_tablet (768×1024) + login_desktop (1200×800)
    // layout auto-adapts: phone vertical → tablet widened → desktop horizontal multi-column

    p.preview_breakpoint(artboard="login", breakpoint="tablet")
    // → preview the tablet variant

    p.list_breakpoint_variants(artboard="login")
    // → [{"breakpoint":"mobile","width":390}, {"breakpoint":"tablet","width":768}, ...]

    BreakpointSizeAdaptation strategy
    mobile390×844Vertical single column, compact spacing
    tablet768×1024Vertical kept, cards widened ×1.2, spacing 16
    desktop1200×800Horizontal multi-column, spacing 24, margins 48

    #Multi-Agent Collaboration

    The core scenario of the AI era: multiple agents working on one prototype at the same time.

    let cm = CollabManager::new(base_revision=1)
    let agent_a = cm.join("designer_bot") // Agent A: design the login page
    let agent_b = cm.join("ux_optimizer") // Agent B: optimize layout

    agent_a.add_op(OpSetFill("login_btn", "#4B6BFB", "#FF0000"))
    agent_b.add_op(OpSetPosition("login_btn", 24.0, 100.0, 400.0, 450.0))

    let conflicts = cm.total_conflicts() // → 0 (different fields, parallel is safe)

    // If there is a conflict:
    agent_b.add_op(OpSetFill("login_btn", "#4B6BFB", "#00FF00")) // same field, different value
    cm.total_conflicts() // → 1 (needs resolution)
    cm.status() // → "Conflicts: 1 ⚠"

    Conflict rules:

    CaseResult
    Different nodes✅ No conflict
    Same node, different fields✅ No conflict (parallel is safe)
    Same node, same field, same value✅ Idempotent, auto-resolved
    Same node, same field, different values⚠️ Conflict, manual choice required
    One deletes + the other edits⚠️ Conflict, keeping the edit suggested
    Both delete✅ Idempotent

    Operational transform (OT): simultaneous inserts at the same position are ordered by timestamp.

    #Design Version Control

    Every change produces a commit; agents can time-travel, branch, and replay changes:

    let h = DesignHistory::new(doc) h.commit("agent_a", "change button color", ops, doc) // rev 1 h.commit("agent_b", "increase spacing", ops2, doc) // rev 2 h.log() // → "→ rev2 [agent_b] increase spacing rev1 [agent_a] change button color ..." h.checkout(1) // → time-travel to rev1's document snapshot h.undo() // → back to rev1 h.redo() // → forward to rev2 h.replay(0, 2) // → replay all operations h.branch(1, "experiment") // → branch from rev1 h.diff(0, 2) // → semantic diff between two revisions

    #AI Design Critique Engine

    The engine reviews prototypes like a senior designer — not rule checking (that's lint), but a holistic evaluation against 8 design principles:

    PrincipleWhat is checked
    Visual hierarchy≥ 3 font sizes (clear size contrast)
    ProximitySpacing between related elements ≥ 8px (Gestalt)
    AlignmentNodes snap to the grid
    ConsistencyColors come from design tokens
    WhitespaceReasonable density (not cramped, not sparse)
    BalanceLeft/right visual weight is balanced
    FocusA clear primary CTA exists (primary button)
    RhythmSpacing values unify to standard tokens

    p.critique(artboard="login")
    // → {"principles":8,"results":[
    // {"principle":"visual_hierarchy","score":9,"verdict":"good",...},
    // {"principle":"balance","score":6,"verdict":"fair",...},...]}

    p.critique_summary(artboard="login")
    // → "Design Critique: B (7/10)"

    #Design Annotation (Developer Handoff)

    Auto-generate a developer handoff spec from the prototype — the equivalent of Figma Dev Mode:

    p.generate_spec(artboard="login")
    // → Markdown document containing:
    // ## Components (component list + variants + sizes)
    // ## Colors (colors + semantic token mapping)
    // ## Typography (font sizes + tokens)
    // ## Spacing (exact coordinates)
    // ## Layout (flex-direction/gap/padding)
    // ## CSS Custom Properties (--color-* / --spacing-*)

    #Property Animation System

    Prototypes need motion — property interpolation / easing functions / timeline choreography:

    let tl = Timeline::new()
    tl.add(fade_in_animation("title")) // fade in
    tl.add(slide_in_right("card")) // slide in from right
    tl.add(press_animation("submit_btn")) // press bounce
    tl.add_sequence([modal_present("modal"), shake_animation("error")]) // sequential

    tl.to_css() // → generates complete CSS @keyframes + animation

    6 easing functions: Linear / EaseIn / EaseOut / EaseInOut / Spring / Bounce 6 animation presets: press / fade_in / slide_in_right / modal_present / shake / pop Choreography: parallel (add) / sequential (add_sequence) / delayed

    #Design-System Reverse Extraction

    Hand the engine an existing prototype and it infers the design system:

    let ds = p.extract_design_system(artboard="dashboard")
    ds.summary()
    // → Extracted Design System:
    // Colors: 6 tokens
    // primary = #4B6BFB (used 5x, confidence 0.9)
    // surface = #FFFFFF (used 12x, confidence 0.9)
    // error = #BA1A1A (used 1x, confidence 0.5)
    // Spacing: 3 values
    // md = 8px, xl = 16px, xxl = 24px
    // Typography: 4 sizes
    // h2 = 24px, h3 = 20px, body = 14px, caption = 12px
    // Components: 3 patterns
    // card (4 instances), button (2 instances), heading (3 instances)

    Inference logic:
    • Colors: sorted by usage frequency → brightness/saturation analysis → semantic name inferred (primary/surface/error)
    • Spacing: gap/padding identified → matched to standard token names (xs/sm/md/lg/xl)
    • Font sizes: matched to the standard scale (display/h1-h4/body/caption/overline)
    • Components: ≥2 nodes with identical (kind, fill, radius) → inferred as one component pattern

    Extract → reuse loop: Agent extracts a design system from design A → creates design B with those tokens and components → visual consistency is automatic.

    #Theme System

    One-click dark/light/custom theme switching — every node referencing tokens updates automatically:

    p.apply_theme("dark") // → surface becomes #1A1C1E, text #E0E0E0
    p.apply_theme("nord") // → Nordic palette
    p.apply_theme("high_contrast") // → WCAG AAA high contrast

    p.set_token("primary", "#FF5722") // single-token change, global effect
    p.preview_themes("btn") // preview the button under each theme

    p.enable_auto_dark() // derive a dark variant from the current theme

    6 predefined themes:

    ThemeStyleprimarysurface
    lightLight (default)#4B6BFB#FFFFFF
    darkDark#A5B4FC#1A1C1E
    high_contrastHigh contrast#0000EE#FFFFFF
    sepiaSepia#8D6E63#FAF6F0
    nordNordic#88C0D0#3B4252
    sunsetWarm sunset#FF7043#FFF8E1

    Auto dark: Theme::auto_dark(light) → invert luminance, keep hue → a dark variant is generated automatically.

    #Component Slot System

    Like React/Vue children/slots — the agent places content into designated component slots:

    p.place_slotted(artboard="page", component_id="modal", instance_id="dialog")
    p.fill_slot(artboard="page", instance_id="dialog", slot_name="title", content="Confirm")
    p.fill_slot(artboard="page", instance_id="dialog", slot_name="content", content="Are you sure?")
    p.fill_slot_with_component(artboard="page", instance_id="dialog",
    slot_name="actions", child_component="button", child_id="ok_btn") // recursive composition

    6 composable components:

    ComponentSlotsLayout
    cardheader / content / footervertical, gap=8, padding=16
    listheader / item_1..3vertical, gap=4
    form_fieldlabel / input / errorvertical, gap=4
    modaltitle / content / actionsvertical, gap=16, padding=24
    app_barleading / title / trailinghorizontal, gap=12
    tab_bartab_1..4horizontal, gap=0

    Key capabilities:
    • Default content: empty slots auto-fill defaults (Card header → "Title")
    • Recursive composition: fill_slot_with_component puts a Button into the Modal's actions slot
    • Slot inspection: list_slots returns every slot and its current content

    #Performance Benchmark Engine

    After the agent produces a design, the engine answers "will this design run well":

    let bench = p.benchmark_artboard(artboard="dashboard")
    // → { nodes: 15, depth: 3, fill: 8, hug: 2, score: 85 }

    let proj = p.benchmark()
    proj.report()
    // → Performance Benchmark Report
    // Overall: B (72/100)
    // Total nodes: 45
    // [dashboard] 15 nodes, depth 3, 8 Fill, 2 Hug, score 85/100
    // [login] 10 nodes, depth 2, 3 Fill, 1 Hug, score 90/100

    p.suggest_optimizations(artboard="dashboard")
    // → {"optimizations":1,"detail":[{"type":"reduce_fill","description":"8 Fills; fixed sizes would reduce solve work"}]}

    Benchmark metrics:

    MetricMeaningAnti-pattern threshold
    node_countTotal nodes> 100
    max_depthMax tree depth> 8
    fill_node_countFill nodes (layout solve cost)> 30
    hug_node_countHug nodes (highest cost)> 20
    avg_childrenAverage children per node> 15
    layout_complexityLayout solve operation count-
    svg_bytesSVG render output bytes-
    memory_estimateMemory estimate (nodes×200 + text×2)-

    Scoring (0–100): node count(30) + depth(25) + Fill(25) + Hug(20) → A/B/C/D

    #Dual Gates and Visual Debt

    The two editing routes apply different merge thresholds to the same set of non-crash predicates (P0–P4) (core/policy.mbt):

    HumanGate (export-mbt-human / apply-human-mbt-op-b64)AgentGate (export-mbt-agent / apply-agent-mbt-op-b64 / render-mbt-b64)
    Structural predicates (lost nodes/empty artboard/broken flows)Hard block — the patch is rejected as a wholeHard block
    Visual predicates (overflow/overlap/contrast)Soft warning — merge allowed, violations recorded as visual debtHard block — any violation rejects the whole patch
    Typical shapeMid-drag canvas states can be saved with debtProgrammatic edits must be right in one shot

    • Debt is not an error: the human route's export carries the current visual debt list in the debt field; Studio surfaces it as a badge, and later edits or auto_fix can repay it.
    • The agent's responsibility boundary: zero tolerance on the agent route — the engine returns a Reject with the blocking violation list (artboard + predicate name + details), and the agent fixes and replays the patch; this guarantees agent writes never degrade document quality.
    • Render is acceptance: render-mbt-b64 fully rebuilds from source at AgentGate level — products of both routes pass the same render acceptance.

    #Integration Overview

    Seven integration routes, the same .mbt.md fact source, the same dual gates:

    RouteShapeFits
    CLI line protocolmoon run --target native cli (newline-framed JSON; one process = one stateful Project session)Scripts, CI, manual driving
    MCPnpx -y moonviz-mcp (prebuilt platform binary, stdio JSON-RPC) or moon run --target native mcpClaude Desktop / ZCode / Cursor and other MCP clients
    Node SDKnpm moonviz-engine-sdk (spawns the CLI: sessions/Project builder/dual-gate ops/DDP bridge)Node-hosted backends/toolchains
    WASM SDKnpm moonviz-engine-wasm (wasm-gc in-process render/validate, JS String passthrough)Browsers, Edge Functions, dependency-free rendering on Node ≥22
    SKILLRepo-root SKILL.md (agent operation spec: fact-source discipline/dual-gate semantics/red lines)Any coding agent's skill mount
    DDP containerRust ddp_codec (DDP1 encrypted / DDP2 keyless)Encrypted design distribution, read-only viewers
    WASM (classic)moon build --target wasm — pure WASM MVP (0 imports, linear memory), consumed by wasmtime/wasmi and any spec-compliant runtimeRust hosts, server-side embedding

    Every engine-v* tag publishes the full artifact set to GitHub Releases: 4 platform binary tarballs + both wasm builds (versioned, e.g. moonviz-wasm-gc-0.1.3.wasm / moonviz-wasm-classic-0.1.3.wasm) + the current npm package tarballs. Distribution does not depend on npm alone.

    MCP client configuration (npx prebuilt route):

    { "mcpServers": { "moonviz": { "command": "npx", "args": ["-y", "moonviz-mcp"], "env": { "MOONVIZ_DIR": "/path/to/moonviz" } } } }

    Environment variable cheat sheet: MOONVIZ_DIR (engine root, must contain cli/moon.pkg) · MOONVIZ_MOON/MOON (moon executable directory) · MOONVIZ_DDP_HELPER (full path to ddp_codec) · MOONVIZ_CLI_BIN (prebuilt CLI binary, takes precedence over moon run).

    #Tech Stack and Binary Distribution

    #The rendering pipeline in one sentence

    One .mbt.md → declaration parsing (literate block scanning) → scene graph (node tree + Fixed/Fill/Hug size specs) → two-pass layout solve (sizes first, positions second; failure ≠ crash) → P0–P4 non-crash predicates + dual-gate acceptance → three pure-MoonBit render backends: SVG (the vector main path: system font stack + elevation shadow tokens + gradient paints), PNG (a homegrown software rasterizer: 2x supersampled AA + rounded-corner scanning + a 5×7 bitmap font + pure-MoonBit DEFLATE, 5–20× smaller output), and a terminal ANSI true-color canvas (camera pan/zoom + pick & drag). Any host backend (Canvas/Skia/OpenGL) integrates through the backend-agnostic RenderPlan display list. The full pipeline is documented in docs/10-render-pipeline.md.

    #Stack composition

    LayerTechnologyExternal dependencies
    Engine kernel + three render backends + CLI/MCP100% MoonBitmoonbitlang/core standard library only
    WASM boundaryMoonBit → wasm-gcnone (JS String Builtins)
    DDP codecRust (standalone ddp_codec process)argon2 / chacha20poly1305 / zstd
    npm launcher / Node SDKvery thin JSzero dependencies

    #Binary distribution: moon exists only at compile time

    moon build --release --target native produces self-contained binaries (CLI 1.26MB / MCP 1.10MB; otool -L verifies they link only the system libc). Copy them to a machine without moon or sources and they just work. Distribution matrix:

    ConsumerNeeds moon?Needs engine sources?
    npx moonviz-mcp (MCP clients)✗✗ (source-side tools set MOONVIZ_DIR)
    Node SDK + moonviz-bin-<platform>✗ (auto-discovers the prebuilt CLI)✗
    Browsers / Edge (moonviz-engine-wasm)✗✗
    Engine developers✓✓

    Binary archives are also published on GitHub Releases (engine-v* tags), so distribution does not depend on npm alone.

    #MoonBit toolchain risk management

    MoonBit evolves fast; minor versions carry real behavioral risk. Four layers of mitigation:

    1. Artifact freezing (the fundamental measure): prebuilt binaries and WASM are snapshotted once released — later breaking toolchain changes cannot affect any distributed artifact; language uncertainty is isolated at build time.
    2. Build toolchain: CI (binaries.yml) installs the latest moon (pinned versions have been pulled from the download CDN); toolchain upgrades are exercised by the full test suite + CLI/MCP smoke gates on every build.
    3. Protocol stability: external protocols such as SolvedLayout / GateDecision / RenderPlan are deliberately stable (the solver reserves a Cassowary swap interface) and do not drift with language versions.
    4. Component isolation as backstop: DDP already demonstrates the standalone-process route for non-MoonBit components; in the extreme, any component can be replaced that way without touching the .mbt.md fact-source format.

    #Architecture Red Lines

    • The engine depends on no client: core/decl are pure libraries
    • Agents have zero dependency on the engine internals: interaction happens over the JSON text protocol
    • 100% MoonBit: zero hand-written JS/Node/frontend code

    #Documentation Index

    • Website and full usage docs: https://asdshuaishuai.github.io/moonviz/ (usage / CLI / Node SDK / WASM / MCP / SKILL / DDP)

    1. 01-architecture.md — Layered architecture
    2. 02-mbtmd-format.md — The .mbt.md spec and the declaration DSL
    3. 03-scene-graph.md — The visual document model
    4. 04-layout-and-predicates.md — Layout engine and non-crash predicates
    5. 05-sync-pipeline.md — Bidirectional incremental sync pipeline
    6. 06-render.md — Render backends
    7. 07-agent-loop.md — Agent workflow and error-fix loop
    8. 08-roadmap-risks.md — Implementation path and risks
    9. 09-rendering-ecosystem.md — MoonBit rendering ecosystem survey
    10. 10-render-pipeline.md — Complete technical notes on the rendering scheme and pipeline (declaration parsing → layout → predicates → SVG/PNG/terminal backends + tech stack + binary distribution and toolchain risk)
    11. 11-user-components.md — User components (component_compile / component_import / component_export)