/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,
$ npx -y skills add ZhangHanDong/makepad-skills --skill makepad-2.0-dsl --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-dsl
Context preview
The summary Claude sees to decide when to auto-load this skill.
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,
SKILL.md
makepad-2.0-dsl.SKILL.mdname: makepad-2.0-dsl
description: |
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, widgets_internal
Makepad 2.0 DSL Syntax Skill
Overview
Makepad 2.0 replaced the compile-time `live_design!` macro with the runtime `script_mod!` macro, powered by the Splash scripting language. This skill covers the complete DSL syntax, property system, registration patterns, and common pitfalls.
Key Syntax Rules
Property Assignment: Colon, NOT Equals
key: value // CORRECT - colon syntax
key = value // WRONG - old 1.x syntax, no longer works
Properties are whitespace/newline separated. No commas between siblings.
View{
width: Fill
height: Fit
flow: Down
spacing: 10
padding: 15
}Named Instances: `:=` Operator
Use `:=` to create addressable, named widget instances:
my_button := Button{ text: "Click me" }
title := Label{ text: "Hello" }Named instances are:
- Addressable from Rust code via `id!(my_button)` or `ids!(my_button)`
- Overridable via dot-path syntax: `MyTemplate{ title.text: "New text" }`
- Stored in the script object's `vec` (not `map`)
Regular properties use `:` and go into `map`:
width: Fill // regular property -> map
label := Label{} // named child -> vecMerge Operator: `+:`
The `+:` operator extends/merges with the parent instead of replacing:
draw_bg +: {
color: #f00 // Only overrides color, keeps all other draw_bg properties
}Without `+:`, you REPLACE the entire property:
draw_bg: { color: #f00 } // REPLACES all of draw_bg - loses hover, border, etc.
draw_bg +: { color: #f00 } // MERGES - only changes color, keeps everything elseDot-Path Shorthand
Dot-path is syntactic sugar for merge:
draw_bg.color: #f00
// is equivalent to:
draw_bg +: { color: #f00 }
draw_text.text_style.font_size: 14
// is equivalent to:
draw_text +: { text_style +: { font_size: 14 } }Let Bindings: Local Templates
`let` creates local, reusable templates within a `script_mod!` block:
let MyCard = RoundedView{
width: Fill height: Fit
padding: 16 flow: Down spacing: 8
draw_bg.color: #2a2a3d
draw_bg.border_radius: 8.0
title := Label{ text: "Default Title" draw_text.color: #fff }
body := Label{ text: "" draw_text.color: #aaa }
}
// Instantiate and override:
MyCard{ title.text: "Card 1" body.text: "Content here" }
MyCard{ title.text: "Card 2" body.text: "More content" }**IMPORTANT**: `let` bindings are LOCAL to the `script_mod!` block. They cannot be accessed from other `script_mod!` blocks. To share across modules, store in `mod.widgets.*`.
Spread Operator: `..`
Inherit all properties from another definition:
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // Inherit from DrawQuad
}Script Module Structure
Basic App Structure
use makepad_widgets::*;
app_main!(App);
script_mod!{
use mod.prelude.widgets.*
load_all_resources() do #(App::script_component(vm)){
ui: Root{
main_window := Window{
window.inner_size: vec2(800, 600)
body +: {
// UI content here
my_button := Button{ text: "Click" }
}
}
}
}
}
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. Register base widgets
App::from_script_mod(vm, self::script_mod)
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[source] source: ScriptObjectRef, // REQUIRED for Script-derived structs
#[live] ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(ids!(my_button)).clicked(actions) {
log!("Button clicked!");
}
}
}
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());
}
}Widget Definition Module
script_mod!{
use mod.prelude.widgets_internal.* // For widget library internals
use mod.widgets.* // Access other registered widgets
// Step 1: Register the Rust struct as a widget base
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
// Step 2: Create a styled variant with default properties
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill
height: Fit
padding: theme.space_2
draw_bg +: {
color: theme.color_bg_app
}
}
}Registration Patterns
Widget Registration
For structs that implement the `Widget` trait:
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
Rust side:
#[derive(Script, ScriptHook, Widget)]
pub struct MyWidget {
#[source] source: ScriptObjectRef, // REQUIRED
#[walk] walk: Walk,
#[layout] layout: Layout,
#[redraw] #[live] draw_bg: DrawQuad,
#[live] draw_text: DrawText,
#[rust] my_state: i32, // Runtime-only, not exposed to script
}Component Registration
For non-widget structs that need script integration:
mod.widgets.MyComponentBase = #(MyComponent::script_component(vm))
Draw Shader Registration
For custom draw types with shader fields:
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // Inherit from DrawQuad
}Rust side:
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct DrawMyShader {
#[deref] draw_super: DrawQuad,
#[live] my_param: f32,
}Setting Type Defaults
mod.wi
Read more
name: makepad-2.0-dsl description: | 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, widgets_internal
Makepad 2.0 DSL Syntax Skill
Overview
Makepad 2.0 replaced the compile-time `live_design!` macro with the runtime `script_mod!` macro, powered by the Splash scripting language. This skill covers the complete DSL syntax, property system, registration patterns, and common pitfalls.
Key Syntax Rules
Property Assignment: Colon, NOT Equals
key: value // CORRECT - colon syntax key = value // WRONG - old 1.x syntax, no longer works
Properties are whitespace/newline separated. No commas between siblings.
View{
width: Fill
height: Fit
flow: Down
spacing: 10
padding: 15
}Named Instances: `:=` Operator
Use `:=` to create addressable, named widget instances:
my_button := Button{ text: "Click me" }
title := Label{ text: "Hello" }Named instances are:
- Addressable from Rust code via `id!(my_button)` or `ids!(my_button)`
- Overridable via dot-path syntax: `MyTemplate{ title.text: "New text" }`
- Stored in the script object's `vec` (not `map`)
Regular properties use `:` and go into `map`:
width: Fill // regular property -> map
label := Label{} // named child -> vecMerge Operator: `+:`
The `+:` operator extends/merges with the parent instead of replacing:
draw_bg +: {
color: #f00 // Only overrides color, keeps all other draw_bg properties
}Without `+:`, you REPLACE the entire property:
draw_bg: { color: #f00 } // REPLACES all of draw_bg - loses hover, border, etc.
draw_bg +: { color: #f00 } // MERGES - only changes color, keeps everything elseDot-Path Shorthand
Dot-path is syntactic sugar for merge:
draw_bg.color: #f00
// is equivalent to:
draw_bg +: { color: #f00 }
draw_text.text_style.font_size: 14
// is equivalent to:
draw_text +: { text_style +: { font_size: 14 } }Let Bindings: Local Templates
`let` creates local, reusable templates within a `script_mod!` block:
let MyCard = RoundedView{
width: Fill height: Fit
padding: 16 flow: Down spacing: 8
draw_bg.color: #2a2a3d
draw_bg.border_radius: 8.0
title := Label{ text: "Default Title" draw_text.color: #fff }
body := Label{ text: "" draw_text.color: #aaa }
}
// Instantiate and override:
MyCard{ title.text: "Card 1" body.text: "Content here" }
MyCard{ title.text: "Card 2" body.text: "More content" }**IMPORTANT**: `let` bindings are LOCAL to the `script_mod!` block. They cannot be accessed from other `script_mod!` blocks. To share across modules, store in `mod.widgets.*`.
Spread Operator: `..`
Inherit all properties from another definition:
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // Inherit from DrawQuad
}Script Module Structure
Basic App Structure
use makepad_widgets::*;
app_main!(App);
script_mod!{
use mod.prelude.widgets.*
load_all_resources() do #(App::script_component(vm)){
ui: Root{
main_window := Window{
window.inner_size: vec2(800, 600)
body +: {
// UI content here
my_button := Button{ text: "Click" }
}
}
}
}
}
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. Register base widgets
App::from_script_mod(vm, self::script_mod)
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[source] source: ScriptObjectRef, // REQUIRED for Script-derived structs
#[live] ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(ids!(my_button)).clicked(actions) {
log!("Button clicked!");
}
}
}
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());
}
}Widget Definition Module
script_mod!{
use mod.prelude.widgets_internal.* // For widget library internals
use mod.widgets.* // Access other registered widgets
// Step 1: Register the Rust struct as a widget base
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
// Step 2: Create a styled variant with default properties
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill
height: Fit
padding: theme.space_2
draw_bg +: {
color: theme.color_bg_app
}
}
}Registration Patterns
Widget Registration
For structs that implement the `Widget` trait:
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
Rust side:
#[derive(Script, ScriptHook, Widget)]
pub struct MyWidget {
#[source] source: ScriptObjectRef, // REQUIRED
#[walk] walk: Walk,
#[layout] layout: Layout,
#[redraw] #[live] draw_bg: DrawQuad,
#[live] draw_text: DrawText,
#[rust] my_state: i32, // Runtime-only, not exposed to script
}Component Registration
For non-widget structs that need script integration:
mod.widgets.MyComponentBase = #(MyComponent::script_component(vm))
Draw Shader Registration
For custom draw types with shader fields:
set_type_default() do #(DrawMyShader::script_shader(vm)){
..mod.draw.DrawQuad // Inherit from DrawQuad
}Rust side:
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct DrawMyShader {
#[deref] draw_super: DrawQuad,
#[live] my_param: f32,
}Setting Type Defaults
mod.wi
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-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,
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-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

