diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..809a21f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ +# Working in OctoScript-Makepad + +Read [README.md](README.md) and the +[code walkthrough](docs/architecture-walkthrough.md) before changing the runtime. + +- This repository owns portable UI nodes, checked DSL evaluation, Makepad + translation, native themed widgets and preview/catalog hosts. App installation, + persistent app stores and system/app agents belong to consuming hosts. +- `runtime.json` and root `Cargo.toml` select the source set. Keep Makepad and + OctoScript pins consistent, preserve one Makepad instance per resolved graph, + and do not move a consumer's dependency pin as an incidental fix. +- `octoscript-node` deliberately has no dependencies. Keep its portable boundary + free of VM, platform and agent dependencies. +- Trace L0 realization, native kit lowering and measured-design translation + separately. Preserve whole-tree failure for malformed or budget-exhausted + input in `octoscript_render::build`. The final widget-source evaluation uses + `eval_checked` in beauty-host, but `eval_with_append_source` in kit-host; + keep their budget descriptions distinct. +- The current `kit-host` and `beauty-host` mount a `View` evaluated on the main + VM into `Splash.view`. +- Keep UI state, app persistence and agent memory distinct in code and docs. + Capabilities exist only when a host supplies them. A preview is not a + production app service or an agent permission grant. +- For render changes run appropriate portable tests, normally + `cargo test --release -p octoscript-node -p octoscript-render -p octoscript-makepad`. + Widget/layout changes also need native acceptance with `beauty-host --remote`; + use actual measurements and screenshots. If you could not run the native + check, say so in the PR. +- Keep English and Chinese README architecture/build claims consistent. Use + source links and keep operational instructions separate from PR validation notes. diff --git a/README.md b/README.md index 0730375..d28880b 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,30 @@ -# Octoscript-Makepad +# OctoScript-Makepad English | [简体中文](README.zh-CN.md) > **Building an OctoSense app?** You do not need to work in this repository. It is the shared UI runtime every OctoSense shell and `card-host` build against; `tools/setup-native.py` in OctoScript-App-Design-Flow checks it out for you as the sibling `octoscript-makepad/` at the pinned revision. Start from the [OctoSense organization profile](https://github.com/OctoSense-org)'s reading order: [OctoScript-App-Design-Flow `AGENTS.md`](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/AGENTS.md) → [`flows/README.md`](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/flows/README.md) → [`docs/QUICKSTART.md`](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/QUICKSTART.md). -Themed, cross-platform **component kits** for apps built on the **Octoscript DSL → makepad native-widget** renderer. +Themed, cross-platform **component kits** for apps built on the **OctoScript DSL → makepad native-widget** renderer. -Author a UI once as plain-data Octoscript DSL; it is evaluated in the makepad-script VM, translated to makepad's own widget dialect, and mounted as **real native makepad widgets** at runtime (with on-device hot reload). This repo is the home for the render pipeline **and** the themed component sets that ride on it — Material 3 today; **iOS** and **liquid-glass** planned. +Author a UI once as plain-data OctoScript DSL; it is evaluated in the makepad-script VM, translated to makepad's own widget dialect, and mounted as **real native makepad widgets** at runtime (with on-device hot reload). This repo is the home for the render pipeline **and** the themed component sets that ride on it — Material 3 today; **iOS** and **liquid-glass** planned. + +Follow a text label from source to native widgets in the +[code walkthrough](docs/architecture-walkthrough.md), then explore L0 cards, +preview commands, state and agent boundaries. Contributor guidance is in +[AGENTS.md](AGENTS.md). ## The pipeline ``` -Octoscript DSL ──► octoscript-render ──► UiNode tree ──► octoscript-makepad ──► makepad dialect string +OctoScript DSL ──► octoscript-render ──► UiNode tree ──► octoscript-makepad ──► makepad dialect string {t:"column", (makepad-script VM, (backend- (pure translation) View{…}/Label{…}/… c:[ … ]} renderer-free) agnostic) │ ▼ - makepad `Splash` widget .set_text() → live native widgets + host main VM → View → Splash.view → live native widgets ``` -- **`crates/octoscript-render`** — backend-agnostic core: evaluates the Octoscript DSL in the makepad-script VM and walks it into a `UiNode` tree. Depends only on `makepad-script`. Unit-tested. +- **`crates/octoscript-node`** — dependency-free `UiNode`/`Attrs` model shared by render backends. +- **`crates/octoscript-render`** — backend-agnostic core: evaluates the OctoScript DSL in the makepad-script VM and walks it into a `UiNode` tree. Depends on `makepad-script`, the portable node model and `serde_json`; it has no platform/draw/widgets dependency. Unit-tested. - **`crates/octoscript-makepad`** — the makepad backend: `to_makepad_ui(&UiNode) -> String` turns the tree into makepad's `View{}/Label{}/…` dialect. Pure, unit-tested — no makepad-platform/draw needed to build or test. - **`crates/octoscript-widgets`** — the **themed native-widget kits** (Material 3 now; iOS / liquid-glass later), as **external `script_mod!` variants of makepad's widgets** (see *Fork-free theming* below). - **`crates/makepad-d3`** — the **d3 grammar as native widgets** (scales, shapes, layouts, hierarchies, geo, 3D), registered into the VM under `mod.d3.*`. Grafted in with its history 2026-08-09 (was `mofa-org/makepad-d3`). @@ -68,7 +74,7 @@ because the `Splash` isolate resolves `ui` against its own view root, the ## Fork-free theming (the key design point) -makepad's native controls — checkbox, switch, radio, slider, text field — are drawn by their own MPSL shaders; their look is **not** reachable from the Octoscript DSL. It **is** reachable from an external crate, but only one way works: +makepad's native controls — checkbox, switch, radio, slider, text field — are drawn by their own MPSL shaders; their look is **not** reachable from the OctoScript DSL. It **is** reachable from an external crate, but only one way works: | Mechanism | Result | |---|---| @@ -79,13 +85,18 @@ The `script_mod!` macro compiles the MPSL at build time; a runtime string never Each new theme is just more variants in `octoscript-widgets` + a `.octoscript` component library — no makepad fork per theme. -### The one upstream PR +### Current mount ownership -Building + running the `kit-host` against upstream surfaced exactly **one** thing upstream doesn't have: a **`Splash` main-VM-mount option**. Upstream's `Splash` always allocates an *isolate* VM (`alloc_splash_vm_with_network(allow_net)`), but the light theme and a shared heap live on the app's **main** VM. The fix is the small `isolate: false` field this project's fork added to `widgets/src/splash.rs` — upstreaming it lets a trusted, app-generated kit mount on the main VM (correct theme, no isolate-heap animator panics). Until then the kit mounts on an isolate (dark-default theme). That is the *only* upstream change needed; everything else runs against upstream `dev` as-is. +`kit-host::App::mount` and `beauty-host::App::mount_request` evaluate the generated +widget source on the host's **main VM** using `cx.with_vm`, construct a `View`, +and assign it to `Splash.view`. This keeps registered fonts and themed widgets +in the same VM. They do not currently mount through `Splash::set_text`. -These notes date from the `kit-host` bring-up. The workspace now builds against the -`OctoSense-org/makepad` revision locked in `runtime.json` (`e29a0eaa`); that `Splash` has -no `isolate` field, so the kit mounts on an isolate. +Older bring-up notes described an isolate mount and a proposed `isolate: false` +field. The pinned Makepad has no such field, but these hosts no longer depend +on that proposal: the current main-VM mount is implemented in the hosts. See +[the walkthrough](docs/architecture-walkthrough.md) before copying an older +mount recipe. Other consumers can choose a different mount path. ## Shared runtime for OctoSense apps @@ -109,7 +120,11 @@ resolved Cargo graph. ### Native application validation -Build `cargo build --release -p kit-host --bin beauty-host` from this workspace. +Prepare and verify the pinned siblings as described above. To open the catalog, +run `cargo run -p kit-host --bin kit-host`. For a preview, build +`cargo build --release -p kit-host --bin beauty-host` from this workspace. +Set `BEAUTY_REQUEST` to a request JSON file containing card/data paths and +viewport dimensions; see the [complete recipe](docs/architecture-walkthrough.md). Launch the standalone host with `--remote`; automation sets `MAKEPAD_HIDE_WINDOWS=1` and uses the built-in HTTP instrument on the native GPU backend. Use `/snap`, input routes and `/g` to inspect the owned application; @@ -123,16 +138,12 @@ extent, snapshot and lifecycle for application acceptance checks. `cargo test --release -p octoscript-node -p octoscript-render -p octoscript-makepad` checks the portable render pipeline and component contracts. -## Status - -Status as of the `kit-host` bring-up; "upstream" below means upstream Makepad at that time. Today every crate here builds against the revisions in `runtime.json`. +## Status and validation scope -- ✅ `octoscript-render` + `octoscript-makepad` — portable render pipeline; **compile + test against upstream `makepad-script`** (rev `e1c2164b`), no fork -- ✅ **Material 3 kit** — `components/material/catalog.octoscript`: ~35 components (buttons, FABs, cards, chips, nav bar/rail/drawer, app bars, dialog/menu/sheets as **real interactive overlays**, pickers, tabs, badges, toolbars), M3 tokens (colour, type scale + Medium weight, shape, elevation, surface tones), Font-Awesome monochrome icons, and real animation (circular spinner + shape-morph loading indicator) -- ✅ `octoscript-widgets` — Material 3 native-control variants (checkbox/switch/radio/slider/text field) + `LoadingMorph`, fork-free; **compiles against upstream `makepad-widgets`** -- ✅ **`apps/kit-host`** — generic app shell that **builds + runs against upstream makepad** (desktop, ~37 MB binary), fork-free, mounting the Material kit via `octoscript_widgets::widgets_mod` -- ⏳ **The one upstream PR:** the `Splash` main-VM-mount option (see above) — the single change needed for correct light-theme rendering -- ⏳ **Next:** that PR (or an isolate-VM theme/heap fix so the mount works isolated); Android build via `cargo-makepad`; Button **touch-ripple** as a `RippleButton` variant; **iOS** + **liquid-glass** kits +The source includes checked evaluation, themed and measured-design translation, +Material widgets, L0 native kits, chart widgets, and native catalog/preview +hosts. Current pins are in [runtime.json](runtime.json). Device results above +predate the current pins; rerun portable tests and native acceptance before shipping. ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index bcf048e..d40ca91 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,24 +1,28 @@ -# Octoscript-Makepad +# OctoScript-Makepad [English](README.md) | 简体中文 > **要开发 OctoSense 应用?** 你不需要在这个仓库里工作。它是所有 OctoSense 外壳和 `card-host` 共同依赖的 UI 运行时;OctoScript-App-Design-Flow 的 `tools/setup-native.py` 会按固定版本把它检出为同级目录 `octoscript-makepad/`。请按 [OctoSense 组织主页](https://github.com/OctoSense-org)给出的顺序阅读:[OctoScript-App-Design-Flow `AGENTS.md`](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/AGENTS.md) → [`flows/README.md`](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/flows/README.md) → [`docs/QUICKSTART.md`](https://github.com/OctoSense-org/OctoScript-App-Design-Flow/blob/main/docs/QUICKSTART.md)。 -面向 **Octoscript DSL → makepad 原生控件**渲染器所构建应用的主题化、跨平台**组件套件**。 +面向 **OctoScript DSL → makepad 原生控件**渲染器所构建应用的主题化、跨平台**组件套件**。 -用纯数据形式的 Octoscript DSL 编写一次 UI:它在 makepad-script VM 中求值,被翻译成 makepad 自身的控件方言,并在运行时挂载为**真正的 makepad 原生控件**(支持设备上热重载)。本仓库既存放渲染管线,**也**存放基于这条管线的各套主题组件:目前是 Material 3,**iOS** 和 **liquid-glass** 在计划中。 +用纯数据形式的 OctoScript DSL 编写一次 UI:它在 makepad-script VM 中求值,被翻译成 makepad 自身的控件方言,并在运行时挂载为**真正的 makepad 原生控件**(支持设备上热重载)。本仓库既存放渲染管线,**也**存放基于这条管线的各套主题组件:目前是 Material 3,**iOS** 和 **liquid-glass** 在计划中。 + +[源码导读与运行步骤](docs/architecture-walkthrough.md)先用一个文本标签说明源码如何变成原生控件, +再介绍 L0 卡片、预览命令、状态与 agent 的边界。贡献约定见 [AGENTS.md](AGENTS.md)。 ## 渲染管线 ``` -Octoscript DSL ──► octoscript-render ──► UiNode tree ──► octoscript-makepad ──► makepad dialect string +OctoScript DSL ──► octoscript-render ──► UiNode tree ──► octoscript-makepad ──► makepad dialect string {t:"column", (makepad-script VM, (backend- (pure translation) View{…}/Label{…}/… c:[ … ]} renderer-free) agnostic) │ ▼ - makepad `Splash` widget .set_text() → live native widgets + host main VM → View → Splash.view → live native widgets ``` -- **`crates/octoscript-render`**:与后端无关的核心。在 makepad-script VM 中对 Octoscript DSL 求值,并遍历生成 `UiNode` 树。只依赖 `makepad-script`,有单元测试。 +- **`crates/octoscript-node`**:无依赖的 `UiNode`/`Attrs` 数据模型,供各渲染后端共享。 +- **`crates/octoscript-render`**:与后端无关的核心。在 makepad-script VM 中对 OctoScript DSL 求值,并遍历生成 `UiNode` 树。依赖 `makepad-script`、便携节点模型与 `serde_json`,不依赖 platform/draw/widgets;有单元测试。 - **`crates/octoscript-makepad`**:makepad 后端。`to_makepad_ui(&UiNode) -> String` 把这棵树转换成 makepad 的 `View{}/Label{}/…` 方言。纯函数,有单元测试,构建和测试都不需要 makepad-platform/draw。 - **`crates/octoscript-widgets`**:**主题化原生控件套件**(目前是 Material 3,之后是 iOS / liquid-glass),以**外部 `script_mod!` 变体的形式扩展 makepad 控件**(见下文*无需 fork 的主题化*)。 - **`crates/makepad-d3`**:**以原生控件实现的 d3 语法**(比例尺、形状、布局、层级、地理、3D),在 VM 中注册到 `mod.d3.*` 下。于 2026-08-09 连同提交历史一起并入(原为 `mofa-org/makepad-d3`)。 @@ -54,7 +58,7 @@ tools/visual-qa.sh # screenshot all 108 on the device ## 无需 fork 的主题化(关键设计点) -makepad 的原生控件(复选框、开关、单选、滑块、文本框)由它们各自的 MPSL 着色器绘制;它们的外观**无法**从 Octoscript DSL 触及。外部 crate **可以**触及,但只有一种方式可行: +makepad 的原生控件(复选框、开关、单选、滑块、文本框)由它们各自的 MPSL 着色器绘制;它们的外观**无法**从 OctoScript DSL 触及。外部 crate **可以**触及,但只有一种方式可行: | 机制 | 结果 | |---|---| @@ -65,11 +69,15 @@ makepad 的原生控件(复选框、开关、单选、滑块、文本框)由 每个新主题只是在 `octoscript-widgets` 中多加一些变体,再加一个 `.octoscript` 组件库,不需要为每个主题 fork 一次 makepad。 -### 唯一一个上游 PR +### 当前的挂载方式 -基于上游构建并运行 `kit-host` 时,只暴露出**一处**上游缺少的东西:**`Splash` 在主 VM 上挂载的选项**。上游的 `Splash` 总是分配一个 *isolate* VM(`alloc_splash_vm_with_network(allow_net)`),但浅色主题和共享堆都位于应用的**主** VM 上。修复方法是本项目的 fork 在 `widgets/src/splash.rs` 中新增的一个小字段 `isolate: false`;把它合入上游后,受信任的、由应用生成的套件就能挂载到主 VM 上(主题正确,也不会出现 isolate 堆上的 animator panic)。在此之前,套件挂载在 isolate 上(默认深色主题)。这是*唯一*需要的上游改动;其他一切都可以直接基于上游 `dev` 运行。 +`kit-host::App::mount` 与 `beauty-host::App::mount_request` 通过 `cx.with_vm` +在宿主的**主 VM** 上求值生成的控件源码,构建 `View` 后赋给 `Splash.view`。 +字体与主题控件因此位于同一个 VM;这两个宿主当前不通过 `Splash::set_text` 挂载。 -以上记录来自 `kit-host` 初建时期。现在本工作区基于 `runtime.json` 锁定的 `OctoSense-org/makepad` 版本(`e29a0eaa`)构建;该版本的 `Splash` 没有 `isolate` 字段,所以套件挂载在 isolate 上。 +早期记录中的 isolate 挂载和拟议的 `isolate: false` 字段不是当前前提。 +锁定的 Makepad 没有该字段,但宿主已经自行实现主 VM 挂载。复制旧示例前请读 +[源码导读](docs/architecture-walkthrough.md);其他消费者仍需单独核对挂载路径。 ## OctoSense 应用的共享运行时 @@ -81,22 +89,20 @@ makepad 的原生控件(复选框、开关、单选、滑块、文本框)由 ### 原生应用验证 -在本工作区中运行 `cargo build --release -p kit-host --bin beauty-host` 进行构建。用 `--remote` 启动独立宿主;自动化流程会设置 `MAKEPAD_HIDE_WINDOWS=1`,并在原生 GPU 后端上使用内置的 HTTP 探测接口。用 `/snap`、输入路由和 `/g` 检查所控制的应用;最后调用 `/gq` 并确认进程已退出。Studio 不属于这个流程。 +先准备并验证上文的锁定依赖。运行组件目录使用 +`cargo run -p kit-host --bin kit-host`。预览宿主使用 +`cargo build --release -p kit-host --bin beauty-host` 构建,并设置 `BEAUTY_REQUEST` +指向包含 card/data 文件路径和视口尺寸的 JSON;完整步骤见[源码导读](docs/architecture-walkthrough.md)。用 `--remote` 启动独立宿主;自动化流程会设置 `MAKEPAD_HIDE_WINDOWS=1`,并在原生 GPU 后端上使用内置的 HTTP 探测接口。用 `/snap`、输入路由和 `/g` 检查所控制的应用;最后调用 `/gq` 并确认进程已退出。Studio 不属于这个流程。 宿主接受经过测量的 AppCard 设计和 L0 卡片,在重新挂载时保留文本选区和滚动状态,并在导航时回收平台 WebView。在 macOS 上,它的自定义事件探针会暴露所控制 WebView 的内容、滚动范围、快照和生命周期,供应用验收检查使用。 `cargo test --release -p octoscript-node -p octoscript-render -p octoscript-makepad` 检查可移植的渲染管线和组件契约。 -## 状态 - -以下状态记录于 `kit-host` 初建时期,其中的“上游”指当时的上游 Makepad。如今本仓库的所有 crate 都基于 `runtime.json` 中的版本构建。 +## 状态与验证范围 -- ✅ `octoscript-render` + `octoscript-makepad`:可移植渲染管线;**基于上游 `makepad-script` 编译并通过测试**(修订版本 `e1c2164b`),无 fork -- ✅ **Material 3 套件**:`components/material/catalog.octoscript`,约 35 个组件(按钮、FAB、卡片、纸片、导航栏/导航轨/抽屉、应用栏,以**真正可交互的浮层**实现的对话框/菜单/面板,选择器、标签页、徽标、工具栏),M3 设计令牌(颜色、字号体系 + Medium 字重、形状、海拔、表面色调),Font-Awesome 单色图标,以及真正的动画(环形加载指示器 + 形状变形加载指示器) -- ✅ `octoscript-widgets`:Material 3 原生控件变体(复选框/开关/单选/滑块/文本框)+ `LoadingMorph`,无需 fork;**基于上游 `makepad-widgets` 编译通过** -- ✅ **`apps/kit-host`**:通用应用外壳,**基于上游 makepad 构建并运行**(桌面端,约 37 MB 二进制),无需 fork,通过 `octoscript_widgets::widgets_mod` 挂载 Material 套件 -- ⏳ **唯一一个上游 PR:** `Splash` 主 VM 挂载选项(见上文),这是正确渲染浅色主题所需的唯一改动 -- ⏳ **下一步:** 提交该 PR(或者修复 isolate VM 的主题/堆问题,让隔离挂载也能正常工作);通过 `cargo-makepad` 构建 Android;以 `RippleButton` 变体实现按钮**触摸涟漪**;**iOS** + **liquid-glass** 套件 +源码包含有执行预算的求值器、主题与设计稿翻译器、Material 控件、L0 原生套件、 +图表以及原生目录/预览宿主。当前依赖以 [runtime.json](runtime.json) 为准。 +上文设备结果早于当前锁定版本;发布前请重新运行便携测试和原生验收。 ## 许可证 diff --git a/apps/kit-host/src/main.rs b/apps/kit-host/src/main.rs index 2fd211f..43aeacb 100644 --- a/apps/kit-host/src/main.rs +++ b/apps/kit-host/src/main.rs @@ -73,12 +73,9 @@ script_mod! { flow: Down show_bg: true draw_bg +: { color: #101417ff } - // Upstream `Splash` always allocates an isolate VM. The - // material kit needs the mount on the app's MAIN VM (light - // theme + shared heap live there), which requires the one - // upstream PR: a `Splash` main-VM-mount option (the - // `isolate: false` field this fork added). Until then the - // kit mounts on an isolate (dark-default theme). + // App::mount evaluates the widget source on the main VM + // and assigns the resulting View to this Splash container, + // keeping the registered fonts and theme on the same heap. host := Splash{ width: Fill, height: Fit } } // Routing signal the mounted kit writes; the app reads it each frame. diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md new file mode 100644 index 0000000..32a6a47 --- /dev/null +++ b/docs/architecture-walkthrough.md @@ -0,0 +1,234 @@ +# Code walkthrough: from app source to native widgets + +OctoSense is a shell that hosts apps. Octos runs their agents. This repository +turns UI descriptions into native Makepad widgets. Follow a small text label +through that process first, then use the later sections for L0 cards, previews +and application state. + +## What this repository runs + +A native Rust application is compiled into a binary with Makepad widgets and +Rust event handlers. An OctoScript app supplies source and data to such a host; +the host evaluates it and mounts native widgets. Both use Makepad's UI event +loop. Agents, network access and storage come from the host's adapters and grants. + +A **DSL** is a language designed for a particular task; here it describes a UI. +The plain-data DSL represents each element as an object with a tag (`t`), +attributes such as `text`, and optional children (`c`). A **VM**, or virtual +machine, evaluates that source. The renderer converts its result into ordinary +Rust data before a backend creates widget source. + + + +## Follow one label from source to screen + +This illustrative Rust fragment uses the public renderer APIs. It was checked +against the source and an existing test, but has not been executed here. It +needs no host capabilities: + +```rust +let source = r#"{t:"text", text:"Hello", h:28}"#; +let tree = octoscript_render::build(source, |_| {}).expect("valid UI source"); +assert_eq!(tree.kind, octoscript_node::NodeKind::Text); +assert_eq!(tree.attrs.text.as_deref(), Some("Hello")); +let widget_source = octoscript_makepad::to_makepad_ui(&tree); +``` + +1. **Evaluate the source.** In [eval.rs](../crates/octoscript-render/src/eval.rs), + `build` creates a fresh `ScriptVm` and evaluates the object. Its `walk_inner` + function reads `t` as the node kind, `text` as an attribute, and `h` as height. + The result is a `UiNode` with kind `Text`, text `Hello`, height `28` and no + children. The [node model](../crates/octoscript-node/src/node.rs) is portable + Rust data with no renderer dependency. +2. **Translate the tree.** In [lib.rs](../crates/octoscript-makepad/src/lib.rs), + `to_makepad_ui` clones the tree, expands marks for AI-authored text, resolves + text contrast, then emits widget source. `widget_name` maps `Text` to `Label`; + `emit_attrs` writes the text property. The `Label` portion is shown below; + surrounding layout and generated font properties are omitted: + + ```text + Label { + text: "Hello" + } + ``` + +3. **Mount the widgets.** The string still needs a native host. In the + [catalog host](../apps/kit-host/src/main.rs), `App::mount` evaluates generated + widget source on the app's **main VM** through `cx.with_vm`, then assigns the + resulting `View` to `Splash.view`. Splash is the container that displays it. + The earlier evaluation built a data tree; this evaluation creates the live UI. +4. **Handle the next action.** `handle_actions` and `handle_event` receive UI + actions, update Rust-held state and remount the UI when needed. The host + supplies the current values again because each `build` uses a fresh VM. + Rendering once does not subscribe the label to a database. + +For a larger version of this path, read `column_of_text_becomes_view_with_label` +in the [translator tests](../crates/octoscript-makepad/src/lib.rs). It checks +that a styled column emits a `RoundedView` containing a `Label` and the +expected text. + +## Where L0 cards and measured designs enter + +An **L0 card** is a checked UI description that can refer to app data and +instance state. **Realization** checks those references against the supplied +values and produces a complete card tree. **Lowering** converts that tree into +the more detailed UI source needed by a rendering backend. A **kit** supplies +the component definitions and styling used during that conversion. + +| Input | Entry point | Output | +| --- | --- | --- | +| Plain-data UI DSL, as in the label above | `octoscript_render::build` | Portable `UiNode` tree | +| L0 card, data and optional instance state | `octoscript_makepad::l0::prepare_with_state` | Realized and lowered source plus `UiNode` | +| Design source with explicit positions and sizes | `octoscript_makepad::design::prepare` | Checked `UiNode`, preserving that geometry | +| `UiNode` | `to_makepad_ui`, `to_makepad_l0_ui`, or `design::to_makepad_ui` | Makepad widget source for a host to mount | + +In [l0.rs](../crates/octoscript-makepad/src/l0.rs), `prepare_with_state` calls +`realize_with_state`, then `complete_root` refuses incomplete output. Preparation +then takes one of two paths: + +- Native kit components load `native//kit.json`. `kit_pack::lower` produces + design source, and `design::prepare` builds its tree. +- Other components load the palette, theme choices such as radius and density + (the code calls these **theme axes**), helpers that derive style values, and + `_kit.octoscript`. The assembled source is then evaluated into a tree. + +`PreparedCard.native_components` tells the host which translator to use. +`realize_with_state`, `InstanceStore` and `kit_pack` belong to the external +`octoscript-ui-l0` crate in the +[OctoScript repository](https://github.com/OctoSense-org/Octoscript/tree/main/crates/octoscript-ui-l0). +This workspace's [runtime lock](../runtime.json) selects that crate's revision. + +The [design translator](../crates/octoscript-makepad/src/design.rs) preserves +explicit geometry. It also checks **semantic kit bindings**: mappings from a +component's role, such as an input field, to the actual child widget that fills +that role. For example, `kit_contract` requires an `input` binding to name a +native `TextInput`. This lets a styled component retain real input behavior. + +The regular and L0 translators both expand AI text marks before resolving +contrast and emitting source; expanding the marks again does not duplicate +them. The measured-design translator has its own emission path. For L0 events, +`to_makepad_l0_ui_with_events` embeds a host-selected event channel. The host +handles the events, updates data and state, and decides when to render again. + +## Runtime limits and native host details + +The two evaluation stages have separate limits: + +| Stage | Behavior | +| --- | --- | +| Source → `UiNode` through `build` | `eval_checked` allows 2,000,000 instructions. Tree walking allows depth 128 and 65,536 nodes. Evaluation errors, unknown tags, malformed children or exhausted limits fail the whole build with `None`. | +| Widget source → live UI in catalog `kit-host` | Uses `eval_with_append_source` on the main VM, without an explicit instruction budget. | +| Widget source → live UI in preview `beauty-host` | Uses `eval_checked(sm, 2_000_000)` on the main VM. | + +The [preview host](../apps/kit-host/src/beauty.rs) adds inspection and replacement +handling around the normal rendering steps. `mount_request` reads the +`BEAUTY_REQUEST` JSON file, prepares a design or L0 card, assigns inspectable IDs, +and replaces `Splash.view`. It retains the old view through replacement drawing, +retires overlays and WebViews, and restores focus, selection and scroll state. + +[Native themes](../crates/octoscript-widgets/src/lib.rs) register compiled widgets +and shaders through `script_mod!` modules. +[makepad-d3](../crates/makepad-d3/README.md) and +[makepad-plot](../crates/makepad-plot/README.md) add chart widgets under `mod.d3.*` +and `mod.plot.*`. The node crate also supplies +[AI text marks](../crates/octoscript-node/src/ai.rs), +[numeric widget state](../crates/octoscript-node/src/state.rs) and +[unit conversions](../crates/octoscript-node/src/units.rs). + +Keep the source set consistent when building a host. +[runtime.json](../runtime.json) selects Makepad and OctoScript revisions; +[Cargo.toml](../Cargo.toml) declares the crates and sibling overrides. Two +Makepad copies can create incompatible Rust types and separate VM heaps. +Check a consuming app's runtime lock before changing its framework checkout. + +## Run the framework examples + +The commands below are source-checked recipes. Their build, GUI and device +execution is **unverified** in this documentation pass. + +Run from this repository after installing Rust, Cargo and Makepad's native +build prerequisites. First prepare and check the dependencies; preparation uses +Git and network access. + +```sh +python3 tools/runtime.py prepare +python3 tools/runtime.py verify --cargo-manifest Cargo.toml +cargo test --release -p octoscript-node -p octoscript-render -p octoscript-makepad +``` + +To inspect generated widget source without opening a window, run the +[translate example](../crates/octoscript-makepad/examples/translate.rs). It uses +a built-in sample; append `-- /absolute/path/example.octoscript` to read your +own source instead. + +```sh +cargo run -p octoscript-makepad --example translate +``` + +Choose a native viewer below. Each command runs until you close that viewer: + +```sh +cargo run -p kit-host --bin kit-host +SPLASH_ROUTE=l0/weather cargo run -p kit-host --bin kit-host +cargo run -p flutter-samples +``` + +`kit-host` has two binaries; name `--bin kit-host` explicitly. In +[kit-host](../apps/kit-host/src/main.rs), `current_route` reads the device route +file, then `SPLASH_ROUTE`, then defaults to `button`. Its `current_source(&self)` +first accepts a device-pushed source file, then tries the in-app screen and +finally that route. The [Flutter host](../apps/flutter-samples/src/lib.rs) has +a separate `current_source()` selecting device-pushed source or its baked +catalog. See the [Flutter catalog limitations](../components/flutter/README.md) +for the scope of that port. + +For a measured design or L0 acceptance run: + +```sh +cargo build --release -p kit-host --bin beauty-host +BEAUTY_REQUEST=/absolute/path/request.json target/release/beauty-host --remote +``` + +`request.json` must supply `card` (source-file path), `data` (JSON-file path), +`width` and `height`. L0 input also needs `kit_dir`; measured design input uses +`"format": "design"`. Optional `layout` and `actions` paths collect measurements +and actions. Even a design request currently reads the data file, so provide +an existing JSON file (for example `{}`). Paths are read by the host process; +use absolute paths for reproducibility. Obtain card and kit inputs from the +[design flow](https://github.com/OctoSense-org/OctoScript-App-Design-Flow). +The native HTTP instrument is enabled by `--remote`; follow its emitted +connection information for `/snap`, `/g`, input routes and `/gq`. +`MAKEPAD_HIDE_WINDOWS=1` hides windows during automated native GPU checks. + +Android requires Makepad's Android toolchain and a device or emulator; the sample +command is `cargo makepad android run -p flutter-samples --release`. +OctoSense builds its desktop, Home and ROM packages in the OctoSense repository. + +## State, app data and agents are different things + +`octoscript_node::state` is a small widget-state helper, not the application's +persistent database. L0 `InstanceStore` supplies per-instance UI state. The +host owns app records, network services and agent integration, and passes +approved values and capabilities into evaluation. For production app stores and +peer routing, continue with the +[OctoSense walkthrough](https://github.com/OctoSense-org/OctoSense/blob/61c668279a7c38a0f8056134d8d29e42ed715806/docs/architecture-walkthrough.md). + +Schedule blocking network requests and model inference outside the Makepad UI +thread, then send completions back to update state and redraw. The consuming +host owns that scheduling and the cost of its synchronous evaluation callbacks. + +## Verification and debugging + +Portable tests exercise tree validity, evaluation budgets, lowering and emitted +widget contracts. They cannot prove font metrics, keyboard focus, WebView +lifecycle or touch behavior. For those, use the native preview and inspect its +measured layout, actions and screenshots. Common starting points: + +- `build` returns `None`: inspect the source, registered capabilities, unknown + tags and instruction/tree limits before changing the widget translator. +- A themed control is blank: check registration of compiled widgets and the VM + on which the final view was evaluated. +- A card shows old values: follow host event handling, state update and remount; + evaluating a source once does not subscribe it to a database. +- Cargo reports duplicate Makepad crates: repair the pinned sibling source set + and verify the resolved graph before editing type definitions.