makepad-2.0-dsl

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Makepad 2.0 DSL Syntax Skill

Makepad 2.0 DSL 语法技能

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.
Makepad 2.0 使用运行时的
script_mod!
宏替代了编译时的
live_design!
宏,该宏由Splash脚本语言提供支持。本技能涵盖完整的DSL语法、属性系统、注册模式以及常见陷阱。

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
}
key: value          // CORRECT - colon syntax
key = value         // WRONG - old 1.x syntax, no longer works
属性使用空格/换行分隔,同级属性之间无需逗号。
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 -> vec
使用
:=
创建可寻址的命名组件实例:
my_button := Button{ text: "Click me" }
title := Label{ text: "Hello" }
命名实例具备以下特性:
  • 可通过Rust代码中的
    id!(my_button)
    ids!(my_button)
    进行寻址
  • 可通过点路径语法覆盖属性:
    MyTemplate{ title.text: "New text" }
  • 存储在脚本对象的
    vec
    中(而非
    map
常规属性使用
:
并存储在
map
中:
width: Fill       // regular property -> map
label := Label{}  // named child -> vec

Merge 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 else
+:
操作符用于扩展/合并父属性,而非完全替换:
draw_bg +: {
    color: #f00    // 仅覆盖color属性,保留draw_bg的其他所有属性
}
如果不使用
+:
, 会完全替换整个属性:
draw_bg: { color: #f00 }    // 替换整个draw_bg属性 - 丢失hover、border等样式
draw_bg +: { color: #f00 }  // 合并属性 - 仅修改color,保留其他所有内容

Dot-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 } }
点路径是合并操作的语法糖:
draw_bg.color: #f00
// 等价于:
draw_bg +: { color: #f00 }

draw_text.text_style.font_size: 14
// 等价于:
draw_text +: { text_style +: { font_size: 14 } }

Let Bindings: Local Templates

Let绑定:本地模板

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.*
.
let
用于在
script_mod!
块内创建本地可复用模板:
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 }
}

// 实例化并覆盖属性:
MyCard{ title.text: "Card 1" body.text: "Content here" }
MyCard{ title.text: "Card 2" body.text: "More content" }
重要提示
let
绑定仅在当前
script_mod!
块内有效,无法从其他
script_mod!
块访问。如需跨模块共享,请存储至
mod.widgets.*

Spread Operator:
..

扩展操作符:
..

Inherit all properties from another definition:
set_type_default() do #(DrawMyShader::script_shader(vm)){
    ..mod.draw.DrawQuad   // Inherit from DrawQuad
}
继承另一个定义的所有属性:
set_type_default() do #(DrawMyShader::script_shader(vm)){
    ..mod.draw.DrawQuad   // 继承DrawQuad的所有属性
}

Script Module Structure

脚本模块结构

Basic App Structure

基础应用结构

rust
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());
    }
}
rust
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内容写在这里
                    my_button := Button{ text: "Click" }
                }
            }
        }
    }
}

impl App {
    fn run(vm: &mut ScriptVm) -> Self {
        crate::makepad_widgets::script_mod(vm);  // 1. 先注册基础组件
        App::from_script_mod(vm, self::script_mod)
    }
}

#[derive(Script, ScriptHook)]
pub struct App {
    #[source] source: ScriptObjectRef,   // Script派生结构体必须包含该字段
    #[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

组件定义模块

rust
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
        }
    }
}
rust
script_mod!{
    use mod.prelude.widgets_internal.*   // 用于组件库内部开发
    use mod.widgets.*                     // 访问其他已注册组件

    // 步骤1:将Rust结构体注册为组件基类
    mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))

    // 步骤2:创建带默认属性的样式变体
    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:
rust
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
Rust side:
rust
#[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
}
对于实现
Widget
trait的结构体:
rust
mod.widgets.MyWidgetBase = #(MyWidget::register_widget(vm))
Rust端代码:
rust
#[derive(Script, ScriptHook, Widget)]
pub struct MyWidget {
    #[source] source: ScriptObjectRef,  // 必须包含
    #[walk] walk: Walk,
    #[layout] layout: Layout,
    #[redraw] #[live] draw_bg: DrawQuad,
    #[live] draw_text: DrawText,
    #[rust] my_state: i32,  // 仅运行时有效,不暴露给脚本
}

Component Registration

组件注册(非组件结构体)

For non-widget structs that need script integration:
rust
mod.widgets.MyComponentBase = #(MyComponent::script_component(vm))
对于需要脚本集成的非组件结构体:
rust
mod.widgets.MyComponentBase = #(MyComponent::script_component(vm))

Draw Shader Registration

绘制着色器注册

For custom draw types with shader fields:
rust
set_type_default() do #(DrawMyShader::script_shader(vm)){
    ..mod.draw.DrawQuad   // Inherit from DrawQuad
}
Rust side:
rust
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct DrawMyShader {
    #[deref] draw_super: DrawQuad,
    #[live] my_param: f32,
}
对于带着色器字段的自定义绘制类型:
rust
set_type_default() do #(DrawMyShader::script_shader(vm)){
    ..mod.draw.DrawQuad   // 继承DrawQuad的属性
}
Rust端代码:
rust
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct DrawMyShader {
    #[deref] draw_super: DrawQuad,
    #[live] my_param: f32,
}

Setting Type Defaults

设置类型默认值

rust
mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{
    width: Fill height: Fit
    draw_bg +: { color: theme.color_bg_app }
}
rust
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:
rust
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
    }
}
组件模块必须在使用它们的UI模块之前注册:
rust
impl App {
    fn run(vm: &mut ScriptVm) -> Self {
        crate::makepad_widgets::script_mod(vm);   // 1. 先注册基础组件
        crate::my_widgets::script_mod(vm);         // 2. 再注册自定义组件
        crate::app_ui::script_mod(vm);             // 3. 最后注册使用组件的UI
        App::from_script_mod(vm, self::script_mod) // 4. 最后注册应用组件
    }
}

Multi-Module Aggregation (lib.rs pattern)

多模块聚合(lib.rs模式)

rust
pub fn script_mod(vm: &mut ScriptVm) {
    crate::module_a::script_mod(vm);
    crate::module_b::script_mod(vm);
    // ... all widget modules
}
rust
pub fn script_mod(vm: &mut ScriptVm) {
    crate::module_a::script_mod(vm);
    crate::module_b::script_mod(vm);
    // ... 所有组件模块
}

Prelude System

预导入系统

Available Preludes

可用预导入包

PreludeUse Case
mod.prelude.widgets.*
App development - includes all standard widgets
mod.prelude.widgets_internal.*
Widget library internal development
预导入包使用场景
mod.prelude.widgets.*
应用开发 - 包含所有标准组件
mod.prelude.widgets_internal.*
组件库内部开发

Prelude Alias Syntax

预导入别名语法

rust
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.
rust
mod.prelude.widgets = {
    ..mod.std,            // 将mod.std的所有内容扩展到当前作用域
    theme:mod.theme,      // 创建theme作为mod.theme的别名
    draw:mod.draw,        // 创建draw作为mod.draw的别名
}
如果不使用别名(比如
mod.theme,
不带
theme:
前缀),模块会被导入但无法通过名称访问。

Cross-Module Sharing

跨模块共享

The
mod
Object is the ONLY Way to Share

mod
对象是唯一的共享方式

rust
// 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.
rust
// 在widget_module.rs中 - 导出到mod.widgets命名空间
script_mod!{
    use mod.prelude.widgets_internal.*
    mod.widgets.MyWidget = set_type_default() do mod.widgets.MyWidgetBase{ ... }
}

// 在app_ui.rs中 - 通过mod.widgets导入
script_mod!{
    use mod.prelude.widgets.*
    use mod.widgets.*   // 现在MyWidget已在作用域内
    // ...
    MyWidget{}
}
use crate.module.*
无效
-
crate.
前缀在script_mod中不可用。

Runtime Property Updates

运行时属性更新

Use
script_apply_eval!
instead of the old
apply_over
+
live!
:
rust
// 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 }) }
});
使用
script_apply_eval!
替代旧的
apply_over
+
live!
rust
// 旧系统
item.apply_over(cx, live!{ height: (height) });

// 新系统 - 使用#(expr)插值Rust表达式
script_apply_eval!(cx, item, {
    height: #(height)
    draw_bg: { is_even: #(if is_even { 1.0 } else { 0.0 }) }
});

Debug Logging

调试日志

Use
~expression
to log values during script evaluation:
rust
script_mod!{
    ~mod.theme           // Logs the theme object
    ~mod.prelude.widgets // Logs what's in the prelude
    ~some_variable       // Logs a variable's value
}
使用
~expression
在脚本执行期间记录值:
rust
script_mod!{
    ~mod.theme           // 记录theme对象
    ~mod.prelude.widgets // 记录预导入包中的内容
    ~some_variable       // 记录变量的值
}

Common Pitfalls

常见陷阱

1. Missing
#[source] source: ScriptObjectRef

1. 缺少
#[source] source: ScriptObjectRef

All
Script
-derived structs MUST have this field:
rust
#[derive(Script, ScriptHook)]
pub struct MyStruct {
    #[source] source: ScriptObjectRef,  // REQUIRED - will fail without it
    // ...
}
所有
Script
派生的结构体必须包含该字段:
rust
#[derive(Script, ScriptHook)]
pub struct MyStruct {
    #[source] source: ScriptObjectRef,  // 必须包含 - 缺少会导致错误
    // ...
}

2. Missing
height: Fit
on Containers

2. 容器组件缺少
height: Fit

Default height is
Fill
. In a
Fit
parent,
Fill
creates a circular dependency = 0 height = invisible:
// WRONG - invisible!
View{ flow: Down
    Label{ text: "You can't see me" }
}

// CORRECT
View{ height: Fit flow: Down
    Label{ text: "Visible!" }
}
默认高度为
Fill
。在
Fit
父容器中,
Fill
会导致循环依赖,最终高度为0,组件不可见:
// 错误 - 不可见!
View{ flow: Down
    Label{ text: "你看不到我" }
}

// 正确
View{ height: Fit flow: Down
    Label{ text: "可见!" }
}

3. Confusing
:
vs
:=

3. 混淆
:
:=

  • key: value
    -- sets a property (stored in map)
  • name := Widget{}
    -- creates a named, addressable child (stored in vec)
  • label := Label{ text: "x" }
    -- named, overridable via
    Template{ label.text: "y" }
  • label: Label{ text: "x" }
    -- anonymous, NOT addressable, overrides fail silently
  • key: value
    -- 设置属性(存储在map中)
  • name := Widget{}
    -- 创建可寻址的命名子组件(存储在vec中)
  • label := Label{ text: "x" }
    -- 命名组件,可通过
    Template{ label.text: "y" }
    覆盖属性
  • label: Label{ text: "x" }
    -- 匿名组件,不可寻址,覆盖操作会静默失败

4. Forgetting
+:
Merge Operator

4. 忘记使用
+:
合并操作符

// WRONG - replaces ALL of draw_bg (loses hover, border, animations)
draw_bg: { color: #f00 }

// CORRECT - merges, only changes color
draw_bg +: { color: #f00 }
// 错误 - 替换整个draw_bg(丢失hover、border、动画)
draw_bg: { color: #f00 }

// 正确 - 合并属性,仅修改color
draw_bg +: { color: #f00 }

5. Wrong Theme Access

5. 主题访问方式错误

// WRONG
color: THEME_COLOR_BG     // old 1.x constant syntax
color: (THEME_COLOR_BG)   // old 1.x parenthesized reference

// CORRECT
color: theme.color_bg_app
padding: theme.space_2
font_size: theme.font_size_p
// 错误
color: THEME_COLOR_BG     // 旧1.x常量语法
color: (THEME_COLOR_BG)   // 旧1.x括号引用语法

// 正确
color: theme.color_bg_app
padding: theme.space_2
font_size: theme.font_size_p

6. Hex Colors Containing 'e' Need
#x
Prefix

6. 包含'e'的十六进制颜色需要
#x
前缀

The Rust tokenizer interprets
e
/
E
in hex literals as scientific notation exponent:
// WRONG - Rust parse error: "expected at least one digit in exponent"
color: #2ecc71
color: #1e1e2e

// CORRECT - use #x prefix
color: #x2ecc71
color: #x1e1e2e

// Colors without 'e' work fine with plain #
color: #ff4444    // OK
color: #44cc44    // OK
Rust分词器会将十六进制字面量中的'e'/'E'解析为科学计数法的指数:
// 错误 - Rust解析错误:"expected at least one digit in exponent"
color: #2ecc71
color: #1e1e2e

// 正确 - 使用#x前缀
color: #x2ecc71
color: #x1e1e2e

// 不含'e'的颜色使用普通#即可
color: #ff4444    // 正常
color: #44cc44    // 正常

7.
pub
Keyword Invalid in script_mod

7.
pub
关键字在script_mod中无效

// WRONG
pub mod.widgets.MyWidget = ...

// CORRECT - visibility is controlled by Rust module system
mod.widgets.MyWidget = ...
// 错误
pub mod.widgets.MyWidget = ...

// 正确 - 可见性由Rust模块系统控制
mod.widgets.MyWidget = ...

8.
Inset{...}
Constructor Syntax for Margins/Padding

8. 边距/内边距使用
Inset{...}
构造函数语法

// WRONG
margin: { left: 10 }
align: { x: 0.5 y: 0.5 }

// CORRECT - use constructor syntax
margin: Inset{ left: 10 }
align: Align{ x: 0.5 y: 0.5 }
padding: Inset{ top: 5 bottom: 5 left: 10 right: 10 }

// Bare number for uniform values is OK
padding: 15
margin: 0.
// 错误
margin: { left: 10 }
align: { x: 0.5 y: 0.5 }

// 正确 - 使用构造函数语法
margin: Inset{ left: 10 }
align: Align{ x: 0.5 y: 0.5 }
padding: Inset{ top: 5 bottom: 5 left: 10 right: 10 }

// 统一值可以直接写数字
padding: 15
margin: 0.

9. Draw Shader Struct Field Ordering with
#[repr(C)]

9. 带
#[repr(C)]
的绘制着色器结构体字段顺序

Non-instance data (
#[rust]
, non-instance
#[live]
fields) MUST go BEFORE
#[deref]
. Only instance fields (shader inputs) go AFTER:
rust
// CORRECT
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
    #[live] pub svg: Option<ScriptHandleRef>,  // non-instance, BEFORE deref
    #[rust] my_state: bool,                     // non-instance, BEFORE deref
    #[deref] pub draw_super: DrawQuad,          // contains DrawVars + base instances
    #[live] pub tint: Vec4f,                    // instance field, AFTER deref - OK
}

// WRONG - #[rust] after instance fields corrupts GPU buffer
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
    #[deref] pub draw_super: DrawQuad,
    #[live] pub tint: Vec4f,
    #[rust] my_state: bool,      // BAD: between instance fields
}
非实例数据(
#[rust]
、非实例
#[live]
字段)必须放在
#[deref]
之前。只有实例字段(着色器输入)可以放在之后:
rust
// 正确
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
    #[live] pub svg: Option<ScriptHandleRef>,  // 非实例字段,放在deref之前
    #[rust] my_state: bool,                     // 非实例字段,放在deref之前
    #[deref] pub draw_super: DrawQuad,          // 包含DrawVars和基础实例
    #[live] pub tint: Vec4f,                    // 实例字段,放在deref之后 - 正确
}

// 错误 - #[rust]放在实例字段之间会破坏GPU缓冲区
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
    #[deref] pub draw_super: DrawQuad,
    #[live] pub tint: Vec4f,
    #[rust] my_state: bool,      // 错误:位于实例字段之间
}

10. No Comments Before First Code in script_mod!

10. script_mod首行不能是注释!

Rust proc macro token stream strips comments, which shifts error positions:
rust
// WRONG
script_mod!{
    // This comment shifts error line info
    use mod.prelude.widgets.*
}

// CORRECT - start with real code immediately
script_mod!{
    use mod.prelude.widgets.*
    // Comments after first code are fine
}
Rust过程宏的令牌流会移除注释,导致错误位置偏移:
rust
// 错误
script_mod!{
    // 该注释会导致错误行号偏移
    use mod.prelude.widgets.*
}

// 正确 - 直接以有效代码开头
script_mod!{
    use mod.prelude.widgets.*
    // 首行代码之后的注释没问题
}

Additional Pitfalls

其他陷阱

  • Cursor values: Use
    cursor: MouseCursor.Hand
    not
    cursor: Hand
    or
    cursor: @Hand
  • Resource paths: Use
    crate_resource("self://path")
    not
    dep("crate://self/path")
  • Texture declarations: Use
    tex: texture_2d(float)
    not
    tex: texture2d
  • Shader
    mod
    vs
    modf
    : Use
    modf(a, b)
    for float modulo, NOT
    mod(a, b)
  • Enum defaults: Use
    default: @off
    with
    @
    prefix for enum default values
  • DefaultNone derive: Don't use
    DefaultNone
    derive; use
    #[derive(Default)]
    with
    #[default]
    attribute
  • Method chaining in shaders: Use
    .method()
    not
    ::method()
    (e.g.,
    Sdf2d.viewport(...)
    )
  • Color mixing: Prefer
    color1.mix(color2, hover)
    chaining over nested
    mix()
    calls
  • Missing widget registration: Call
    crate::makepad_widgets::script_mod(vm)
    in
    App::run()
    BEFORE your own modules
  • 光标值:使用
    cursor: MouseCursor.Hand
    而非
    cursor: Hand
    cursor: @Hand
  • 资源路径:使用
    crate_resource("self://path")
    而非
    dep("crate://self/path")
  • 纹理声明:使用
    tex: texture_2d(float)
    而非
    tex: texture2d
  • 着色器中的
    mod
    modf
    :使用
    modf(a, b)
    进行浮点数取模,而非
    mod(a, b)
  • 枚举默认值:枚举默认值使用
    default: @off
    ,带
    @
    前缀
  • DefaultNone派生:不要使用
    DefaultNone
    派生;使用
    #[derive(Default)]
    搭配
    #[default]
    属性
  • 着色器中的方法链:使用
    .method()
    而非
    ::method()
    (例如
    Sdf2d.viewport(...)
  • 颜色混合:优先使用
    color1.mix(color2, hover)
    链式调用,而非嵌套
    mix()
    调用
  • 组件注册缺失:在
    App::run()
    中,调用
    crate::makepad_widgets::script_mod(vm)
    必须早于自定义模块

Syntax Quick Reference

语法速查

Old (live_design!)New (script_mod!)
<BaseWidget>
mod.widgets.BaseWidget{}
or
BaseWidget{}
(if imported)
{{StructName}}
#(Struct::register_widget(vm))
(THEME_COLOR_X)
theme.color_x
<THEME_FONT>
theme.font_regular
instance hover: 0.0
hover: instance(0.0)
uniform color: #fff
color: uniform(#fff)
draw_bg: {}
(replace)
draw_bg +: {}
(merge)
default: off
default: @off
fn pixel(self)
pixel: fn()
item.apply_over(cx, live!{...})
script_apply_eval!(cx, item, {...})
旧语法(live_design!)新语法(script_mod!)
<BaseWidget>
mod.widgets.BaseWidget{}
BaseWidget{}
(已导入时)
{{StructName}}
#(Struct::register_widget(vm))
(THEME_COLOR_X)
theme.color_x
<THEME_FONT>
theme.font_regular
instance hover: 0.0
hover: instance(0.0)
uniform color: #fff
color: uniform(#fff)
draw_bg: {}
(替换)
draw_bg +: {}
(合并)
default: off
default: @off
fn pixel(self)
pixel: fn()
item.apply_over(cx, live!{...})
script_apply_eval!(cx, item, {...})

Reference Files

参考文档

  • DSL Syntax Reference -- Complete syntax grammar and examples
  • Property System -- Walk, Layout, Draw, and shader properties
  • DSL语法参考 -- 完整语法规则与示例
  • 属性系统 -- Walk、Layout、Draw及着色器属性说明