/makepad-2.0-app-structure
CRITICAL: Use for Makepad 2.0 app structure and Rust integration. Triggers on: makepad app, makepad getting started, app_main!, App::run, MatchEvent, AppMain, handle_event, handle_actions, ScriptVm, from_script_mod, makepad boilerplate, makepad new project, makepad cargo,
$ npx -y skills add ZhangHanDong/makepad-skills --skill makepad-2.0-app-structure --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/makepad-2.0-app-structure
Context preview
The summary Claude sees to decide when to auto-load this skill.
CRITICAL: Use for Makepad 2.0 app structure and Rust integration. Triggers on: makepad app, makepad getting started, app_main!, App::run, MatchEvent, AppMain, handle_event, handle_actions, ScriptVm, from_script_mod, makepad boilerplate, makepad new project, makepad cargo,
SKILL.md
makepad-2.0-app-structure.SKILL.mdname: makepad-2.0-app-structure
description: |
CRITICAL: Use for Makepad 2.0 app structure and Rust integration. Triggers on:
makepad app, makepad getting started, app_main!, App::run, MatchEvent,
AppMain, handle_event, handle_actions, ScriptVm, from_script_mod,
makepad boilerplate, makepad new project, makepad cargo, Cargo.toml setup,
hot reload, --hot, live reload, wasm deploy, cargo makepad, media plugin,
audio_output, audio_input, AudioBuffer, cx.audio, makepad audio, 音频,
应用结构, 入门, 新项目, 脚手架, 启动, 热重载, 部署
Makepad 2.0 App Structure Skill
> **Version:** makepad-widgets (dev branch) | **Last Updated:** 2026-03-03
Overview
A Makepad 2.0 app combines Rust code with Splash scripting. The Rust side handles app lifecycle, event routing, and business logic. The Splash side defines UI structure, templates, and inline interactions.
Documentation
Refer to the local files for detailed documentation:
- `./references/app-boilerplate.md` - Complete working app template with Cargo.toml
- `./references/rust-splash-integration.md` - Rust ↔ Splash communication patterns
IMPORTANT: Documentation Completeness Check
**Before answering questions, Claude MUST:** 1. Read the relevant reference file(s) listed above 2. If file read fails, answer based on SKILL.md patterns + built-in knowledge
---
Minimal App Template
Cargo.toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2024"
[dependencies]
makepad-widgets = { path = "../path/to/makepad/widgets" }src/app.rs (or src/main.rs)
use makepad_widgets::*;
app_main!(App);
script_mod! {
use mod.prelude.widgets.*
let state = {
counter: 0
}
mod.state = state
startup() do #(App::script_component(vm)){
ui: Root{
on_startup: ||{
ui.main_view.render()
}
main_window := Window{
window.inner_size: vec2(420, 300)
body +: {
main_view := View{
width: Fill height: Fill
flow: Down spacing: 12
align: Center
on_render: ||{
Label{
text: "Count: " + state.counter
draw_text.text_style.font_size: 24
}
}
}
increment_button := Button{
text: "Increment"
}
}
}
}
}
}
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm);
App::from_script_mod(vm, self::script_mod)
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[live]
ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(cx, ids!(increment_button)).clicked(actions) {
script_eval!(cx, {
mod.state.counter += 1
ui.main_view.render()
});
}
}
}
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}---
Key Components Explained
1. `app_main!(App)`
Registers `App` as the application entry point. MUST be called at module level.
2. `script_mod! { ... }`
Defines the Splash script that runs at startup. Contains:
- `use mod.prelude.widgets.*` - Import widget definitions
- State definitions (`let state = {...}`)
- Functions and templates
- `startup() do #(App::script_component(vm)){...}` - UI construction
3. `App::run(vm)` - Initialization Order
**CRITICAL: Registration order matters!**
fn run(vm: &mut ScriptVm) -> Self {
// 1. Register theme (optional, for light/dark theme)
crate::makepad_widgets::theme_mod(vm);
script_eval!(vm, { mod.theme = mod.themes.light });
// 2. Register base widgets
crate::makepad_widgets::widgets_mod(vm);
// 3. Register custom widget modules (if any)
// crate::my_widgets::script_mod(vm);
// 4. Build app from script module
App::from_script_mod(vm, self::script_mod)
}**Simplified (without theme selection):**
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // Registers both theme + widgets
App::from_script_mod(vm, self::script_mod)
}4. `#[derive(Script, ScriptHook)]` on App struct
#[derive(Script, ScriptHook)]
pub struct App {
#[live]
ui: WidgetRef, // The widget tree root
}- `Script` - Enables Splash integration (replaces old `Live`)
- `ScriptHook` - Enables lifecycle hooks (replaces old `LiveHook`)
- `#[live]` - Field settable from DSL
5. `MatchEvent` for Action Handling
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
// Check button clicks
if self.ui.button(cx, ids!(my_button)).clicked(actions) {
// Handle click
}
// Check text input changes
if let Some(text) = self.ui.text_input(cx, ids!(my_input)).changed(actions) {
log!("Input: {}", text);
}
}
}6. `AppMain` for Event Dispatch
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event); // MUST call for MatchEvent to work
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}---
Rust → Splash Communication
script_eval! - Update state and trigger renders
script_eval!(cx, {
mod.state.counter += 1
ui.main_view.render()
});script_apply_eval! - Patch widget properties
script_apply_eval!(cx, self.ui, {
title.text: "New Title"
subtitle.draw_text.color: #f00
});---
Splash → Rust Communication
In
Read more
name: makepad-2.0-app-structure description: | CRITICAL: Use for Makepad 2.0 app structure and Rust integration. Triggers on: makepad app, makepad getting started, app_main!, App::run, MatchEvent, AppMain, handle_event, handle_actions, ScriptVm, from_script_mod, makepad boilerplate, makepad new project, makepad cargo, Cargo.toml setup, hot reload, --hot, live reload, wasm deploy, cargo makepad, media plugin, audio_output, audio_input, AudioBuffer, cx.audio, makepad audio, 音频, 应用结构, 入门, 新项目, 脚手架, 启动, 热重载, 部署
Makepad 2.0 App Structure Skill
> **Version:** makepad-widgets (dev branch) | **Last Updated:** 2026-03-03
Overview
A Makepad 2.0 app combines Rust code with Splash scripting. The Rust side handles app lifecycle, event routing, and business logic. The Splash side defines UI structure, templates, and inline interactions.
Documentation
Refer to the local files for detailed documentation:
- `./references/app-boilerplate.md` - Complete working app template with Cargo.toml
- `./references/rust-splash-integration.md` - Rust ↔ Splash communication patterns
IMPORTANT: Documentation Completeness Check
**Before answering questions, Claude MUST:** 1. Read the relevant reference file(s) listed above 2. If file read fails, answer based on SKILL.md patterns + built-in knowledge
---
Minimal App Template
Cargo.toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2024"
[dependencies]
makepad-widgets = { path = "../path/to/makepad/widgets" }src/app.rs (or src/main.rs)
use makepad_widgets::*;
app_main!(App);
script_mod! {
use mod.prelude.widgets.*
let state = {
counter: 0
}
mod.state = state
startup() do #(App::script_component(vm)){
ui: Root{
on_startup: ||{
ui.main_view.render()
}
main_window := Window{
window.inner_size: vec2(420, 300)
body +: {
main_view := View{
width: Fill height: Fill
flow: Down spacing: 12
align: Center
on_render: ||{
Label{
text: "Count: " + state.counter
draw_text.text_style.font_size: 24
}
}
}
increment_button := Button{
text: "Increment"
}
}
}
}
}
}
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm);
App::from_script_mod(vm, self::script_mod)
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[live]
ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(cx, ids!(increment_button)).clicked(actions) {
script_eval!(cx, {
mod.state.counter += 1
ui.main_view.render()
});
}
}
}
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}---
Key Components Explained
1. `app_main!(App)`
Registers `App` as the application entry point. MUST be called at module level.
2. `script_mod! { ... }`
Defines the Splash script that runs at startup. Contains:
- `use mod.prelude.widgets.*` - Import widget definitions
- State definitions (`let state = {...}`)
- Functions and templates
- `startup() do #(App::script_component(vm)){...}` - UI construction
3. `App::run(vm)` - Initialization Order
**CRITICAL: Registration order matters!**
fn run(vm: &mut ScriptVm) -> Self {
// 1. Register theme (optional, for light/dark theme)
crate::makepad_widgets::theme_mod(vm);
script_eval!(vm, { mod.theme = mod.themes.light });
// 2. Register base widgets
crate::makepad_widgets::widgets_mod(vm);
// 3. Register custom widget modules (if any)
// crate::my_widgets::script_mod(vm);
// 4. Build app from script module
App::from_script_mod(vm, self::script_mod)
}**Simplified (without theme selection):**
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // Registers both theme + widgets
App::from_script_mod(vm, self::script_mod)
}4. `#[derive(Script, ScriptHook)]` on App struct
#[derive(Script, ScriptHook)]
pub struct App {
#[live]
ui: WidgetRef, // The widget tree root
}- `Script` - Enables Splash integration (replaces old `Live`)
- `ScriptHook` - Enables lifecycle hooks (replaces old `LiveHook`)
- `#[live]` - Field settable from DSL
5. `MatchEvent` for Action Handling
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
// Check button clicks
if self.ui.button(cx, ids!(my_button)).clicked(actions) {
// Handle click
}
// Check text input changes
if let Some(text) = self.ui.text_input(cx, ids!(my_input)).changed(actions) {
log!("Input: {}", text);
}
}
}6. `AppMain` for Event Dispatch
impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event); // MUST call for MatchEvent to work
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}---
Rust → Splash Communication
script_eval! - Update state and trigger renders
script_eval!(cx, {
mod.state.counter += 1
ui.main_view.render()
});script_apply_eval! - Patch widget properties
script_apply_eval!(cx, self.ui, {
title.text: "New Title"
subtitle.draw_text.color: #f00
});---
Splash → Rust Communication
In
Skills for building cross-platform UI applications with Makepad 2.0.
Other skills on makepad-skills.
- /makepad-2.0-animation
CRITICAL: Use for Makepad 2.0 animation system. Triggers on: makepad animation, makepad animator, Animator, AnimatorState, hover effect, makepad transition, animation state, Forward, Snap, Loop, ease function, makepad animate, timeline, snap(), default @off, animation group, 动画,
Open skill - /makepad-2.0-design-judgment
CRITICAL: Entry-level skill for Makepad 2.0 GUI development. This is the FIRST skill to load for any Makepad task — it provides design judgment anchors ABOVE the other 13 Makepad 2.0 skills. Triggers on: makepad, makepad app, makepad project, makepad design, live_design!,
Open skill - /makepad-2.0-dsl
CRITICAL: Use for Makepad 2.0 DSL syntax and property system. Triggers on: makepad dsl, script_mod!, makepad syntax, makepad property, makepad 2.0 syntax, colon syntax, merge operator, named instance, let binding, mod.widgets, register_widget, script_component, type_default,
Open skill - /makepad-2.0-events
CRITICAL: Use for Makepad 2.0 event and action handling. Triggers on: makepad event, makepad action, MatchEvent, handle_event, handle_actions, on_click, on_render, on_return, on_startup, script_eval!, script_apply_eval!, button clicked, text changed, slider changed, checkbox
Open skill - /makepad-2.0-layout
CRITICAL: Use for Makepad 2.0 layout system. Triggers on: makepad layout, makepad width, makepad height, makepad flex, makepad flow, makepad padding, makepad margin, makepad spacing, makepad align, makepad sizing, Fill, Fit, Inset, Flow.Down, Flow.Right, ScrollXView,
Open skill - /makepad-2.0-migration
CRITICAL: Use for migrating from Makepad 1.x to 2.0. Triggers on: makepad migration, live_design to script_mod, makepad upgrade, makepad 1.x, old syntax, new syntax, makepad breaking changes, makepad 迁移, 旧语法, LiveHook to ScriptHook, apply_over to script_apply_eval, Live to
Open skill

