Token导航 LogoToken导航

Agent Skill · 前端设计

makepad-2.0-splash(makepad 2 0 飞溅)

makepad-2.0-splash 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

makepad-2.0-splash 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,暂无第三方扫描结果,按安装量在前端设计类的 10,216 个 Skill 里排第 8,327。

总安装 294周安装 12GitHub Stars 737下载 95核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:makepad-2.0-splash(makepad 2 0 飞溅)
来源仓库:https://github.com/zhanghandong/makepad-skills
仓库路径:skills/makepad-2.0-splash
安装命令:
npx skills add https://github.com/zhanghandong/makepad-skills --skill makepad-2.0-splash
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/zhanghandong/makepad-skills --skill makepad-2.0-splash

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

用于处理 GitHub 仓库与协作信息,支持启动页相关 Issue 和 PR 管理。适合在应用开发流程中围绕代码变更进行整理。需确认仓库访问权限和维护状态,避免误操作或数据丢失。建议在操作前核对权限范围,防止触发敏感操作。makepad-2.0-splash 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/makepad-2.0-splash

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/zhanghandong/makepad-skills --skill makepad-2.…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

makepad-2.0-splash 怎么安装?

在终端执行 npx skills add https://github.com/zhanghandong/makepad-skills --skill makepad-2.0-splash。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

makepad-2.0-splash 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

makepad-2.0-splash 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

makepad-2.0-splash 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

makepad-2.0-splash 用的人多吗?

公开数据是累计安装 294 次,近一周安装 12 次,下载 95 次,GitHub 737 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

makepad-2.0-splash 安全吗?

没有查到第三方扫描结果,安全性无法从公开资料判断,安装前请自行审查源码、依赖和命令行为。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 没有第三方扫描结果,安全性只能靠自己读源码判断。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 要求有安全扫描结论才肯安装的团队。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
makepad-2.0-splash

makepad 2 0 飞溅 · 本页

294737需要联网未明确未收录

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Makepad 2.0 Splash Scripting Language

Splash is Makepad 2.0's core runtime UI scripting language, released February 12, 2026. It replaces the old compile-time live_design! macro system with a runtime script_mod! macro that enables hot reload, streaming evaluation, and AI-first code generation.

Core Concepts

Script Structure

Every Splash script starts with a use import and is embedded in Rust via the script_mod!{} macro:

use makepad_widgets::*;

app_main!(App);

script_mod! {
    use mod.prelude.widgets.*

    // let bindings, functions, state, and UI definitions go here

    startup() do #(App::script_component(vm)){
        ui: Root{
            main_window := Window{
                window.inner_size: vec2(800, 600)
                body +: {
                    // UI content
                }
            }
        }
    }
}

Syntax Rules

  • No commas between properties -- whitespace-delimited
  • No semicolons -- cleaner syntax optimized for LLM generation
  • Property assignment: key: value
  • Dot-path shorthand: draw_bg.color: #f00 (equivalent to draw_bg +: {color: #f00})
  • Merge operator: key +: {...} extends parent without replacing
  • Named children: name:= Widget{...} (addressable, overridable per-instance)
  • Let bindings: let MyTemplate = Widget{...} (local scope, must be defined before use)
  • Rust binding: #(Struct::register_widget(vm)) connects Splash to Rust structs
  • Debug logging: ~expression logs value during evaluation

State Management

State is managed via the mod.state object and reactive on_render callbacks:

// Define state
let state = { counter: 0 }
mod.state = state

// Reactive rendering -- re-runs when .render() is called
main_view := View{
    on_render: ||{
        Label{ text: "Count: " + state.counter }
    }
}

Event Handling

Events are handled both inline in Splash and from Rust:

// Inline event handlers in Splash
add_button := Button{
    text: "Add"
    on_click: ||{
        add_todo(ui.todo_input.text(), "")
        ui.todo_input.set_text("")
    }
}

// TextInput return key
todo_input := TextInput{
    on_return: || ui.add_button.on_click()
}

// Startup event
on_startup: ||{
    ui.main_view.render()
}

From Rust, use script_eval! to execute Splash code:

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()
            });
        }
    }
}

Functions

fn tag_color(tag) {
    if tag == "dev" theme.color_highlight
    else if tag == "design" theme.color_selection_focus
    else theme.color_highlight
}

fn add_todo(text, tag) {
    todos.push({text: text, tag: tag, done: false})
    ui.todo_list.render()
}

Control Flow

// If/else
if todos.len() == 0
    EmptyState{}
else for i, todo in todos {
    TodoItem{ label.text: todo.text }
}

// For loops
for i, item in array {
    Label{ text: item.name }
}

// While
while condition { ... }

HTTP Requests

let req = net.HttpRequest{
    url: "https://api.example.com/data"
    method: net.HttpMethod.GET
    headers: {"User-Agent": "MakepadApp/1.0"}
}
net.http_request(req) do net.HttpEvents{
    on_response: |res| {
        let text = res.body.to_string()
        let json = res.body.parse_json()
    }
    on_error: |e| { /* handle error */ }
}

Streaming responses use is_streaming: true with on_stream and on_complete callbacks.

HTML Parsing

let doc = html_string.parse_html()
doc.query("p")              // all <p> elements
doc.query("#main")           // by id
doc.query("p.bold")          // by class
doc.query("div > p")         // direct children
doc.query("p[0]").text       // text content
doc.query("a@href")          // attribute value

Streaming Evaluation

Splash's parser supports checkpoint-based incremental parsing, designed for AI/LLM streaming code generation:

// Rust API for streaming evaluation
vm.eval_with_append_source(script_mod, &code, NIL.into())

This enables real-time UI updates as code is generated token-by-token, without requiring a complete script before evaluation.

Hot Reload & Script Mod Tracking

Splash scripts support hot reload via the --hot flag. The VM tracks each script_mod! block with a unique ScriptModKey (file, line, column):

// Internal: ScriptModKey uniquely identifies a script_mod! block
ScriptModKey { file: "src/app.rs", line: 5, col: 1 }

// Runtime substitution via overrides
ScriptCode::script_mod_overrides  // HashMap of ScriptModKey -> updated source

How hot reload works:

  1. File watcher (makepad_live_reload_core) detects source file changes
  2. script_mod! blocks are extracted from Rust source (handles raw strings, comments, char literals)
  3. Rust placeholder counts (#(...)) are tracked -- adding/removing placeholders requires full rebuild
  4. Validated script mods are applied via script_mod_overrides
  5. IP-to-location mapping provides source maps for error reporting (fallback to nearest token for synthetic opcodes)

ScriptSource variants:

  • ScriptSource::Mod -- Standard module evaluation (startup)
  • ScriptSource::Streaming -- Incremental streaming evaluation (AI/LLM)

Critical Layout Rules

  1. Always set height: Fit on containers -- default height: Fill causes invisible UI (0px height)
  2. Use width: Fill on the root container -- never fixed pixel width at the top level
  3. Set new_batch: true on any View with show_bg: true that contains text children
  4. Use := for named children in templates -- without it, text overrides fail silently
  5. draw_bg.border_radius takes a float, not an Inset -- draw_bg.border_radius: 16.0
  6. Use styled Views (RoundedView, SolidView) instead of raw View{show_bg: true}

Widget Reference

Core containers: View, SolidView, RoundedView, RectView, RoundedShadowView, CircleView, GradientXView, GradientYView, ScrollXYView, ScrollXView, ScrollYView

Text: Label, H1-H4, P, TextBox, TextInput, LinkLabel, Markdown, Html

Controls: Button, ButtonFlat, ButtonFlatter, CheckBox, Toggle, RadioButton, Slider, DropDown

Layout: Splitter, FoldHeader, Hr, Vr, Filler

Lists: PortalList, FlatList

Navigation: Modal, Tooltip, PopupNotification, SlidePanel, ExpandablePanel, PageFlip, StackNavigation

Dock: Dock, DockSplitter, DockTabs, DockTab

Media: Image, Icon, LoadingSpinner, Vector, MathView, MapView

Canvas: Rendering Splash from Claude Code

Makepad Canvas (tools/canvas/) is a standalone app that renders Splash code received via HTTP/WS. Used by Claude Code for visual output.

HTTP API (recommended for sending Splash)

PORT=$(cat /tmp/makepad-canvas.port)

# Full render
curl -s -X POST "http://127.0.0.1:$PORT/splash" -d 'View{width:Fill height:Fit Label{text:"Hello"}}'

# Streaming render
curl -s -X POST "http://127.0.0.1:$PORT/splash/stream"                    # begin
curl -s -X POST "http://127.0.0.1:$PORT/splash/stream" -d 'View{...'      # append
curl -s -X POST "http://127.0.0.1:$PORT/splash/end"                       # end

# Clear
curl -s -X POST "http://127.0.0.1:$PORT/clear"

WS Event Listening (for receiving click events)

# Long-lived WS connection receives button click events as JSON
mkfifo /tmp/ws_fifo; (sleep 99999 > /tmp/ws_fifo &)
websocat ws://127.0.0.1:$PORT < /tmp/ws_fifo > /tmp/canvas_events &

# Events arrive as: {"event":"click","widget":"btn_name"}

Interactive Buttons

Use name:= Button{...} to create clickable buttons. The name is sent in click events:

View{width:Fill height:Fit flow:Right spacing:12
  btn_save := Button{text:"Save"}
  btn_cancel := Button{text:"Cancel"}
}

When clicked: {"event":"click","widget":"btn_save"}

Vector Animations in Splash

// Pulsing dot (loop_:true = indefinite, NOT "indefinite"!)
Vector{width:16 height:16
  Circle{cx:8 cy:8 r:6 fill:#x44ddaa opacity:Tween{from:0.3 to:1.0 dur:1.5 loop_:true}}
}

// Moving dot with color change
Vector{width:Fill height:30
  Path{d:"M 20 15 L 400 15" stroke:#x222244 stroke_width:1.}
  Circle{cx:Tween{from:20 to:400 dur:3.0 loop_:true} cy:15 r:4 fill:Tween{from:#x44ddaa to:#xffaa44 dur:3.0 loop_:true}}
}

Canvas Splash Syntax (CRITICAL -- differs from script_mod!)

When generating Splash for Canvas HTTP rendering (POST /splash), use these EXACT patterns. Canvas Splash syntax differs from script_mod! macro context in several critical ways:

1. Properties use dot-path inline, NOT nested blocks:

// WRONG -- nested block syntax does not render backgrounds
RoundedView{height: Fit draw_bg: { color: #x1a1a2e border_radius: 8.0 } }

// CORRECT -- dot-path inline
RoundedView{width: Fill height: Fit draw_bg.color: #x1a1a2e draw_bg.radius: 8.}

2. Border radius is draw_bg.radius, NOT draw_bg.border_radius:

// WRONG
draw_bg.border_radius: 8.0

// CORRECT
draw_bg.radius: 8.

3. Padding uses explicit Inset{} type with trailing-dot floats:

// WRONG -- bare number or nested block
padding: 20
padding: { top: 20 bottom: 20 }

// CORRECT
padding: Inset{left: 20. right: 20. top: 16. bottom: 16.}

4. Align uses explicit Align{} type:

// WRONG
align: { y: 0.5 }

// CORRECT
align: Align{y: 0.5}
align: Center

5. Float values use trailing dot:

// WRONG       // CORRECT
8.0            8.
16.0           16.
0.5            0.5

6. SolidView and RoundedView do NOT need show_bg: true or new_batch: true -- they render backgrounds out of the box.

7. Use --data-binary for multi-line Splash via curl -- plain -d strips newlines.

Proven Canvas Dashboard Template

Source: tools/canvas/examples/token-dashboard.splash

SolidView{width: Fill height: Fit draw_bg.color: #x0c0c18 flow: Down padding: Inset{left: 32. right: 32. top: 24. bottom: 24.} spacing: 20

    // Title
    Label{text: "Dashboard Title" draw_text.color: #xeeeeff draw_text.text_style.font_size: 20}

    // Card row
    View{width: Fill height: Fit flow: Right spacing: 16
        RoundedView{width: Fill height: Fit draw_bg.color: #x161628 draw_bg.radius: 8. padding: Inset{left: 20. right: 20. top: 16. bottom: 16.} flow: Down spacing: 6
            Label{text: "Metric Name" draw_text.color: #x888899 draw_text.text_style.font_size: 10}
            Label{text: "Value" draw_text.color: #xcc66ff draw_text.text_style.font_size: 28}
        }
    }

    // Horizontal bar chart row
    View{width: Fill height: Fit flow: Right spacing: 8 align: Align{y: 0.5}
        Label{text: "Label" width: 100 draw_text.color: #xbbbbbb draw_text.text_style.font_size: 10}
        RoundedView{width: 200 height: 12 draw_bg.color: #xf44336 draw_bg.radius: 2.}
        Label{text: "200" draw_text.color: #x777777 draw_text.text_style.font_size: 10}
    }

    // Vertical bar chart (bars bottom-aligned)
    View{width: Fill height: 130 flow: Right spacing: 2 align: Align{y: 1.0}
        View{width: Fill height: Fit flow: Down align: Center spacing: 4
            RoundedView{width: 14 height: 80 draw_bg.color: #x7733cc draw_bg.radius: 2.}
            Label{text: "Mon" draw_text.color: #x444455 draw_text.text_style.font_size: 7}
        }
    }
}

Canvas Tips

  • HTTP for splash, WS for events — most reliable pattern
  • Vector shape properties: fill, stroke, stroke_width — NOT draw_bg.*
  • CJK/Chinese text: Supported in both body text and code blocks. CodeEditor uses double-width columns for CJK characters (fixed 2026-03-23). Theme font_code includes LXGWWenKai as Chinese fallback.
  • Large POST bodies: Canvas supports up to 512KB HTTP body
  • Pub/sub broadcast: All connected WS clients receive click events
  • Health check: Use GET /ping (NOT /health)
  • Monitor toggle: /tmp/canvas-monitor-active flag file controls statusline auto-refresh. Canvas sidebar has a toggle button.

Compiled vs Eval: Two Fundamentally Different Widget Creation Paths

Understanding this distinction is CRITICAL for debugging any Splash eval issue:

Compiled path (script_mod!, examples, studio):
  parse → compile → execute → create_widget
    → script_apply(FULL type default object with all vec + map entries)
    → on_after_apply(value = full object) ✓  ← ScriptHook runs
    → Templates registered, #[live] fields populated from type default

Eval path (POST /splash, Splash.set_text):
  parse → eval → create_widget_from_prototype
    → script_apply(EVAL VALUE ONLY, e.g. {body: "..."})
    → on_after_apply: SKIPPED (is_eval() guard in TextFlow/Markdown)
    → Templates NOT registered, #[live] fields use defaults (not type default)
AspectCompiled (script_mod!)Eval (set_text)
Widget creationFull Rust + ScriptVm initScriptVm eval string only
on_after_applyCalled with full type defaultNOT called
Type default vec (named children)Fully inheritedMay lose entries in proto copy
Type default map (properties)Applied to #[live] fieldsOnly eval value applied
Template registrationVia ScriptHook during applyMust be done lazily in draw_walk
ScrollYViewWorksRenders blank — use View

Fix pattern for eval-path issues: Implement lazy initialization in draw_walk that detects missing state and looks up the type default via cx.with_vm(|vm| vm.bx.heap.type_default_for_object(...)). This is how Markdown's code_block template inheritance was fixed.

Splash Eval Pitfalls (CRITICAL -- learned 2026-03-23)

These issues only affect widgets created via Splash runtime eval (POST /splash, Splash.set_text()), NOT compiled script_mod! widgets:

1. ScrollYView does NOT work in Splash eval -- renders blank

// WRONG -- Splash eval renders nothing
ScrollYView{ width: Fill height: Fill flow: Down
    Label{ text: "invisible" }
}

// CORRECT -- use View, Canvas wraps it in its own ScrollYView
View{ width: Fill height: Fit flow: Down
    Label{ text: "visible" }
}

2. on_after_apply / ScriptHook is NOT called for eval-created widgets

When Splash eval creates a widget (e.g. Markdown{body: "..."}), the ScriptHook::on_after_apply callback is never invoked. Any initialization that depends on on_after_apply must have a fallback path (e.g. lazy init in draw_walk).

3. Type default properties are NOT fully inherited in eval path

When set_type_default() overrides a widget type with extra properties (like use_code_block_widget: true) or named children (like code_block:= View{...}), instances created via Splash eval may not inherit these. The #[live] fields only get values from the eval apply value (e.g. {body: "..."}), not the full type default.

Workaround: Check for missing state in draw_walk and look up the type default via vm.bx.heap.type_default_for_object().

4. Type default vec entries (named children) may not copy to instances

Even though copy_type_default_vec exists, the vec entries from set_type_default() may lose entries between registration and instance creation. The auto-proto vec copy in new_with_proto_impl copies from the direct proto, which may have fewer entries than the type_default.

5. Nested Markdown{} inside Splash works but needs type default templates

When Canvas overrides mod.widgets.Markdown with code_block:= View{CodeView{...}}, and Splash eval creates Markdown{body: "..."}, the code_block template is NOT automatically available. The fix (in widgets/src/markdown.rs) lazily looks up the type default at draw time and registers missing templates.


Debugging Splash

Command-Line Flags

FlagDescription
--hotEnable hot reload: watches script_mod! source files and auto-refreshes UI on save. Only reloads Splash DSL; Rust changes need recompilation.
--stdin-loopStudio mode: communicates with Makepad Studio via stdin/websocket. Used internally by Studio.

Print Debugging

std.println() / std.print() are the primary debugging tools. Output goes to both terminal and Studio's Log View:

std.println("debug: state.counter = " + state.counter)

The ~expression debug log syntax also prints values during evaluation:

~state.counter    // prints the value of state.counter during eval

Makepad Studio Integration

Studio can run Splash scripts directly from the Run List panel (looks for makepad.splash in project root). Script errors appear in the Log View with file path and error details.

When running under Studio, Splash scripts get a hub module:

APIDescription
hub.run(env, cmd, args)Launch subprocess from Splash
hub.set_run_items(items)Register runnable items in Studio's Run List
hub.studio_ipStudio's WebSocket address

Current Limitations

  • No breakpoint debugging -- Splash VM does not support breakpoints or stepping
  • No AST dump flag -- Inspecting parse results requires adding logs in Rust source (script/)
  • Print-based debugging -- std.println() and ~expr are the primary debugging tools

File References

  • Full language manual: splash.md (2559 lines)
  • Migration guide: AGENTS.md (815 lines)
  • Counter example: examples/counter/src/app.rs
  • Todo example: examples/todo/src/app.rs
  • Detailed reference: skills/makepad-2.0-splash/references/splash-language-reference.md
  • Patterns guide: skills/makepad-2.0-splash/references/splash-scripting-patterns.md

Practical Splash Lessons (learned 2026-03-31, from building Vox voice input app)

Lesson 1: instance Fields Cannot Be Added in +: Blocks

The most critical Splash limitation. Adding instance my_var: 0.5 inside a draw_bg +: {} block causes a runtime error: "cannot push to frozen vec".

// WRONG — runtime crash
draw_bg +: {
    instance hover: 0.0          // CRASH: cannot push to frozen vec
    pixel: fn() { ... }
}

// CORRECT — override pixel function only, use built-in variables
draw_bg +: {
    pixel: fn() {
        let t = self.draw_pass.time    // built-in, always available
        return Pal.premul(vec4(t, 0.0, 0.0, 1.0))
    }
}

Workarounds:

  • Use self.draw_pass.time for time-based animation
  • Use self.pos, self.rect_size (always available)
  • For custom instance variables, create a Rust DrawQuad subtype (see makepad-2.0-shaders skill)
  • Use LoadingSpinner widget for simple animated indicators

Lesson 2: Transparent Floating Window Recipe

Creating a truly transparent overlay window requires three things:

my_window := Window{
    show_caption_bar: false
    window.transparent: true             // 1. Window-level transparency
    pass.clear_color: #x00000000         // 2. Render pass clear to fully transparent
    body +: {
        // 3. Do NOT set draw_bg on body — it overrides transparency
        View{
            width: Fill height: Fill
            // Only visible elements show; rest is see-through
        }
    }
}

Common mistakes:

  • Setting only window.transparent: true — window stays opaque (gray background)
  • Setting draw_bg.color: #x00000000 on body — does NOT make it transparent, just black
  • Must also configure as floating panel from Rust: MacosWindowConfig::floating_panel() + Borderless

Reference implementation: Makepad tools/canvas/src/app.rs uses this exact pattern.

Lesson 3: Property Names That Don't Exist

Splash silently ignores unknown properties. These caused us real debugging time:

WrongCorrectNotes
password: trueis_password: trueTextInput password mode
color: #fff on LoadingSpinner(not supported)LoadingSpinner has no color property
window.backdrop: VibrancyWorks, but needs transparent: true tooBackdrop alone doesn't make window transparent

Lesson 4: Emoji Rendering

Makepad's text renderer supports some emoji but not all:

WorksDoesn't Work
🎙 🔍 🔄✨ ⏳

If an emoji shows as a box or garbage character, try a different one. Stick to basic emoji from the BMP (Basic Multilingual Plane).

Lesson 5: width: Fit + Large border_radius = Spiky Shape

RoundedView with border_radius: 28.0 on a height: 56 capsule produces diamond-shaped ends instead of half-circles. The underlying sdf.box() formula breaks when radius >= min(w,h)/2.

Fix: Use a custom SDF capsule shader instead of RoundedView:

View{
    show_bg: true
    draw_bg +: {
        pixel: fn() {
            let r = self.rect_size.y * 0.5
            let px = self.pos.x * self.rect_size.x
            let py = self.pos.y * self.rect_size.y
            let cx = clamp(px, r, max(r, self.rect_size.x - r))
            let d = length(vec2(px - cx, py - self.rect_size.y * 0.5)) - r
            let alpha = 1.0 - smoothstep(-1.0, 1.0, d)
            return Pal.premul(vec4(0.1, 0.1, 0.18, alpha * 0.82))
        }
    }
}

Lesson 6: Multi-Window App — Window Visibility Control

Windows declared in script_mod! auto-show on startup. Makepad WindowRef has no close()/open() method.

Working pattern: Declare windows at normal size. Use configure_window() to bring to front when needed.

// Show: configure_window triggers makeKeyAndOrderFront on macOS
let settings = self.ui.window(cx, ids!(settings_window));
settings.configure_window(cx, dvec2(480.0, 560.0), dvec2(500.0, 200.0), false, "Settings".into());

// Hide: resize to 1x1 (no close/minimize on WindowRef)
let capsule = self.ui.window(cx, ids!(capsule_window));
capsule.resize(cx, dvec2(1.0, 1.0));

Note: reposition(cx, dvec2(-9999, -9999)) does NOT reliably hide macOS floating panels.

Lesson 7: new_batch: true and Widget Z-Order

Adding a LoadingSpinner (or any child widget with its own draw shader) inside a custom-shader View can cause bleed-through at the edges — the child widget draws outside the parent's SDF mask.

Fix: Either:

  1. Draw animation in the parent's own pixel shader (no child widget z-order issues)
  2. Use clip_x: true + clip_y: true on the parent (may not fully solve it)

Lesson 8: Continuous Redraw for Time-Based Shader Animation

self.draw_pass.time in a shader only advances when the widget is redrawn. Without explicit redraw, time freezes.

fn handle_next_frame(&mut self, cx: &mut Cx, _e: &NextFrameEvent) {
    if self.inner.state != STATE_IDLE {
        // Redraw the WINDOW (not just the view) to update draw_pass.time
        self.ui.widget(cx, ids!(my_window)).redraw(cx);
        self.inner.next_frame = cx.new_next_frame();
    }
}

Key: Redraw the Window widget, not just the inner View. The draw pass time is per-window.

Lesson 9: #[rust] Fields with Complex Types in Script-Derived Structs

#[derive(Script, ScriptHook)] structs can only have #[rust] fields whose types implement Default. For complex non-Default types (channels, handles, etc.), wrap them in an Inner struct:

#[derive(Default)]
struct Inner {
    timer: Timer,
    rx: Option<crossbeam_channel::Receiver<u64>>,
    handle: Option<SomeNonDefaultHandle>,
}

#[derive(Script, ScriptHook)]
pub struct App {
    #[live] ui: WidgetRef,
    #[rust] inner: Inner,    // Single Default-able wrapper
}

平台分布

Codex

32.93%
按下载量换算31

Claude

33.09%
按下载量换算31

Cursor

19.28%
按下载量换算18

Gemini CLI

8.68%
按下载量换算8

安全审计

暂无安全审计结果可展示。

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills