From d172a2facb82df71f1c2ba3bcd6ba766fa44bb89 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:09:34 -0700 Subject: [PATCH 1/5] docs: explain rendering pipeline and correct runtime ownership --- AGENTS.md | 28 ++++++ README.md | 46 +++++---- README.zh-CN.md | 33 ++++--- docs/architecture-walkthrough.md | 157 +++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 31 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/architecture-walkthrough.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..aaea8b7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# 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. Malformed or budget-exhausted input must fail as a whole. +- The current `kit-host` and `beauty-host` mount a `View` evaluated on the main + VM into `Splash.view`. Do not repeat historical claims that they must wait + for an `isolate: false` field or currently use `Splash::set_text`. +- 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. Record unavailable GPU/device checks + honestly. Do not label structural tests as visual acceptance. +- Keep English and Chinese README architecture/build claims consistent. Use + symbol/file links and label historical observations and unrun recipes. diff --git a/README.md b/README.md index 0730375..1220194 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ Themed, cross-platform **component kits** for apps built on the **Octoscript DSL 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. +For a source-by-source introduction and runnable examples, read the +[junior Rust code walkthrough](docs/architecture-walkthrough.md). Contributor +guidance is in [AGENTS.md](AGENTS.md). + ## The pipeline ``` @@ -15,10 +19,11 @@ Octoscript DSL ──► octoscript-render ──► UiNode tree ──► {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`). @@ -79,13 +84,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 +119,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 +137,14 @@ 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`; old upstream bring-up revisions are +not the build contract. The catalog's historical device observations above are +not a new device verification of this checkout. Run the portable tests and +native acceptance workflow for the revision you intend to ship. ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index bcf048e..457bdeb 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,6 +8,9 @@ 用纯数据形式的 Octoscript DSL 编写一次 UI:它在 makepad-script VM 中求值,被翻译成 makepad 自身的控件方言,并在运行时挂载为**真正的 makepad 原生控件**(支持设备上热重载)。本仓库既存放渲染管线,**也**存放基于这条管线的各套主题组件:目前是 Material 3,**iOS** 和 **liquid-glass** 在计划中。 +面向初级 Rust 开发者的[源码导读与运行步骤](docs/architecture-walkthrough.md) +说明 L0、设计稿、原生挂载、状态与 agent 的边界;贡献约定见 [AGENTS.md](AGENTS.md)。 + ## 渲染管线 ``` @@ -15,10 +18,11 @@ Octoscript DSL ──► octoscript-render ──► UiNode tree ──► {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`)。 @@ -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 应用的共享运行时 @@ -87,16 +95,13 @@ makepad 的原生控件(复选框、开关、单选、滑块、文本框)由 `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` 为准,不能用早期上游版本 +代替。上文的历史设备观察不代表本次文档修订重新验证了设备;发布前应运行便携 +测试和原生验收。运行目录使用 `cargo run -p kit-host --bin kit-host`;预览宿主还需 +`BEAUTY_REQUEST` JSON 文件提供 card/data 路径和视口尺寸,完整步骤见源码导读。 ## 许可证 diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md new file mode 100644 index 0000000..d13feeb --- /dev/null +++ b/docs/architecture-walkthrough.md @@ -0,0 +1,157 @@ +# Code walkthrough: from app source to native widgets + +This guide is for a Rust developer new to OctoSense. It describes framework +revision `8f103d0c650196d455cbcaa55b13911475121224`, also selected by the +OctoSense workspace inspected for this walkthrough. Read the consuming app's +lock before substituting a newer checkout. + +## What this repository runs + +OctoSense is a shell that hosts apps. Octos is the agent kernel. This repository +is the shared **UI renderer**. A rendered card does not acquire an AI agent, +network access, or an app database just because it renders here. Those services +come from the consuming host's adapters and grants. + +A native Rust application is compiled into a binary with Makepad widgets and +Rust event handlers. An OctoScript app supplies source/data to such a host; +the host evaluates it and mounts native widgets. Both end up on Makepad's UI +event loop. Neither requires one Tokio task per widget. + +There are distinct source paths: + +| Input | Entry point | Output | +| --- | --- | --- | +| Plain-data UI DSL, such as `{t:"text", text:"Hello"}` | `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` | +| Source-measured design | `octoscript_makepad::design::prepare` | Checked `UiNode`, preserving explicit geometry | +| `UiNode` | `to_makepad_ui`, `to_makepad_l0_ui`, or `design::to_makepad_ui` | Makepad widget source for a host to mount | + +These entry points are not interchangeable. `design::to_makepad_ui` preserves +measured geometry and validates semantic kit bindings; the themed translation +applies its own widget mapping. Native L0 kits choose the design path internally. + +## Read the code in this order + +1. [Workspace manifest](../Cargo.toml) and [runtime lock](../runtime.json): one + Makepad source set and one OctoScript L0 revision. The sibling patches are + intentional. Two Makepad copies can produce incompatible Rust types and + separate VM heaps; matching package names alone does not make them one crate. +2. [Node model](../crates/octoscript-node/src/node.rs): `UiNode` contains a + `NodeKind`, optional `Attrs`, and child nodes. This crate has no dependencies. + It is the portable data boundary; it is not a window or a running agent. +3. [Evaluator](../crates/octoscript-render/src/eval.rs): `build` creates a fresh + `ScriptVm`, lets the host register capabilities, installs pure L0 helpers, + calls `eval_checked` with an instruction budget, and walks the returned + object into the tree. Unknown tags, bad children and exhausted depth/node + budgets fail the whole build (`None`). It uses Makepad's script VM, not an + implicit Octos agent turn. State must be supplied again by the host on a + later evaluation; arbitrary VM globals do not survive a fresh `build`. +4. [L0 preparation](../crates/octoscript-makepad/src/l0.rs): + `realize_with_state` checks the card against data/state, then `complete_root` + refuses incomplete output. Native kit components load `native//kit.json` + and use `kit_pack::lower` plus `design::prepare`. The other path loads the + palette, ordered theme axes, derivation helpers and `_kit.octoscript`, then + evaluates the lowered source. Missing capabilities do not become fabricated + fixture data. `PreparedCard.native_components` tells the host which renderer + to use. +5. [Translation](../crates/octoscript-makepad/src/lib.rs) and + [design translation](../crates/octoscript-makepad/src/design.rs): the output + is source text describing native Makepad widgets, not HTML. Translation + alone does not create a window. `to_makepad_l0_ui_with_events` provides a + host-selected event channel; the host is responsible for handling events, + updating state/data, and deciding when to render again. +6. [Native themes](../crates/octoscript-widgets/src/lib.rs): compiled + `script_mod!` modules register themed widgets and their shaders. This is why + replacing a runtime string is not equivalent to compiling a shader variant. +7. [Catalog host](../apps/kit-host/src/main.rs): `App::mount` builds source from + the route and Rust-held state, evaluates it, translates the tree, evaluates + the widget source on the app's **main VM** with `cx.with_vm`, and assigns the + resulting `View` to `Splash.view`. `handle_actions`/`handle_event` turn UI + actions into updates and remounts. Follow one button through those methods. +8. [Preview host](../apps/kit-host/src/beauty.rs): `mount_request` reads the + `BEAUTY_REQUEST` JSON file, prepares a design or L0 card, assigns inspectable + IDs, builds a `View` using checked evaluation on the main VM, and replaces + `Splash.view`. It retains the old view through replacement drawing, retires + overlays/WebViews, and restores requested focus/selection/scroll state. + +The last two paths do **not** call `Splash::set_text()` for their current +mount. That API's isolate behavior explains old bring-up notes, but not these +hosts' current VM ownership. A Splash widget is a mounting container here. +Other consumers must be checked independently. + +## Run the framework examples + +Commands below are source-derived recipes, not a record of a GUI/device run. +Run them from this repository. Install Rust/Cargo and platform-native Makepad +build prerequisites first. Dependency preparation needs Git/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 +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. A device-pushed +route/source file takes precedence over the desktop environment fallback; see +`current_route` and `current_source` if a route seems ignored. Flutter samples +are a visual catalog with documented limitations, not evidence that every +Flutter platform integration has been implemented. + +For a measured design/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`/`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 real card/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` is for automated native GPU checks, not proof of a +portable headless renderer. This documentation pass did not run a GPU preview. + +Android requires Makepad's Android toolchain and a device/emulator; the sample +command is `cargo makepad android run -p flutter-samples --release`. +The actual OctoSense desktop/home/ROM packages are built in the OctoSense and +ROM repositories, not by `kit-host`. Launching this catalog will not install an +app into App Hub or create an app peer. + +## 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/capabilities into evaluation. For production app stores and +peer routing, continue with the +[OctoSense walkthrough](https://github.com/OctoSense-org/OctoSense/blob/main/docs/architecture-walkthrough.md). + +Do not do blocking network requests or model inference in a Makepad event +handler. A host should schedule that work outside the UI thread and send a +completion back to update state and redraw. This renderer itself supplies no +Tokio agent scheduler. Its synchronous checked evaluation and host callbacks +must remain bounded regardless of what asynchronous runtime the app uses. + +## 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/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. From 5c05e1a20fc0b92a6a211d3cd512eaf256040706 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:55:32 -0700 Subject: [PATCH 2/5] docs: address architecture review and clarify runtime boundaries --- AGENTS.md | 16 ++-- README.md | 20 +++-- README.zh-CN.md | 25 ++++--- apps/kit-host/src/main.rs | 9 +-- docs/architecture-walkthrough.md | 124 ++++++++++++++++--------------- 5 files changed, 99 insertions(+), 95 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index aaea8b7..809a21f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# Working in Octoscript-Makepad +# Working in OctoScript-Makepad Read [README.md](README.md) and the [code walkthrough](docs/architecture-walkthrough.md) before changing the runtime. @@ -12,17 +12,19 @@ Read [README.md](README.md) and the - `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. Malformed or budget-exhausted input must fail as a whole. + 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`. Do not repeat historical claims that they must wait - for an `isolate: false` field or currently use `Splash::set_text`. + 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. Record unavailable GPU/device checks - honestly. Do not label structural tests as visual acceptance. + 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 - symbol/file links and label historical observations and unrun recipes. + source links and keep operational instructions separate from PR validation notes. diff --git a/README.md b/README.md index 1220194..ef082db 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -# 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. For a source-by-source introduction and runnable examples, read the -[junior Rust code walkthrough](docs/architecture-walkthrough.md). Contributor +[code walkthrough](docs/architecture-walkthrough.md). 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) │ ▼ @@ -23,7 +23,7 @@ Octoscript DSL ──► octoscript-render ──► UiNode tree ──► ``` - **`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-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`). @@ -73,7 +73,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 | |---|---| @@ -141,10 +141,8 @@ checks the portable render pipeline and component contracts. 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`; old upstream bring-up revisions are -not the build contract. The catalog's historical device observations above are -not a new device verification of this checkout. Run the portable tests and -native acceptance workflow for the revision you intend to ship. +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 457bdeb..c7763d4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,20 +1,20 @@ -# 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** 在计划中。 -面向初级 Rust 开发者的[源码导读与运行步骤](docs/architecture-walkthrough.md) +[源码导读与运行步骤](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) │ ▼ @@ -22,7 +22,7 @@ Octoscript DSL ──► octoscript-render ──► UiNode tree ──► ``` - **`crates/octoscript-node`**:无依赖的 `UiNode`/`Attrs` 数据模型,供各渲染后端共享。 -- **`crates/octoscript-render`**:与后端无关的核心。在 makepad-script VM 中对 Octoscript DSL 求值,并遍历生成 `UiNode` 树。依赖 `makepad-script`、便携节点模型与 `serde_json`,不依赖 platform/draw/widgets;有单元测试。 +- **`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`)。 @@ -58,7 +58,7 @@ tools/visual-qa.sh # screenshot all 108 on the device ## 无需 fork 的主题化(关键设计点) -makepad 的原生控件(复选框、开关、单选、滑块、文本框)由它们各自的 MPSL 着色器绘制;它们的外观**无法**从 Octoscript DSL 触及。外部 crate **可以**触及,但只有一种方式可行: +makepad 的原生控件(复选框、开关、单选、滑块、文本框)由它们各自的 MPSL 着色器绘制;它们的外观**无法**从 OctoScript DSL 触及。外部 crate **可以**触及,但只有一种方式可行: | 机制 | 结果 | |---|---| @@ -89,7 +89,10 @@ 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 的内容、滚动范围、快照和生命周期,供应用验收检查使用。 @@ -98,10 +101,8 @@ makepad 的原生控件(复选框、开关、单选、滑块、文本框)由 ## 状态与验证范围 源码包含有执行预算的求值器、主题与设计稿翻译器、Material 控件、L0 原生套件、 -图表以及原生目录/预览宿主。当前依赖以 `runtime.json` 为准,不能用早期上游版本 -代替。上文的历史设备观察不代表本次文档修订重新验证了设备;发布前应运行便携 -测试和原生验收。运行目录使用 `cargo run -p kit-host --bin kit-host`;预览宿主还需 -`BEAUTY_REQUEST` JSON 文件提供 card/data 路径和视口尺寸,完整步骤见源码导读。 +图表以及原生目录/预览宿主。当前依赖以 [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 index d13feeb..221addf 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -1,21 +1,19 @@ # Code walkthrough: from app source to native widgets -This guide is for a Rust developer new to OctoSense. It describes framework -revision `8f103d0c650196d455cbcaa55b13911475121224`, also selected by the -OctoSense workspace inspected for this walkthrough. Read the consuming app's -lock before substituting a newer checkout. +[runtime.json](../runtime.json) selects Makepad and OctoScript revisions; +[Cargo.toml](../Cargo.toml) declares the crates and sibling overrides. Check the +consuming app's runtime lock before changing its framework checkout. ## What this repository runs OctoSense is a shell that hosts apps. Octos is the agent kernel. This repository -is the shared **UI renderer**. A rendered card does not acquire an AI agent, -network access, or an app database just because it renders here. Those services -come from the consuming host's adapters and grants. +is the shared UI renderer. Agents, network access and storage come from the +host's adapters and grants. A native Rust application is compiled into a binary with Makepad widgets and -Rust event handlers. An OctoScript app supplies source/data to such a host; +Rust event handlers. An OctoScript app supplies source and data to such a host; the host evaluates it and mounts native widgets. Both end up on Makepad's UI -event loop. Neither requires one Tokio task per widget. +event loop. There are distinct source paths: @@ -26,7 +24,7 @@ There are distinct source paths: | Source-measured design | `octoscript_makepad::design::prepare` | Checked `UiNode`, preserving explicit geometry | | `UiNode` | `to_makepad_ui`, `to_makepad_l0_ui`, or `design::to_makepad_ui` | Makepad widget source for a host to mount | -These entry points are not interchangeable. `design::to_makepad_ui` preserves +`design::to_makepad_ui` preserves measured geometry and validates semantic kit bindings; the themed translation applies its own widget mapping. Native L0 kits choose the design path internally. @@ -38,52 +36,62 @@ applies its own widget mapping. Native L0 kits choose the design path internally separate VM heaps; matching package names alone does not make them one crate. 2. [Node model](../crates/octoscript-node/src/node.rs): `UiNode` contains a `NodeKind`, optional `Attrs`, and child nodes. This crate has no dependencies. - It is the portable data boundary; it is not a window or a running agent. + It is the portable data boundary between backends. The same crate contains + [ai.rs](../crates/octoscript-node/src/ai.rs), which expands AI-authored text + marks; [state.rs](../crates/octoscript-node/src/state.rs), which provides + numeric widget state; and [units.rs](../crates/octoscript-node/src/units.rs), + which implements shared unit conversions. 3. [Evaluator](../crates/octoscript-render/src/eval.rs): `build` creates a fresh `ScriptVm`, lets the host register capabilities, installs pure L0 helpers, calls `eval_checked` with an instruction budget, and walks the returned object into the tree. Unknown tags, bad children and exhausted depth/node - budgets fail the whole build (`None`). It uses Makepad's script VM, not an - implicit Octos agent turn. State must be supplied again by the host on a - later evaluation; arbitrary VM globals do not survive a fresh `build`. + budgets fail the whole build (`None`). The limits come from `octoscript_node`: + 2,000,000 evaluation instructions, depth 128 and 65,536 nodes. The host + supplies state on each evaluation because `build` creates a fresh VM. 4. [L0 preparation](../crates/octoscript-makepad/src/l0.rs): - `realize_with_state` checks the card against data/state, then `complete_root` + `realize_with_state` checks the card against data and state, then `complete_root` refuses incomplete output. Native kit components load `native//kit.json` and use `kit_pack::lower` plus `design::prepare`. The other path loads the palette, ordered theme axes, derivation helpers and `_kit.octoscript`, then - evaluates the lowered source. Missing capabilities do not become fabricated - fixture data. `PreparedCard.native_components` tells the host which renderer - to use. + evaluates the lowered source with explicit host data. `PreparedCard.native_components` tells the host which renderer + 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); + use this workspace's runtime lock to select its source revision. 5. [Translation](../crates/octoscript-makepad/src/lib.rs) and - [design translation](../crates/octoscript-makepad/src/design.rs): the output - is source text describing native Makepad widgets, not HTML. Translation - alone does not create a window. `to_makepad_l0_ui_with_events` provides a + [design translation](../crates/octoscript-makepad/src/design.rs): + `to_makepad_ui` and the L0 translation path clone the tree, run + `ai::expand_ai_marks` to place visible marks beside AI-authored text, resolve + ink contrast, then emit Makepad widget source. The AI-mark pass is + idempotent. The measured-design translator has its own emission path. + `to_makepad_l0_ui_with_events` provides a host-selected event channel; the host is responsible for handling events, - updating state/data, and deciding when to render again. + updating state and data, and deciding when to render again. 6. [Native themes](../crates/octoscript-widgets/src/lib.rs): compiled - `script_mod!` modules register themed widgets and their shaders. This is why - replacing a runtime string is not equivalent to compiling a shader variant. + `script_mod!` modules register themed widgets and their compiled shaders. + [makepad-d3](../crates/makepad-d3/README.md) and + [makepad-plot](../crates/makepad-plot/README.md) provide chart widgets, + registered under `mod.d3.*` and `mod.plot.*` on the same Makepad source set. 7. [Catalog host](../apps/kit-host/src/main.rs): `App::mount` builds source from the route and Rust-held state, evaluates it, translates the tree, evaluates the widget source on the app's **main VM** with `cx.with_vm`, and assigns the - resulting `View` to `Splash.view`. `handle_actions`/`handle_event` turn UI - actions into updates and remounts. Follow one button through those methods. + resulting `View` to `Splash.view`. `handle_actions` and `handle_event` turn UI + actions into updates and remounts. Its initial tree evaluation uses the + checked renderer, but final widget-source evaluation uses + `eval_with_append_source`, without an explicit instruction budget. 8. [Preview host](../apps/kit-host/src/beauty.rs): `mount_request` reads the `BEAUTY_REQUEST` JSON file, prepares a design or L0 card, assigns inspectable - IDs, builds a `View` using checked evaluation on the main VM, and replaces - `Splash.view`. It retains the old view through replacement drawing, retires - overlays/WebViews, and restores requested focus/selection/scroll state. + IDs, builds a `View` using `eval_checked(sm, 2_000_000)` on the main VM, + and replaces `Splash.view`. It retains the old view through replacement drawing, retires + overlays and WebViews, and restores focus, selection and scroll state. -The last two paths do **not** call `Splash::set_text()` for their current -mount. That API's isolate behavior explains old bring-up notes, but not these -hosts' current VM ownership. A Splash widget is a mounting container here. -Other consumers must be checked independently. +Both hosts use Splash as a container for a main-VM `View`; their mounting +paths differ in final evaluation budgets as described above. ## Run the framework examples -Commands below are source-derived recipes, not a record of a GUI/device run. -Run them from this repository. Install Rust/Cargo and platform-native Makepad -build prerequisites first. Dependency preparation needs Git/network access. +Run from this repository after installing Rust, Cargo and Makepad's native +build prerequisites. Dependency preparation uses Git and network access. ```sh python3 tools/runtime.py prepare @@ -94,13 +102,16 @@ 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. A device-pushed -route/source file takes precedence over the desktop environment fallback; see -`current_route` and `current_source` if a route seems ignored. Flutter samples -are a visual catalog with documented limitations, not evidence that every -Flutter platform integration has been implemented. +`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/L0 acceptance run: +For a measured design or L0 acceptance run: ```sh cargo build --release -p kit-host --bin beauty-host @@ -109,43 +120,38 @@ 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`/`actions` paths collect measurements +`"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 real card/kit inputs from the +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` is for automated native GPU checks, not proof of a -portable headless renderer. This documentation pass did not run a GPU preview. +`MAKEPAD_HIDE_WINDOWS=1` hides windows during automated native GPU checks. -Android requires Makepad's Android toolchain and a device/emulator; the sample +Android requires Makepad's Android toolchain and a device or emulator; the sample command is `cargo makepad android run -p flutter-samples --release`. -The actual OctoSense desktop/home/ROM packages are built in the OctoSense and -ROM repositories, not by `kit-host`. Launching this catalog will not install an -app into App Hub or create an app peer. +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 +`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/capabilities into evaluation. For production app stores and +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/main/docs/architecture-walkthrough.md). +[OctoSense walkthrough](https://github.com/OctoSense-org/OctoSense/blob/docs/junior-architecture-walkthrough/docs/architecture-walkthrough.md). -Do not do blocking network requests or model inference in a Makepad event -handler. A host should schedule that work outside the UI thread and send a -completion back to update state and redraw. This renderer itself supplies no -Tokio agent scheduler. Its synchronous checked evaluation and host callbacks -must remain bounded regardless of what asynchronous runtime the app uses. +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/screenshots. Common starting points: +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. From beb76353b33e89ae61caf585c930804403a4de10 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:59:48 -0700 Subject: [PATCH 3/5] docs: keep companion walkthrough links stable after merge --- docs/architecture-walkthrough.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md index 221addf..0bce33b 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -140,7 +140,7 @@ 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/docs/junior-architecture-walkthrough/docs/architecture-walkthrough.md). +[OctoSense walkthrough](https://github.com/OctoSense-org/OctoSense/blob/c3011a2057ec59738b79466f48ff2ad8d0e60130/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 From fb29b6b1cb6e16f38d99a8aef60431a9565dfd59 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:36:37 -0700 Subject: [PATCH 4/5] docs: clarify walkthroughs for junior Rust readers --- README.md | 7 +- README.zh-CN.md | 4 +- docs/architecture-walkthrough.md | 223 ++++++++++++++++++++----------- 3 files changed, 153 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index ef082db..d28880b 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ Themed, cross-platform **component kits** for apps built on the **OctoScript DSL 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. -For a source-by-source introduction and runnable examples, read the -[code walkthrough](docs/architecture-walkthrough.md). Contributor -guidance is in [AGENTS.md](AGENTS.md). +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 diff --git a/README.zh-CN.md b/README.zh-CN.md index c7763d4..d40ca91 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,8 +8,8 @@ 用纯数据形式的 OctoScript DSL 编写一次 UI:它在 makepad-script VM 中求值,被翻译成 makepad 自身的控件方言,并在运行时挂载为**真正的 makepad 原生控件**(支持设备上热重载)。本仓库既存放渲染管线,**也**存放基于这条管线的各套主题组件:目前是 Material 3,**iOS** 和 **liquid-glass** 在计划中。 -[源码导读与运行步骤](docs/architecture-walkthrough.md) -说明 L0、设计稿、原生挂载、状态与 agent 的边界;贡献约定见 [AGENTS.md](AGENTS.md)。 +[源码导读与运行步骤](docs/architecture-walkthrough.md)先用一个文本标签说明源码如何变成原生控件, +再介绍 L0 卡片、预览命令、状态与 agent 的边界。贡献约定见 [AGENTS.md](AGENTS.md)。 ## 渲染管线 diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md index 0bce33b..2bc85bf 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -1,102 +1,173 @@ # Code walkthrough: from app source to native widgets -[runtime.json](../runtime.json) selects Makepad and OctoScript revisions; -[Cargo.toml](../Cargo.toml) declares the crates and sibling overrides. Check the -consuming app's runtime lock before changing its framework checkout. +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 -OctoSense is a shell that hosts apps. Octos is the agent kernel. This repository -is the shared UI renderer. Agents, network access and storage come from the -host's adapters and grants. - 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 end up on Makepad's UI -event loop. +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 -There are distinct source paths: +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, such as `{t:"text", text:"Hello"}` | `octoscript_render::build` | Portable `UiNode` tree | +| 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` | -| Source-measured design | `octoscript_makepad::design::prepare` | Checked `UiNode`, preserving explicit geometry | +| 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 | -`design::to_makepad_ui` preserves -measured geometry and validates semantic kit bindings; the themed translation -applies its own widget mapping. Native L0 kits choose the design path internally. - -## Read the code in this order - -1. [Workspace manifest](../Cargo.toml) and [runtime lock](../runtime.json): one - Makepad source set and one OctoScript L0 revision. The sibling patches are - intentional. Two Makepad copies can produce incompatible Rust types and - separate VM heaps; matching package names alone does not make them one crate. -2. [Node model](../crates/octoscript-node/src/node.rs): `UiNode` contains a - `NodeKind`, optional `Attrs`, and child nodes. This crate has no dependencies. - It is the portable data boundary between backends. The same crate contains - [ai.rs](../crates/octoscript-node/src/ai.rs), which expands AI-authored text - marks; [state.rs](../crates/octoscript-node/src/state.rs), which provides - numeric widget state; and [units.rs](../crates/octoscript-node/src/units.rs), - which implements shared unit conversions. -3. [Evaluator](../crates/octoscript-render/src/eval.rs): `build` creates a fresh - `ScriptVm`, lets the host register capabilities, installs pure L0 helpers, - calls `eval_checked` with an instruction budget, and walks the returned - object into the tree. Unknown tags, bad children and exhausted depth/node - budgets fail the whole build (`None`). The limits come from `octoscript_node`: - 2,000,000 evaluation instructions, depth 128 and 65,536 nodes. The host - supplies state on each evaluation because `build` creates a fresh VM. -4. [L0 preparation](../crates/octoscript-makepad/src/l0.rs): - `realize_with_state` checks the card against data and state, then `complete_root` - refuses incomplete output. Native kit components load `native//kit.json` - and use `kit_pack::lower` plus `design::prepare`. The other path loads the - palette, ordered theme axes, derivation helpers and `_kit.octoscript`, then - evaluates the lowered source with explicit host data. `PreparedCard.native_components` tells the host which renderer - 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); - use this workspace's runtime lock to select its source revision. -5. [Translation](../crates/octoscript-makepad/src/lib.rs) and - [design translation](../crates/octoscript-makepad/src/design.rs): - `to_makepad_ui` and the L0 translation path clone the tree, run - `ai::expand_ai_marks` to place visible marks beside AI-authored text, resolve - ink contrast, then emit Makepad widget source. The AI-mark pass is - idempotent. The measured-design translator has its own emission path. - `to_makepad_l0_ui_with_events` provides a - host-selected event channel; the host is responsible for handling events, - updating state and data, and deciding when to render again. -6. [Native themes](../crates/octoscript-widgets/src/lib.rs): compiled - `script_mod!` modules register themed widgets and their compiled shaders. - [makepad-d3](../crates/makepad-d3/README.md) and - [makepad-plot](../crates/makepad-plot/README.md) provide chart widgets, - registered under `mod.d3.*` and `mod.plot.*` on the same Makepad source set. -7. [Catalog host](../apps/kit-host/src/main.rs): `App::mount` builds source from - the route and Rust-held state, evaluates it, translates the tree, evaluates - the widget source on the app's **main VM** with `cx.with_vm`, and assigns the - resulting `View` to `Splash.view`. `handle_actions` and `handle_event` turn UI - actions into updates and remounts. Its initial tree evaluation uses the - checked renderer, but final widget-source evaluation uses - `eval_with_append_source`, without an explicit instruction budget. -8. [Preview host](../apps/kit-host/src/beauty.rs): `mount_request` reads the - `BEAUTY_REQUEST` JSON file, prepares a design or L0 card, assigns inspectable - IDs, builds a `View` using `eval_checked(sm, 2_000_000)` on the main VM, - and replaces `Splash.view`. It retains the old view through replacement drawing, retires - overlays and WebViews, and restores focus, selection and scroll state. - -Both hosts use Splash as a container for a main-VM `View`; their mounting -paths differ in final evaluation budgets as described above. +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. Dependency preparation uses Git and network access. +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 From c23f964ce00ef8266a48613bc35c29625b72d0c4 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:40:38 -0700 Subject: [PATCH 5/5] docs: align final review corrections and companion links --- docs/architecture-walkthrough.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture-walkthrough.md b/docs/architecture-walkthrough.md index 2bc85bf..32a6a47 100644 --- a/docs/architecture-walkthrough.md +++ b/docs/architecture-walkthrough.md @@ -211,7 +211,7 @@ 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/c3011a2057ec59738b79466f48ff2ad8d0e60130/docs/architecture-walkthrough.md). +[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