MoUI examples are runnable documentation. Showcase is the visual catalog and
now follows the same TEA shape as ordinary apps: Model / Msg / update / view
driven by Program::simple_with_environment. It still contains the Counter and
Todo interaction patterns. The WYSIWYG Markdown editor stays separate because
it demonstrates a larger editing workflow with its own model and parser tests.
Apps that need host-service work should use Program::new with Effect[Msg];
prefer Effect::host_service when a host-service bridge should carry a stable
diagnostic key, use Effect::run for custom structured async bridges, and use
Effect::service_task when a service-like one-shot async task needs runtime
managed cancellation, completion, and stale-dispatch diagnostics. Use
Effect::task for custom task kinds. Apps that need ongoing typed callbacks can
add subscriptions=model => ... and stable Subscription keys while keeping
concrete timer or host adapters out of core.
Showcase surfaces renderer capability follow-ups first so visible docs do not
hide partial or gap status behind ready features. The dedicated
examples/design_systems/app package owns Material, Carbon, Primer, and Fluent
source-mapped preview UI plus the Sickle first-party theme addon sampler, so
Showcase remains a MoUI framework catalog and does not depend on moui_theme.
Sickle lives in moui_theme/sickle as a first-party theme addon rather than an
official source-mapped preset. Design Systems is addon diagnostic coverage with
Web wasm-gc and macOS, Windows, and Linux Skia entrypoints for trying the addon
sampler outside the framework Showcase.
Use the Non-render component cookbook when you want to copy a pattern rather than inspect a full example package. It maps forms, tables, shells, menus, host services, timers, clipboard, window events, and virtual lists to the examples that exercise them. For a single runnable surface that packs those host recipes plus canvas paint, open Showcase's Platform workspace.
Use App templates when starting a new shared app package.
Standalone apps should use moui new (see Getting started);
the docs skeletons cover counter, dashboard, and document-editor shapes for
monorepo or hand-authored packages. The root website/ workspace uses the same
app-first shape outside examples/ so MoUI can render its own bilingual
homepage.
Mobile packaging metadata lives in moui.mobile.json. Application code stays
in examples/<app>/app; Android, iOS, and HarmonyOS use matching
*_window_hosted entrypoints plus the wzzc-dev/window templates. The
templates own native lifecycle, surface creation, and input, while the MoUI
entrypoint supplies the program and renderer provider. Run
sh scripts/window-hosted-hostsim-smoke.sh after changing the mobile host path.
| Example | Purpose | Shared app package | Main coverage |
|---|---|---|---|
| Website | MoUI-built homepage workspace | website/app/ |
Bilingual product homepage, first-screen MoUI brand hero, compact Counter code snippet, interactive runtime preview, framework foundations, platform matrix, release-readiness cards, quick-start Web commands, runtime Docs portal that fetches packaged same-origin docs/*.md Markdown plus MoUI and moui_skia README copies, Web-only website/web_wasm entrypoint |
| Playground | MoonBit-native browser tutorial and editor | website/playground/app/, website/playground/web_wasm/ |
Code editor built with moui_richtext, controlled main.mbt/moon.pkg files, app-safe import validation, pinned MoonBit compiler Worker bridge, sandbox preview host, local persistence, share URL protocol, and six bilingual lesson assets |
| Agent Counter | Minimal agent-controllable runtime example | examples/agent_counter/, examples/agent_counter/main/, examples/agent_counter/macos_skia/ |
Counter app with semantics/command-intent flow for agent observation and control, plus a native macOS Skia entrypoint |
| Counter | Minimal model/update/view app | examples/counter/app/ |
Simple Program::simple flow, center/card, typed button messages, and Android/iOS/HarmonyOS window-hosted entrypoints |
| Multi Window | Host-managed scene example | examples/multi_window/app/ |
Independent main and inspector runtimes through HostWindowActions (open / focus / close) plus HostWindowRequestQueue and HostWindowSceneResolver, with native macOS/Windows/Linux windows and a multi-canvas Web route |
| HarmonyOS Demo | Standalone experimental HarmonyOS window-hosted demo | examples/harmonyos_demo/app/, examples/harmonyos_demo/harmonyos_window_hosted/ |
Platform-neutral viewport/tap feedback demo, HarmonyOS window-hosted entrypoint, and HAP packaging through the wzzc-dev/window template; runtime support remains pending matching-device evidence |
| Button Freeze Probe | Native Skia button freeze repro | examples/button_freeze_probe/app/ |
Minimal data_filter_bar filter chips, red primary accent, repeated click counter, direct primary/tonal button comparison, native Skia macOS/Windows/Linux entrypoints |
| Showcase | Unified component, pattern, platform, and diagnostic catalog | examples/showcase/app/ |
A root TEA shell over four isolated packages: Components owns focused moui/views demos; Patterns owns Counter/Todo, forms, data, navigation, feedback, and text/media workflows; Platform owns timer/window/clipboard/file/canvas recipes, route/session facts, and Mobile Service Probe; Diagnostics alone imports runtime/render internals for inspector and advanced rendering. Web, desktop Skia/WGPU/Sun, and Android/iOS/HarmonyOS entrypoints all call the same root app. Showcase intentionally has no moui_theme dependency and is not an official design-system compatibility claim. |
| Design Systems | Addon diagnostic source-mapped design-system preview and first-party theme sampler | examples/design_systems/app/, examples/design_systems/{web_wasm,macos_skia,windows_skia,linux_skia}/ |
Material, Carbon, Primer, and Fluent switching through the moui_theme/material, moui_theme/carbon, moui_theme/primer, and moui_theme/fluent entrypoints over shared moui_theme/common models, Sickle switching through moui_theme/sickle as a first-party theme addon, light/dark/high-contrast/system variants for official source-mapped presets, compact/standard/comfortable density, semantic palette roles, typography specimen, spacing/density grid, component-token matrix sampling, component style bundle usage, custom inheritance/override API, Web and native Skia host entrypoints, coverage/parity status labels, and explicit source-mapped preview wording rather than official-complete claims |
| Settings | Settings shell pattern | examples/settings/app/ |
Form sections, sidebar navigation, segmented theme mode, toggle preferences, saveable state snapshot/restore |
| Data Table | Operational data browser pattern | examples/data_table/app/ |
Search/filter toolbar pattern, status chips, ColumnVisibilityState, sortable table headers with DataSortState, app-owned column width/order state, row selection with SelectionState, selection toolbar actions, tree filters, loading/error/empty states, PaginationState, public pagination and detail_panel, model-level filtering and data slicing |
| Excel | Spreadsheet workbook prototype | examples/excel/{cell,formula,sheet,xlsx,app}/, examples/excel/{macos_skia,linux_skia}/ |
Native .xlsx workbook load/save flow through an app-private xlsx adapter, desktop spreadsheet shell, formula/name bars, sheet tabs, cell edit/copy/cut/paste/delete, row/column insertion, undo/redo, formula evaluation, number formats, color swatches, heat-map display, host file services, and macOS/Linux Skia entrypoints |
| File Importer | File import workflow pattern | examples/file_importer/app/ |
Drop zone, file dialog facade, unavailable service state, pending completion handling, selected file list |
| WebView Demo | Native platform WebView pattern | examples/webview_demo/app/ |
Controlled web_view primitive, native host capability fallback, address bar, navigation commands, JavaScript evaluation command, macOS/Windows/Linux Skia native entrypoints, Web wasm unavailable fallback without iframe |
| PDF Workbench | PDF reading and light editing prototype | examples/pdf_workbench/app/ |
Clean native PDF reader/editor shell, host binary file service open/save flow, PDFium page bitmap preview, fit-width responsive reading canvas, scrollable page/inspector panels, reader fullscreen toggle, page navigation/direct page jump/search/metadata summaries, undoable/discardable preview rotate/crop/stamp/title/bookmark/note edit state, separate pdflite_adapter package for real parsing/writeback checks, JSONL pdflite helper protocol plus native process transport, native-only pdfium_adapter package for page rasterization, macOS/Windows/Linux Skia native entrypoints |
| Command Palette | Command metadata and menu pattern | examples/command_palette/app/ |
Command palette rows, shortcut labels, enabled/disabled dispatch, command menu, context menu fallback, program_with_services, and HostAppServices::show_context_menu native menu preview |
| Markdown Editor | Typora-style editing prototype | examples/markdown_editor/app/ |
Editor snapshot core, mizchi/markdown parsing, source-range mapping, primary rich text editor, optional source preview |
| Code Editor | Native code editor shell and language-provider prototype | examples/code_editor/app/ |
Native moui_richtext editor shell with activity rail, file tab, line-number gutter, status bar, tokenizer-backed highlighting, bracket matching, auto indentation, multi-cursor edits, hidden find/replace overlay, runtime action-command shortcuts, completion overlay, diagnostics, hover, go-to-definition, main-editor Diff mode, and custom language/provider registration through app-owned callbacks |
| Mo Desktop | macOS-inspired responsive desktop simulation | examples/mo_desktop/app/ |
Lock/unlock session, image wallpaper, menu bar, live dock, calendar/weather/task widgets, responsive Finder with navigation/search/icon-list modes/selection, Safari start page and search results, searchable Apps/Actions launcher, notifications, Control Center toggles/sliders, global light/dark appearance, Web wasm-gc and macOS Skia entrypoints |
| Mo Workbench | Native-Skia-first desktop agent dogfood app | examples/mo_workbench/app/ |
Work/Code/Design task shell with a session dashboard, interactive coding-agent chat, product-state/palette preview, responsive searchable task sidebar, settings overlay, backend-aware OpenSeek/ACP controls, injected stub backend, OpenSeek native transport, generic ACP stdio native transport, and a macOS Skia entrypoint |
Focused Website checks:
moon test website/app --target native
moon build website/web_wasm --target wasm-gcThe Website Docs page is part of the same MoUI app state as the homepage. It
does not precompile Markdown into wasm; the Web host text-file service fetches
the selected same-origin Markdown file from docs/ at runtime. For local
preview, run node scripts/sync-website-docs.mjs so website/web_wasm/docs/
contains the root docs plus moui-readme.md and moui-skia-readme.md. The
GitHub Pages workflow packages website/web_wasm with
scripts/package-web-app.mjs for release/strip wasm, local runtime JS,
precompressed assets, and bundle-size.json, then runs
node scripts/sync-website-docs.mjs --out dist/pages/docs so the published
site fetches the same Markdown paths from docs/.
Counter is the smallest recommended app shape. It keeps user code in
Model / Msg / update / view, then lets Program::simple connect that pure
model loop to the runtime. It has Web, macOS, Windows, Linux, experimental
Android and iOS Skia embedded-session entrypoints plus managed Kotlin/SwiftUI
packaging and a windows_wgpu_cosmic entrypoint, so it is also the quickest way
to verify a thin platform package without the full Showcase surface:
using @views {button, card, center, column, row, text}
pub struct Model {
count : Int
}
pub(all) enum Msg {
Increment
Decrement
Reset
}
pub fn update(model : Model, msg : Msg) -> Model {
match msg {
Increment => { count: model.count + 1 }
Decrement => { count: model.count - 1 }
Reset => { count: 0 }
}
}
pub fn view(model : Model) -> @moui.View[Msg] {
center(
card(
column([
text("MoUI Counter").title(),
text("Count: \{model.count}").title(),
row([
button("-", on_click=Decrement),
button("Reset", on_click=Reset),
button("+", on_click=Increment),
]),
]),
),
)
}
pub fn program() -> @moui.Program[Model, Msg] {
@moui.Program::simple(init=Model::new(), update~, view~)
}Focused Counter checks:
moon test examples/counter/app --target native
moon build examples/counter/web_wasm --target wasm-gc
MOUI_SKIA_DISABLE_PREBUILD_SKIA=1 moon check examples/counter/android_window_hosted --target native
MOUI_SKIA_DISABLE_PREBUILD_SKIA=1 moon check examples/counter/ios_window_hosted --target native
sh scripts/window-hosted-hostsim-smoke.shFallback APK and .app builds validate packaging paths only. Use a matching
device or simulator smoke before claiming first-frame runtime support.
HarmonyOS Demo is the standalone experimental HarmonyOS app. It deliberately
does not extend Counter: examples/harmonyos_demo/app owns the shared TEA UI
with visible tap and viewport feedback, and
examples/harmonyos_demo/harmonyos_window_hosted creates the window-hosted
application. The wzzc-dev/window/harmonyos template owns the Stage Ability
and XComponent bridge; app source does not keep a native project fixture.
Focused HarmonyOS Demo checks:
MOUI_SKIA_DISABLE_PREBUILD_SKIA=1 moon test examples/harmonyos_demo/app --target native
MOUI_SKIA_DISABLE_PREBUILD_SKIA=1 moon check examples/harmonyos_demo/harmonyos_window_hosted --target native
sh scripts/window-hosted-hostsim-smoke.sh
moui build harmonyos harmonyos_demo \
--mobile-config "$PWD/examples/harmonyos_demo/moui.mobile.json" --fallback-skiaFor real HarmonyOS Skia checks, use the locked HarmonyOS release artifact:
MOUI_SKIA_PLATFORM=harmonyos MOUI_SKIA_ARCH=arm64 MOUI_SKIA_LINK_MODE=static \
moon check examples/harmonyos_demo/harmonyos_window_hosted --target nativeHarmonyOS auto / skia-gpu builds require the complete static provider. The
locked shared libskia.so is usable for raster rendering, but hides Ganesh
internal symbols referenced by libskia_ganesh_ext.a; use dynamic linking only
with explicit skia-raster. Leaving MOUI_SKIA_LINK_MODE unset lets the shell
builder choose static for GPU and dynamic for raster.
Fallback HAP builds validate MoonBit C/native glue/staged package shape only. Use a matching device or emulator smoke before claiming HarmonyOS first-frame runtime support.
Button Freeze Probe isolates the native Skia click-freeze investigation from
the full Showcase surface. It keeps only the reusable data_filter_bar search
input, selected filter chips, direct primary/tonal button comparison, and a
small click/action readout so repeated clicks exercise the same focused-input,
button dispatch, and redraw path without table, tree, pagination, or renderer
catalog noise.
Focused Button Freeze Probe checks:
moon test examples/button_freeze_probe/app --target native
moon build examples/button_freeze_probe/macos_skia --target nativeCode Editor is a native-only editor shell. It does not embed Monaco or a
WebView; the editable surface is moui_richtext.controlled_rich_text_editor
with app-owned editor chrome, code formatting, and language-service state. The
shared app owns the source buffer, cursors, hidden find/replace overlay,
completion overlay, diagnostics, hover result, definition target,
bracket-match state, and a main-editor Diff mode for review and patch
inspection.
Language support is registered through CodeLanguageRegistry and
CodeLanguageProvider callbacks. Providers supply tokenizer, completion,
diagnostics, hover, and definition callbacks, so the example demonstrates
custom language registration without moving app-specific language-service APIs
into the MoUI framework. Native entrypoints register the editor's
ActionCommandMap with the runtime for shortcut metadata.
Focused Code Editor checks:
moon test examples/code_editor/app --target native
moon check examples/code_editor/macos_skia --target native
moon check examples/code_editor/windows_skia --target native
moon check examples/code_editor/linux_skia --target nativeWebView Demo shows the native platform-view path without involving renderer
draw commands. The shared app owns controlled navigation state: a page link
emits NavigationRequested, the model updates url, and the host commits the
real native WebView to the next DrawFrame.platform_views rectangle. Buttons
exercise the host command queue for load, reload, stop, back, forward, and
JavaScript evaluation.
Native entrypoints pass the same HostWebViewCommandQueue to the Skia provider
options so macOS WKWebView, Windows WebView2 builds, and Linux WebKitGTK
builds can drain commands after rendering. Web wasm passes an unavailable
capability and renders fallback UI; it does not create an iframe overlay.
Windows real WebView builds are auto-detected by the prebuild from
.tools/webview2/ (set up by scripts/windows/setup_msvc_deps.ps1 -InstallWebView2),
matching how Linux auto-detects WebKitGTK via pkg-config. Override with
MOUI_WINDOWS_WEBVIEW2_* environment variables for custom SDK paths.
Linux WebKitGTK builds are auto-detected via pkg-config when
libwebkit2gtk-4.1-dev is installed. Override with MOUI_LINUX_WEBKITGTK_*
environment variables for custom setups.
Linux WebKitGTK builds also require a matching-host smoke before claiming
runtime evidence: the backend pumps the GTK main context, syncs
DrawFrame.platform_views placements, forwards navigation/title/history/script
events, and drains queued commands after each rendered frame, but package checks
only prove the contract mapping and fallback path.
Focused WebView Demo checks:
moon test examples/webview_demo/app --target native
moon check examples/webview_demo/macos_skia --target native
moon check examples/webview_demo/windows_skia --target native
moon check examples/webview_demo/linux_skia --target native
moon check examples/webview_demo/web_wasm --target wasm-gcConfigured Linux WebKitGTK check (auto-detected when packages are installed):
moon check examples/webview_demo/linux_skia --target nativeShowcase is organized around the main catalog order:
Overview -> Examples -> Text & Media -> Controls -> Forms -> Data -> Layout -> Navigation Shell -> Feedback -> Runtime/Renderer -> Diagnostics. The first nine sections
cover user-facing components and layout patterns. Runtime/Renderer displays
host capability and renderer status cards. Diagnostics shows a compact
inspector snapshot with runtime, TEA program message/effect task/subscription,
duplicate key names, view, layout, semantics, render command, and render-scope
counters, then links to the deeper diagnostic routes for
interaction wiring, text diagnostics, and advanced rendering without crowding
the main sidebar.
The hidden diagnostic routes remain directly addressable for focused tests and development workflows:
Advanced Rendering: app-localcustom_layoutdemos for layer/blend, filter, shader effect, path, transform, and opacity draw commands.Text Diagnostics: CJK mixed text, RTL/bidi samples, emoji status labels, fixed-width wrapping, a narrowTextRun.frameclipping sample, and a compact Markdown/rich text diagnostic.Interaction Lab: tooltip, file-drop modifier wiring, FocusScope traversal, first-invalid targeting, Enter/Escape command targets, shortcut affordances, runtimeView::focus_trapcontainment, publicshortcut_buttondispatch, app-ownedfocus_ringaffordances, popover/dropdown expanded semantics, pressed/selected/disabled semantic state examples, button/text-field variants, and deterministic image lifecycle states.Forms: validating/help/error/disabled/read-only field states, keyed first-invalid focus targets, and submit-guard state for the form workflow bar.Navigation Shell: route headers, section navigation, breadcrumbs, dialogs, sheets, command metadata, app-owned route/deep-link history, a controlled fade/slide route transition preview, a controlled drag-resizable split pane, andRouteFocusStorestate showing whichruntime.focus_key(...)call should restore route focus after a route switch.HostRouteSourceprovides the host-layer route/deep-link subscription fanout that apps can feed into this shared state, but the visible route history is still a serializable shadow stack and the transition is sampled by app state; browser history, automatic route-transition scheduling, and native deep-link dispatch remain host/app follow-up work.Feedback: toast/banner/callout/progress/inline-error surfaces plus aToastQueueexample that converts queued items intotoast_stackrows while keeping timers in the app model.Examples: Counter and Todo reusable app patterns until the dedicated example apps cover those workflows.
The Markdown editor keeps Markdown source as the saved value while presenting a formatted editor surface as the primary workflow. Source preview remains available from the toolbar. See Markdown Editor for the editing model, source/visual mapping, contextual commands, and validation guidance.
The Settings example is a shared app package without platform entrypoints. It
shows the recommended non-render shell for account preferences: a public sidebar
constructor drives controlled section selection, form fields own validation
messages in the app model, segmented controls choose light/dark/system theme
mode, and SaveableStateStore snapshots restore the current settings without a
host service.
The Data Table example is also shared-app only. It models the data workflow that
operational tools usually need before renderer-specific polish: controlled
search/filter toolbar, status chips, column visibility, app-owned column width
and order controls, sortable table headers, tree filters, stable model-level
sorting, page navigation, selected-row detail, plus empty/loading/error panels
built from public views constructors.
The app keeps filtering, sorting, and page slicing in its TEA model while using
public DataSortState, PaginationState, ColumnVisibilityState,
ColumnWidthState, ColumnOrderState, SelectionState, data_filter_bar,
table sort-header, row-selection, column_visibility_panel,
selection_toolbar, pagination, and detail_panel helpers for reusable view
structure. Filter predicates, async requests, pointer-specific header gestures,
column width/order persistence, and bulk action effects remain app-owned.
The Excel example is a native spreadsheet-workbook prototype. The app package
owns the MoUI application, TEA messages, host-service file effects, and command map,
while app-private cell, formula, sheet, and xlsx packages own cell
coordinates/value formatting, formula evaluation, pure workbook operations, and
mbtexcel import/export. The visible surface is intentionally desktop
spreadsheet-first: grouped file/edit/format/number/view controls, formula and
cell-reference inputs, scrollable grid, bottom sheet tabs, status bar, color
swatches, number formatting, and heat-map display.
Focused Excel checks:
moon test examples/excel/cell --target native
moon test examples/excel/formula --target native
moon test examples/excel/sheet --target native
moon test examples/excel/xlsx --target native
moon test examples/excel/app --target native
moon check examples/excel/macos_skia --target nativeThe File Importer example demonstrates the non-render file workflow surface. The
view uses drop_zone and file_import_panel; the pure model accepts dropped
paths, while the effect-capable runtime uses Program::new and
Effect::host_service to request an app-level host file dialog through
HostAppServices and feed unavailable, immediate, or pending responses back as
typed HostCompleted messages. Pending file-dialog responses are stored as
model state and declared through HostAppServices::completion_subscription, so
the later host completion dispatches through the same typed TEA update path as
synchronous responses and cancels when the model leaves Pending. Its app
tests also compose the importer as a child feature with View::map,
Effect::map, and Subscription::map, which is the recommended pattern when a
parent TEA model owns a child workflow that can still return follow-up effects
or ongoing event sources; the parent runtime assertions also keep the mapped
child effect descriptors, active completion subscription descriptor, and
subscription lifecycle cancellation visible through program diagnostics.
Browser hosts commonly expose file
names while native hosts can expose filesystem paths, so production apps should
treat these strings as host-provided display or import handles rather than
assuming one platform shape.
PDF Workbench is a MoUI example-level PDF reader and light editor. Its shared
app package is intentionally a lightweight UI shell so the native Skia
entrypoint does not pull the full PDF parser into one huge generated C
translation unit. The app keeps host interaction in TEA effects: open uses a
file dialog followed by HostAppServices::read_binary_file, while save and
save-as write through HostAppServices::write_binary_file; save-as defaults
the dialog name to the current PDF file name and appends .pdf when the source
path has no .pdf suffix. Clean documents write unchanged original bytes, while
dirty documents ask the injected
PdfWorkbenchDocumentServices writeback hook for new PDF bytes before writing.
After a dirty save succeeds, the app reloads the written bytes through the same
document service so the clean snapshot, metadata, page summaries, and queued
diagnostics reflect the actual saved PDF rather than stale preview state.
Preview edits are tracked as an app-owned edit log with a clean snapshot so the
user can undo the last queued edit or discard queued changes before saving. The
right inspector keeps those controls grouped as Page, Queue, Document, and
Diagnostics sections: page operations stay near undo/discard, queued edits show
as compact rows, the saved/unsaved badge and zoom percentage stay visible, and
parser/raster/writeback diagnostics are separated from primary editing actions.
The current pdflite adapter applies rotate/crop edits, writes stamp text back as
a standard-font overlay, updates the PDF Info dictionary title, adds
current-page bookmarks, and writes current-page text annotations when saving
dirty documents.
The reader shell is responsive: wide windows show thumbnails, the page canvas,
and the inspector side by side, while narrower windows hide side panels so the
PDF bitmap remains the primary readable surface. The page toolbar can also
switch the reader into a fullscreen window-filling mode that hides the app
chrome and side panels until the user exits it. The page toolbar includes
previous/next, direct page jump, zoom in/out, and a Fit action that returns to
the fit-width 100% baseline while reusing the raster cache when available.
The search field exposes previous/next hit controls and a compact active
match-position label such as Find: 2/5; opening a new PDF clears stale search
state so results always refer to the current document.
When the inspector is hidden, the page surface keeps a compact edit strip for
rotate, crop, stamp, undo, and discard so light editing stays available in the
reader-first layout.
examples/pdf_workbench/pdflite_adapter owns the direct
bobzhang/pdflite dependency for real PDF parse/text/outline/annotation
summary and rotate/crop/stamp/title/bookmark/note writeback checks. It is kept
outside the default native Skia entrypoints for now because directly importing
pdflite into the app executable triggers the same large native compile path the
prototype is trying to avoid. The
examples/pdf_workbench/pdflite_service_protocol package defines that boundary
as typed load/writeback requests plus JSONL-safe responses. Request/writeback
PDF bytes use base64 payload fields, while document-loaded responses carry
reconstructable metadata, outline, annotation, page-summary, diagnostic, and
page-count fields without echoing the original PDF bytes. The
examples/pdf_workbench/pdflite_service_native_transport package turns that
JSONL protocol into PdfWorkbenchDocumentServices by spawning a helper process
per load/writeback request, so native Skia entrypoints can stay thin and avoid
direct pdflite imports. The helper executable itself can still have a slow first
native compile because it intentionally contains pdflite; that cost is isolated
from the PDF Workbench UI binary.
examples/pdf_workbench/pdfium_adapter owns the native-only PDFium C FFI for
existing-page rasterization. The shared app depends only on injected
document/raster service interfaces, so Web and app-package tests still build
without pdflite or PDFium while native Skia entrypoints pass the PDFium raster
service. Its focused native test covers both fallback-unavailable behavior and,
when PDFium is linked, real BMP output with expected page dimensions, 32-bit
pixel metadata, file-size consistency, and rendering page 2 of a generated
multi-page PDF.
When PDFium is linked, opening, paging, direct page jumps, or zooming a PDF
requests a bitmap raster and the preview draws it through MoUI DrawImage with
a local BMP source path. The shared app keeps a small most-recently-used raster
cache for page/zoom combinations so backtracking stays fast without unbounded
bitmap growth, and the Pages sidebar reuses cached page bitmaps as real
thumbnails for pages the reader has already visited. If PDFium is disabled or
rendering fails, the app keeps the loaded document, falls back to the
structural MoUI preview with diagnostics, and shows a dismissible failure
banner. The Skia PDF backend is reserved for a future export/generation route
that writes MoUI draw commands to PDF; it is not used to rasterize existing PDF
pages.
For an interactive startup run, set MOUI_PDF_WORKBENCH_STARTUP_PDF to a PDF
path such as examples/pdf_workbench/fixtures/minimum.pdf; the startup path
uses the same binary-read, document-load, and PDFium raster request flow as the
Open button. node scripts/pdf-workbench-native-smoke.mjs keeps the automated
check to PDFium real-raster tests plus native entrypoint builds.
Set MOUI_PDF_WORKBENCH_PDFLITE_HELPER to an already-built
pdflite_service_cli executable when you want native Skia runs to use the real
pdflite document model. Use MOUI_PDF_WORKBENCH_PDFLITE_HELPER=auto from the
repository root to target the conventional native debug helper path under
_build/native/debug/build/examples/pdf_workbench/pdflite_service_cli/.
MOUI_PDF_WORKBENCH_PDFLITE_HELPER_ARGS may be a whitespace-separated argument
string or a JSON string array, and
MOUI_PDF_WORKBENCH_PDFLITE_HELPER_CWD sets the helper working directory for
fixture or packaged-app smoke runs. When the helper variable is absent, the
entrypoints keep the lightweight document summary fallback but still use PDFium
for page bitmaps.
Focused PDF Workbench checks:
moon test examples/pdf_workbench/app --target native
moon test examples/pdf_workbench/app --target native --filter 'pdf workbench lightweight smoke covers startup raster navigation search and cache'
moon test examples/pdf_workbench/app --target wasm-gc
moon test examples/pdf_workbench/pdflite_service_protocol --target native
moon test examples/pdf_workbench/pdflite_service_protocol --target wasm-gc
moon test examples/pdf_workbench/pdflite_service_native_transport --target native
moon test examples/pdf_workbench/pdflite_adapter --target native
MOUI_PDFIUM_ENABLE_PREBUILD_PDFIUM=1 moon test examples/pdf_workbench/pdfium_adapter --target native
moon test moui/backend/host --target native
moon build examples/pdf_workbench/macos_skia --target native
node scripts/pdf-workbench-native-smoke.mjs
scripts/pdf-workbench-macos-smoke.sh
MOUI_PDF_WORKBENCH_STARTUP_PDF=examples/pdf_workbench/fixtures/minimum.pdf moon run examples/pdf_workbench/macos_skia --target native
moon build examples/pdf_workbench/windows_skia --target native
moon build examples/pdf_workbench/linux_skia --target nativeThe PDFium provider is a module-level prebuild hook, but it does not download
PDFium by default. Set MOUI_PDFIUM_ENABLE_PREBUILD_PDFIUM=1 only for real
raster adapter validation, or provide MOUI_PDFIUM_INCLUDE plus
MOUI_PDFIUM_LIB_DIR to use a local PDFium install.
The named lightweight smoke uses fake document and raster services to exercise
startup open, bitmap drawing, multi-page navigation, search, zoom, and raster
cache reuse without compiling the pdflite helper executable.
node scripts/pdf-workbench-native-smoke.mjs is the matching-host real-raster
smoke. It runs the PDFium adapter tests, builds the current host's native Skia
entrypoint, and verifies the log contains the PDFium bitmap path.
scripts/pdf-workbench-macos-smoke.sh is a macOS convenience wrapper for the
same runner.
The Command Palette example keeps command definitions in @views.ActionCommand
metadata, renders them through the public palette and command menu views, and
uses @views.ActionCommandMap for shortcut dispatch. Disabled commands stay
visible for discoverability but do not dispatch through model actions or runtime
command bindings. Its effect-capable program_with_services path demonstrates
HostAppServices::show_context_menu, dispatching the selected native menu
command back through the same typed message loop while preserving the view-level
fallback context menu for hosts without native menu support.
Mo Desktop is a platform-neutral desktop simulation inspired by the macOS 27 reference. It starts on a full-screen lock surface and unlocks into a layered desktop with persistent menu and dock chrome. Finder is the primary workspace; Safari, the app launcher, Control Center, and Notification Center share the same typed model and update path. Narrow viewports hide decorative widgets, collapse Finder's sidebar into location tabs, and keep the dock and overlays inside the available canvas.
The example intentionally implements a smaller set of working apps and system surfaces instead of rendering inactive dock placeholders. Finder navigation, search, view modes, and selection are controlled; Safari supports a start page and query results; Control Center owns appearance, connectivity, brightness, volume, and battery preferences; Notification Center owns read state and task completion.
Focused checks:
moon test examples/mo_desktop/app --target native
moon test examples/mo_desktop/app --target wasm-gc
moon build examples/mo_desktop/web_wasm --target wasm-gc
moon build examples/mo_desktop/macos_skia --target nativeMo Workbench is the native-Skia-first desktop agent dogfood app. Its portable
shared app package is a Work / Code / Design task shell with a
responsive task sidebar and injected AgentBackendRuntime; the macOS Skia
entrypoint selects OpenSeek or a generic ACP stdio subprocess backend from
settings.
The current surfaces are:
- Work: session summary cards, next actions, and recent tasks. Review, Running, and All task actions open the Code tab with the matching sidebar filter.
- Code: session history, message timeline, starter cards, model/thinking or ACP controls, prompt composer, steering while streaming, and permission responses.
- Design: live task/model/settings/typography state plus control and palette previews; it is not a design-document editor.
- Settings overlay: API, Agent, and Editor preferences for backend/provider configuration, ACP command/args/cwd, working directory, approval policy, sandbox, appearance, and font size.
The sidebar supports task search, status filters, expandable task groups, settings, and the appearance toggle.
The ACP backend implements stdio JSON-RPC as an ACP client/control side. It supports baseline session creation, prompt turns, cancellation, session updates, mode/config updates, and permission requests. It intentionally advertises no client filesystem or terminal capability in this slice.
Focused checks for the current slice:
moon test examples/mo_workbench/app --target native
moon test examples/mo_workbench/acp_native_transport --target native
moon test examples/mo_workbench/app --target wasm-gc
moon build examples/mo_workbench/macos_skia --target nativeSee Mo Workbench for the app architecture, current slice, connector boundary, and transport follow-up notes.
Build any Web example from the repository root, then serve the repository with a local static server:
moon build examples/counter/web_wasm --target wasm-gc
moon build examples/showcase/web_wasm --target wasm-gc
moon build examples/markdown_editor/web_wasm --target wasm-gc
moon build examples/mo_desktop/web_wasm --target wasm-gc
moon build website/web_wasm --target wasm-gc
python3 -m http.server 8080 --bind 127.0.0.1Open the corresponding examples/*/web_wasm/index.html page from the local
server, or website/web_wasm/index.html for the homepage/docs workspace. The
Web path uses wasm-gc + window/web + browser WebGPU host imports; there is no
JS-target fallback. Serve from the repository root when testing Website Docs so
the browser can fetch the static docs/*.md files by relative path.
For release-size checks and packaged Web artifacts, use:
node scripts/web-bundle-size.mjs examples/counter/web_wasm --json
node scripts/package-web-app.mjs examples/counter/web_wasm --out artifacts/web/counterThe package helper emits release/strip wasm, MoUI Web runtime JS, precompressed
.gz/.br siblings, bundle-size.json, and any files under the Web entrypoint
assets/ directory. Keep large app resources out of MoonBit source: small
constants can remain in code, but large images, long Markdown, large JSON, and
fixtures should live under assets/ and be referenced with relative URLs such
as assets/logo.png or assets/story/buttons.json. Web text/Markdown/JSON
loads must stay same-origin; the browser host rejects cross-origin text-file
fetches.
macOS examples use the shared app package plus the macOS host core and renderer
provider packages. The recommended native entrypoints import
backend/macos/skia through the _skia packages:
moon build examples/showcase/macos_skia --target native
moon build examples/markdown_editor/macos_skia --target native
moon build examples/pdf_workbench/macos_skia --target native
moon build examples/pdf_workbench/windows_skia --target native
moon build examples/pdf_workbench/linux_skia --target native
moon build examples/mo_desktop/macos_skia --target native
moon build examples/mo_workbench/macos_skia --target nativeThe macos_skia entrypoints select the native Skia raster renderer explicitly.
They require the local Skia native link setup that makes moui_skia/native
available at runtime. Normal macOS Skia runs use the renderer's system
FontMgr path; tester-owned first-frame smoke runs explicitly select the
EmptyTypeface fallback path. The
macos_wgpu and macos_wgpu_cosmic packages remain available as native WGPU
and text-provider diagnostics.
After configuring real Skia link flags, run the opt-in real Skia check to verify both the binding smoke and MoUI renderer presenter pixels:
scripts/macos-skia-renderer-smoke.shOn macOS, the helper below resolves the pinned JetBrains Skia binary provider,
temporarily wires the resulting include/library paths into moui_skia, the MoUI
renderer smoke, Showcase, Markdown Editor, and Mo Workbench macos_skia
packages, then runs the renderer pixel smoke and builds the Showcase entrypoint:
scripts/macos-skia-renderer-smoke.shPass --enable-skshaper when the selected Skia binary also provides the
SkShaper module libraries; the helper then verifies the MoUI renderer smoke ran
with the optional shaped-run path available.
Direct local moon run commands use the moui_skia prebuild hook, so the
checked-in packages do not need machine-local path rewrites. Set
MOUI_SKIA_LINK_MODE=dynamic|static|auto before moon run to choose the Skia
library mode. Helper smoke runs can still use --link-mode dynamic|static|auto
to override the environment for that invocation. HarmonyOS is stricter:
auto / skia-gpu must resolve to static, while dynamic is supported only for
explicit skia-raster.
For a fuller local smoke, pass --run-showcase-smoke. The helper builds
Showcase and then runs the moui_tester first-frame smoke. Add
--run-markdown-smoke to build Markdown Editor and run the same tester-owned
first-frame marker:
scripts/macos-skia-renderer-smoke.sh --run-showcase-smoke
scripts/macos-skia-renderer-smoke.sh --run-showcase-smoke --run-markdown-smokeUse --skia-provider existing when you already have a local Skia build:
scripts/macos-skia-renderer-smoke.sh \
--skia-provider existing \
--skia-include /path/to/skia \
--skia-lib-dir /path/to/skia/out/StaticRun the generated executable under _build/native/debug/build/... for the
example you built. If moon run exposes linker issues, use the build-and-execute
flow described in platform-notes.md.
To wrap an example as a local .app bundle:
sh scripts/package-macos-app.sh \
--package examples/showcase/macos_skia \
--name "MoUI Showcase" \
--bundle-id dev.wzzc.moui.showcase \
--version 0.1.0The bundle includes and validates a schema version 1
Contents/Resources/moui-package.json manifest so local packaging output can be
inspected without parsing Info.plist.
Windows native examples use the MSVC toolchain and vcpkg zlib:x64-windows.
The recommended native entrypoints import backend/windows/skia through the
_skia packages and select the native Skia raster provider explicitly.
windows_wgpu and windows_wgpu_cosmic packages remain available as native WGPU
diagnostics; the build/package helpers download and bundle wgpu_native.dll
only for those WGPU packages.
winget install --id Microsoft.VisualStudio.2022.BuildTools -e
powershell -ExecutionPolicy Bypass -File .\scripts\windows\setup_msvc_deps.ps1 -InstallZlib
powershell -ExecutionPolicy Bypass -File .\scripts\windows\build_windows_msvc.ps1 `
-Package examples/showcase/windows_skia `
-BuildOnly
powershell -ExecutionPolicy Bypass -File .\scripts\windows\build_windows_msvc.ps1 `
-Package examples/markdown_editor/windows_skia `
-BuildOnlyTo run an entrypoint directly, import the MSVC environment in the same PowerShell process:
powershell -ExecutionPolicy Bypass -Command "& { . .\scripts\windows\msvc_env.ps1; moon run examples/showcase/windows_skia --target native }"
powershell -ExecutionPolicy Bypass -Command "& { . .\scripts\windows\msvc_env.ps1; moon run examples/markdown_editor/windows_skia --target native }"windows_skia follows the same Skia availability rules as the backend provider:
if moui_skia/native is only in fallback mode, renderer creation reports a
diagnostic instead of opening an empty HWND.
Windows Skia example entrypoints are interactive app entrypoints. Keep
matching-host first-frame smoke in tester/backend smoke runners and cite the
smoke log that actually ran.
Markdown Editor also keeps examples/markdown_editor/windows_wgpu_cosmic for
explicit Moon Cosmic text-provider comparison on the native WGPU diagnostic
route.
For a reusable distributable folder with the built executable and runtime DLLs:
powershell -ExecutionPolicy Bypass -File .\scripts\windows\package_windows_app_msvc.ps1 `
-Package examples/showcase/windows_skia `
-AppName MoUIShowcase `
-Version 0.1.0The package is written under dist\windows-msvc\MoUIShowcase and includes a
schema version 1 moui-package.json, run.cmd, and the runtime DLLs needed by
the selected renderer. Skia packages omit wgpu_native.dll; WGPU diagnostic
packages include the WGPU release metadata and set MBT_WGPU_NATIVE_ROOT
through run.cmd.
Linux examples use the wzzc-dev/window@0.5.4-0.1.0 Wayland host core. The
recommended native entrypoints use backend/linux/skia and present Skia CPU
pixel frames through the Wayland wl_shm path. Run them on a configured Linux
host with a Wayland compositor and real Skia link flags:
moon run examples/showcase/linux_skia --target native
moon run examples/markdown_editor/linux_skia --target nativeLinux Skia example entrypoints are interactive app entrypoints. Keep matching-host first-frame smoke in tester/backend smoke runners and keep those logs separate from the window package dependency smoke logs.
For build-only validation, use:
moon build examples/showcase/linux_skia --target native
moon build examples/markdown_editor/linux_skia --target nativeThe linux_wgpu and linux_wgpu_cosmic Showcase entrypoints remain available for
explicit native WGPU diagnostics. linux_wgpu_cosmic selects the shared Moon Cosmic
text provider explicitly, while the platform-default Linux WGPU entrypoint
composes the fontconfig provider scaffold with the same Cosmic fallback. The
Showcase and Markdown Editor linux_skia entrypoints select the native Skia
raster renderer explicitly; configure real Skia link flags before relying on
Skia-rendered pixels.
Use package-level tests for shared app logic and Web builds for browser entry points:
moon test examples/showcase/app --target native
moon test examples/counter/app --target native
moon test examples/settings/app --target native
moon test examples/data_table/app --target native
moon test examples/excel/cell --target native
moon test examples/excel/formula --target native
moon test examples/excel/sheet --target native
moon test examples/excel/xlsx --target native
moon test examples/excel/app --target native
moon test examples/file_importer/app --target native
moon test examples/pdf_workbench/app --target native
moon test examples/pdf_workbench/pdflite_service_protocol --target native
moon test examples/pdf_workbench/pdflite_adapter --target native
moon test examples/pdf_workbench/pdfium_adapter --target native
moon test examples/command_palette/app --target native
moon test examples/markdown_editor/app --target native
moon test examples/mo_desktop/app --target native
moon test website/app --target native
moon build examples/counter/web_wasm --target wasm-gc
moon build examples/showcase/web_wasm --target wasm-gc
moon build examples/markdown_editor/web_wasm --target wasm-gc
moon build examples/mo_desktop/web_wasm --target wasm-gc
moon build website/web_wasm --target wasm-gc
node scripts/web-bundle-size.mjs examples/counter/web_wasm --jsonBefore changing platform entrypoints, include the affected host package tests and current-platform example builds.