
flutter-shader
by moinsen-dev
This project demonstrates the power of **Claude Code Skills** — a way to teach Claude specialized knowledge that it can apply automatically. The entire festive shader application you see here was built by Claude using a custom skill for Flutter fragment shader development.
SKILL.md
name: flutter-shader description: Develop Flutter fragment shaders (GLSL) end-to-end. Use when creating, debugging, or integrating custom shaders in Flutter apps. Triggers on shader, GLSL, fragment shader, CustomPainter with shader, ShaderMask, visual effects, procedural graphics, or GPU rendering in Flutter.
Flutter Fragment Shader Development
Comprehensive guide for building, integrating, debugging, and shipping Flutter fragment shaders using Flutter's FragmentProgram / FragmentShader APIs.
Scope and Capabilities
What Flutter Supports
- Fragment shaders (pixel shaders) only - vertex shaders are NOT supported
- Core runtime objects:
FragmentProgram: compiled shader asset that creates shader instancesFragmentShader: instance with uniforms bound toPaint.shader
Backend Awareness
Flutter runs with Skia or Impeller backends:
- Both support custom shaders
ImageFilter.shaderis Impeller-only- Performance characteristics differ between backends
Project Setup Checklist
1. File Structure
/shaders/
my_effect.frag
/lib/
shaders/
widgets/
2. Declare in pubspec.yaml
flutter:
shaders:
- shaders/my_effect.frag
3. Hot Reload
In debug mode, shader edits trigger recompilation on hot reload/restart.
GLSL Authoring Rules
Required Header
#version 460 core
#include <flutter/runtime_effect.glsl>
out vec4 fragColor;
Coordinate Access
Use FlutterFragCoord() instead of gl_FragCoord:
vec2 p = FlutterFragCoord().xy / u_size;
Key Limitations
- Only
sampler2D(no samplerCube, etc.) - Only
texture(sampler, uv)two-argument form - No extra varying inputs
- No UBO/SSBO
- No unsigned ints or booleans
OpenGLES Y-Flip Fix
When sampling engine textures on OpenGLES:
vec2 uv = FlutterFragCoord().xy / u_size;
#ifdef IMPELLER_TARGET_OPENGLES
uv.y = 1.0 - uv.y;
#endif
Uniform Indexing Rules
Rule 1: Float uniforms use declaration order
float, vec2, vec3, vec4 set via setFloat(index, value) in declaration order.
Rule 2: Samplers have separate index space
sampler2D set via setImageSampler(samplerIndex, image) - does NOT consume float indices.
Example
uniform float uScale; // setFloat(0, ...)
uniform sampler2D uTexture; // setImageSampler(0, ...) - separate!
uniform vec2 uMagnitude; // setFloat(1, x), setFloat(2, y)
uniform vec4 uColor; // setFloat(3..6, r,g,b,a)
shader.setFloat(0, 23); // uScale
shader.setFloat(1, 114); // uMagnitude.x
shader.setFloat(2, 83); // uMagnitude.y
shader.setFloat(3, r); // uColor.r
shader.setFloat(4, g); // uColor.g
shader.setFloat(5, b); // uColor.b
shader.setFloat(6, a); // uColor.a
shader.setImageSampler(0, image); // uTexture
Loading and Using Shaders
Load Program
final program = await FragmentProgram.fromAsset('shaders/my_effect.frag');
Create and Bind Uniforms
final shader = program.fragmentShader();
shader.setFloat(0, timeSeconds);
shader.setFloat(1, width);
shader.setFloat(2, height);
Draw with Shader
canvas.drawRect(rect, Paint()..shader = shader);
ImageFilter (Impeller-only)
ImageFilter.shader(shader) // Only works on Impeller!
Development Workflow
Step 1: Write Shader Spec
Define before coding:
- Inputs (uniforms):
u_time,u_size, effect parameters - Texture sampling requirements
- Application context: full-screen, mask, backdrop
Step 2: Establish Uniform Contract
Consistent ordering convention:
uniform vec2 u_size;uniform float u_time;- Effect parameters...
Mirror in Dart with constants for indices.
Step 3: Create Integration Wrapper
Choose pattern:
CustomPainter- drawing into CanvasShaderMask- masking child contentBackdropFilter/ImageFiltered- post-processing (Impeller-only)
Step 4: Performance Optimization
- Reuse
FragmentShaderinstances - don't recreate each frame - Precache
FragmentProgrambefore animations start - SkSL warm-up for Skia backend jank mitigation
- Use Impeller where available (precompiles at build-time)
Step 5: Cross-Platform Testing
Test on:
- Android (OpenGLES/Vulkan)
- iOS (Metal)
- Web (CanvasKit/skwasm)
Debugging Guide
Black Screen Diagnosis
- Check
fragColoris written - Verify coordinate normalization (divide by size)
- Audit uniform index mapping
Uniform Layout Inspection
Use impellerc + flatc for reflection data on uniform offsets.
Backend Errors
ImageFilter.shader throws on non-Impeller backends.
Additional Resources
- TEMPLATES.md - Copy-paste shader starter kits
- REFERENCE.md - Complete API and troubleshooting guide
Quick Reference
| Task | Tool/Pattern |
|---|---|
| Load shader | FragmentProgram.fromAsset() |
| Create instance | program.fragmentShader() |
| Set float uniform | shader.setFloat(index, value) |
| Set texture | shader.setImageSampler(index, image) |
| Draw to canvas | Paint()..shader = shader |
| Post-process | ImageFilter.shader() (Impeller) |
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


