Skip to main content

makepad-2-0-shaders

CRITICAL: Use for Makepad 2.0 shader system. Triggers on: makepad shader, Sdf2d, pixel shader, draw_bg, draw_text, draw_quad, makepad gpu, shader function, pixel fn, vertex fn, instance, uniform, shader variable, sdf, premultiply, Pal.premul, GaussShadow, makepad graphics, custom draw, DrawQuad, DrawVector, 着色器, 像素, 渲染, 自定义绘制, 距离场

インストールへ移動

ソース情報

リポジトリ
ZhangHanDong/makepad-skills
ソースの最終更新活動
2026年4月4日 17:48
検出された SKILL.md の言語
英語
スター
748
フォーク
87

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
3 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
makepad-2.0-shaders
description
CRITICAL: Use for Makepad 2.0 shader system. Triggers on: makepad shader, Sdf2d, pixel shader, draw_bg, draw_text, draw_quad, makepad gpu, shader function, pixel fn, vertex fn, instance, uniform, shader variable, sdf, premultiply, Pal.premul, GaussShadow, makepad graphics, custom draw, DrawQuad, DrawVector, 着色器, 像素, 渲染, 自定义绘制, 距离场
# Makepad 2.0 Shader Skill > **Version:** makepad-widgets (dev branch) | **Last Updated:** 2026-03-03 ## Overview Makepad uses a custom GPU shader system integrated into the widget property tree. Shaders are defined inline using `pixel: fn() { ... }` and `vertex: fn() { ... }` blocks within `draw_bg`, `draw_text`, or custom draw objects. ## Documentation Refer to the local files for detailed documentation: - `./references/shader-reference.md` - Shader syntax, variables, built-ins, custom functions - `./references/sdf2d-reference.md` - SDF2D primitives, combinators, drawing operations --- ## Shader Basics ### Pixel Shader Structure ``` draw_bg +: { // Declare variables instance hover: 0.0 // Animatable per-instance uniform accent: #4488ff // Shared across all instances pixel: fn() { let sdf = Sdf2d.viewport(self.pos * self.rect_size) // ... SDF operations ... return sdf.result } } ``` ### Variable Types | Type | Declaration | Animatable | Scope | |------|-------------|-----------|-------| | `instance` | `instance hover: 0.0` | Yes (via Animator) | Per-widget instance | | `uniform` | `uniform color: #fff` | No | Shared across instances | | `texture_2d` | `texture_2d tex: none` | No | Texture sampler | | `varying` | `varying uv: vec2` | No | Vertex → fragment | ### Built-in Variables | Variable | Type | Description | |----------|------|-------------| | `self.pos` | `vec2` | Normalized position (0.0 to 1.0) | | `self.rect_size` | `vec2` | Widget size in pixels | | `self.dpi_factor` | `float` | Screen DPI factor | | `self.draw_pass.time` | `float` | Time in seconds | --- ## CRITICAL: Premultiply Alpha **Every pixel shader MUST return premultiplied alpha color!** ``` // WRONG - non-premultiplied pixel: fn() { return vec4(1.0, 0.0, 0.0, 0.5) } // CORRECT - use Pal.premul() pixel: fn() { return Pal.premul(vec4(1.0, 0.0, 0.0, 0.5)) } // ALSO CORRECT - sdf.result is already premultiplied pixel: fn() { let sdf = Sdf2d.viewport(self.pos * self.rect_size) sdf.circle(cx, cy, r) sdf.fill(#f00) return sdf.result } ``` --- ## SDF2D Quick Reference ### Setup ``` let sdf = Sdf2d.viewport(self.pos * self.rect_size) ``` ### Primitives ``` sdf.circle(cx, cy, radius) sdf.rect(x, y, w, h) sdf.box(x, y, w, h, border_radius) sdf.hexagon(cx, cy, radius) sdf.arc(cx, cy, radius, start_angle, end_angle, thickness) sdf.move_to(x, y) sdf.line_to(x, y) sdf.close_path() ``` ### Drawing ``` sdf.fill(color) // Filled shape sdf.stroke(color, width) // Outlined shape sdf.glow(color, amount) // Glow effect sdf.clear(color) // Clear with color ``` ### Combinators ``` sdf.union() // Add shapes together sdf.intersect() // Keep overlap only sdf.subtract() // Remove second from first sdf.gloop(radius) // Smooth union sdf.blend(amount) // Linear blend ``` ### Transforms ``` sdf.translate(x, y) sdf.rotate(angle, cx, cy) sdf.scale(factor, cx, cy) ``` --- ## Color Operations ``` // Mix two colors mix(#f00, #00f, 0.5) // 50% blend // Premultiply alpha Pal.premul(vec4(r, g, b, a)) // HSV conversions Pal.hsv2rgb(vec4(h, s, v, 1.0)) Pal.rgb2hsv(color) // Random Math.random_2d(vec2(x, y)) ``` --- ## Common Shader Patterns ### Gradient Background ``` draw_bg +: { pixel: fn() { let grad = mix(#1a1a2e, #16213e, self.pos.y) return Pal.premul(vec4(grad.xyz, 1.0)) } } ``` ### Hover Color Change ``` draw_bg +: { instance hover: 0.0 color: #333 pixel: fn() { return Pal.premul(mix(self.color, self.color * 1.3, self.hover)) } } ``` ### Box Shadow ``` draw_bg +: { pixel: fn() { let sdf = Sdf2d.viewport(self.pos * self.rect_size) // Shadow sdf.box(2.0, 2.0, self.rect_size.x - 4.0, self.rect_size.y - 4.0, 8.0) sdf.fill(GaussShadow.box_shadow(sdf, 4.0, #0005)) // Card sdf.box(0.0, 0.0, self.rect_size.x - 2.0, self.rect_size.y - 2.0, 8.0) sdf.fill(#2a2a3d) return sdf.result } } ``` ### Rounded Button with States ``` draw_bg +: { instance hover: 0.0 instance down: 0.0 uniform color_bg: #4488ff uniform color_hover: #5599ff uniform color_down: #3377ee pixel: fn() { let sdf = Sdf2d.viewport(self.pos * self.rect_size) sdf.box(0.0, 0.0, self.rect_size.x, self.rect_size.y, 6.0) let color = mix(self.color_bg, self.color_hover, self.hover) let color = mix(color, self.color_down, self.down) sdf.fill(color) return sdf.result } } ``` --- ## Custom Shader Functions ``` draw_bg +: { fn wave(pos: vec2, time: float) -> float { return sin(pos.x * 10.0 + time * 3.0) * 0.1 } pixel: fn() { let w = self.wave(self.pos, self.draw_pass.time) let color = mix(#1a1a2e, #4488ff, self.pos.y + w) return Pal.premul(vec4(color.xyz, 1.0)) } } ``` --- ## Splash Shader Capability Boundary **Splash CAN:** - Override `pixel: fn()`, `vertex: fn()`, `get_color: fn()` on existing draw types via `+:` - Define helper shader functions within `+:` blocks - Set instance/uniform variables on existing draw types - Use all SDF2D, color, math built-ins in shader functions **Splash CANNOT:** - Create new DrawQuad/DrawText/DrawSvg types (must define in Rust) - Add new instance fields to existing shaders (GPU layout is compile-time) **Rule:** Rust defines the draw type struct + registers it; Splash overrides how it draws. See `./references/shader-reference.md` "Splash Shader Capabilities & Boundaries" for the full pattern. --- ## Custom Fullscreen Shader Pattern (learned 2026-03-26) For standalone shader-driven widgets (e.g. particle fields, visualizers), follow the `examples/shader` pattern: ### 1. Custom Draw Type (Rust) ```rust #[derive(Script, ScriptHook)] #[repr(C)] // CRITICAL: must be repr(C) for GPU layout pub struct DrawMyShader { #[deref] draw_super: DrawQuad, // inherits from DrawQuad #[live] my_param: f32, // maps to shader variable } ``` ### 2. Register + Define Shader (script_mod!) ``` set_type_default() do #(DrawMyShader::script_shader(vm)){ ..mod.draw.DrawQuad // inherit DrawQuad defaults my_param: 0.5 // default value // Custom functions: property-style syntax, NOT fn name(self, ...) my_helper: fn(a: float, b: float) -> vec2 { return vec2(a * 2.0, b * 0.5) } pixel: fn() { let result = self.my_helper(self.pos.x, self.pos.y) return Pal.premul(vec4(result.x, result.y, 0.0, 1.0)) } } ``` ### 3. Widget with Turtle Layout ```rust fn draw_walk(&mut self, cx: &mut Cx2d, _: &mut Scope, walk: Walk) -> DrawStep { cx.begin_turtle(walk, self.layout); let rect = cx.turtle().rect(); self.draw_bg.draw_abs(cx, rect); // single fullscreen quad cx.end_turtle_with_area(&mut self.area); DrawStep::done() } ``` ### 4. Updating Shader Variables from Rust ```rust // Direct field access (when draw type has #[live] fields): self.draw_bg.my_param = 0.75; self.area.redraw(cx); // Via NextFrame for animation: if let Event::NextFrame(ne) = event { if ne.set.contains(&self.next_frame) { self.draw_bg.my_param += 0.01; self.area.redraw(cx); self.next_frame = cx.new_next_frame(); } } ``` --- ## Instanced Particle Rendering (learned 2026-03-26) For drawing thousands of independent particles (dots, stars, etc.): ### Draw Shader ```rust #[derive(Script, ScriptHook)] #[repr(C)] pub struct DrawDot { #[deref] draw_super: DrawQuad, #[live] dot_color: Vec3, // per-instance color } ``` ``` // Shader: each instance is a small circle pixel: fn() { let d = length(self.pos - vec2(0.5, 0.5)) let alpha = 1.0 - smoothstep(0.35, 0.5, d) return Pal.premul(vec4(self.dot_color * alpha, alpha)) } ``` ### Rendering Loop ```rust self.draw_dot.begin_many_instances(cx); // start batch for i in 0..particles.len() { let (x, y) = particles[i]; self.draw_dot.dot_color = vec3(r, g, b); // set per-instance data self.draw_dot.draw_abs(cx, Rect { pos: dvec2(x - radius, y - radius), size: dvec2(radius * 2.0, radius * 2.0), }); } self.draw_dot.end_many_instances(cx); // submit batch as one draw call ``` ### Physics Pattern (spring-back displacement) ```rust // Per particle: store persistent displacement displacements: Vec<(f64, f64)>, // Each frame: for i in 0..dots.len() { let (mut dx, mut dy) = displacements[i]; // 1. Decay (spring back, 0.94 = ~2-3 sec return) dx *= 0.94; dy *= 0.94; // 2. Apply forces (cursor push, ripples, etc.) let dist = distance(dot_pos, mouse_pos); let t = (1.0 - dist / radius).max(0.0); let push = t * t * t * strength; // cubic falloff dx += direction.x * push; dy += direction.y * push; displacements[i] = (dx, dy); // Draw at original_pos + displacement } ``` ### Performance Notes - 10,000 particles at 60fps: OK on macOS Metal (one draw call via instancing) - CPU physics loop: 10K × 17 distance checks = ~170K ops/frame, negligible - Key: `begin_many_instances` / `end_many_instances` batches into single GPU draw call ---
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る