makepad-2-0-dsl – skill Lập trình cho agent AI
Hướng dẫn Makepad 2.0 về dsl; dùng khi xây dựng hoặc gỡ lỗi mã UI Makepad.
Cài skill makepad-2-0-dsl bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/makepad-2-0-dsl-2891d.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /makepad-2-0-dsl – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/makepad-2-0-dsl-2891d.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $makepad-2-0-dsl – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/makepad-2-0-dsl-2891d.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /makepad-2-0-dsl – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/makepad-2-0-dsl-2891d.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /makepad-2-0-dsl – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Limitations
- Verify against current Makepad 2.0 docs; upstream APIs change frequently.
- Do not run bundled scripts without explicit user approval.
When to Use
- Use when this upstream workflow matches the user's stated goal.
- Use when the task requires the procedures documented in this skill.
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 reference covers the upstream Splash/script_mod generation; it is not a complete stable Makepad language specification. Record the exact Makepad git revision from Cargo.lock, inspect that revision's widget/script sources and compile a minimal example before migrating an existing live_design application. Do not mix generations merely because a package is called 2.0.
Key Syntax Rules
Property Assignment: Colon, NOT Equals
key: value // CORRECT - colon syntax
key = value // WRONG - old 1.x syntax, no longer worksProperties 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)orids!(my_button) - Overridable via dot-path syntax:
MyTemplate{ title.text: "New text" } - Stored in the script object's
vec(notmap)
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.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
width: Fill height: Fit
draw_bg +: { color: theme.color_bg_app }
}Registration Order (CRITICAL)
Widget modules MUST be registered BEFORE UI modules that use them:
impl App {
fn run(vm: &mut ScriptVm) -> Self {
crate::makepad_widgets::script_mod(vm); // 1. Base widgets FIRST
crate::my_widgets::script_mod(vm); // 2. Custom widgets SECOND
crate::app_ui::script_mod(vm); // 3. UI using widgets THIRD
App::from_script_mod(vm, self::script_mod) // 4. App component LAST
}
}Multi-Module Aggregation (lib.rs pattern)
pub fn script_mod(vm: &mut ScriptVm) {
crate::module_a::script_mod(vm);
crate::module_b::script_mod(vm);
// ... all widget modules
}Prelude System
Available Preludes
| Prelude | Use Case |
|---------|----------|
| mod.prelude.widgets.* | App development - includes all standard widgets |
| mod.prelude.widgets_internal.* | Widget library internal development |
Prelude Alias Syntax
mod.prelude.widgets = {
..mod.std, // Spread all of mod.std into scope
theme:mod.theme, // Create 'theme' as alias for mod.theme
draw:mod.draw, // Create 'draw' as alias for mod.draw
}Without the alias (mod.theme, without theme:), the module is included but has no accessible name.
Cross-Module Sharing
The mod Object is the ONLY Way to Share
// In widget_module.rs - export to mod.widgets namespace
script_mod!{
use mod.prelude.widgets_internal.*
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{ ... }
}
// In app_ui.rs - import via mod.widgets
script_mod!{
use mod.prelude.widgets.*
use mod.widgets.* // Now MyWidget is in scope
// ...
MyWidget{}
}**use crate.module.* does NOT work** - the crate. prefix is not available in script_mod.
Runtime Property Updates
Use script_apply_eval! instead of the old apply_over + live!:
// Old system
item.apply_over(cx, live!{ height: (height) });
// New system - use #(expr) for Rust expression interpolation
script_apply_eval!(cx, item, {
height: #(height)
draw_bg: { is_even: #(if is_even { 1.0 } else { 0.0 }) }
});Never interpolate untrusted text into executable script/DSL. Set text through typed properties/APIs, validate resource paths and avoid logging sensitive model/user values. Shader/layout examples are partial and must be checked across target GPU/platform, DPI and keyboard/accessibility behavior.
Debug Logging
Use ~expression to log values during script evaluation:
script_mod!{
~mod.theme // Logs the theme objec… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- makepad-2-0-events – Hướng dẫn Makepad 2.0 về events; dùng khi xây dựng hoặc gỡ lỗi mã UI Makepad.
- makepad-2-0-layout – Hướng dẫn Makepad 2.0 về layout; dùng khi xây dựng hoặc gỡ lỗi mã UI Makepad.
- makepad-2-0-widgets – Hướng dẫn Makepad 2.0 về widgets; dùng khi xây dựng hoặc gỡ lỗi mã UI Makepad.
- makepad-widgets – Chọn và kết hợp các widget Makepad, cấu hình thuộc tính và kiểu dáng, gỡ lỗi hành vi…
- markstream-custom-components – Ghi đè node renderer của Markstream và thêm thẻ tùy chỉnh đáng tin cậy trên Vue, React…
- markstream-react – Tích hợp renderer markstream-react (beta) vào React 18+ hoặc Next.js với entrypoint…
- markstream-vue – Tích hợp markstream-vue vào Vue 3 thuần với các chế độ renderer, lựa chọn code và DOM…
- markstream-vue2-cli – Tích hợp markstream-vue2 vào Vue CLI hoặc Webpack 4 với CSS tương thích export-map, dự…