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, 着色器, 像素, 渲染, 自定义绘制, 距离场

Ir para a instalação

Informações da origem

Repositório
ZhangHanDong/makepad-skills
Última atividade na origem
4 de abril de 2026 às 17:48
Idioma detectado do SKILL.md
inglês
Estrelas
750
Forks
88

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
3 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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 ---
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub