scenario-godot-shaders

Installation
SKILL.md

Godot shaders (technical artist, shading)

Target: Godot 4.7.2.stable, macOS Apple Silicon (Metal by default, Vulkan through MoltenVK for GPU timing).

Expert level here means every shader is text the agent can diff, compiled under each target renderer, drawn on a real mesh in a window, swept across its parameters and looked at on a contact sheet, with its GPU cost measured against a StandardMaterial3D baseline. Compiling is not the same as working: several 4.7.2 failures only appear when the backend draws, and several bugs produce no error at all. If a sibling skill named here is missing from your available skills, ask the user to install it (npx skills add scenario-labs/skills --skill <name>); unattended, proceed from tool schemas and flag the gap.

REQUIRED BACKGROUND: scenario-godot-expert (channels, gd_run, the review loop, 4.7 traps).

Stance (the expert delta)

  1. Code first, graphs on request. Text shaders give loops, functions, #include and clean diffs (Godotneers, Shaderland [01:10:09]; Daniel Ilett on the gaps of VisualShader). When a human wants a graph, build the VisualShader in code (add_node, connect_nodes, an Expression node for the maths) and save it as .tres; port names are not exposed to GDScript, so output indices are hard-coded and checked by reading get_code() [added, run 2026-10-02].
  2. Compile headless, then draw windowed. Headless get_shader_uniform_list() catches language errors per --rendering-method in about 0.4 s per renderer. Stencil reads in the opaque pass and fog shaders under Compatibility only fail when a window draws them. Uninitialized locals and DEPTH written in one branch never fail at all, so the linter checks those [added, run 2026-10-02].
  3. World or object space beats mesh UVs. Dissolve, wind, water and triplanar effects should be driven from object-space or world-space coordinates, so seams and UV stretch disappear (StayAtHomeDev dissolve [00:09:59], DevPoodle triplanar, Dylearn grass). For a shared material, put the per-object values (bounds, amount) in instance uniforms, or each mesh dissolves at the wrong height [added].
  4. Water that does not slide. Use two panned copies of one seamless cellular noise, multiply them, raise to 1.25, and share them between vertex() and fragment() so the crests sit on the wave tops (Bramwell [00:11:57 to 00:20:57]). Use hybrid toon bands, a smoothstep only near each cut, so the bands do not flicker (Dylearn [00:13:42]). Shore foam comes from vertical depth, reconstructed from the depth texture with the reversed-z formula [added].
  5. HDR edges need three things together: a color above 1.0, the EMISSION output, and Glow in the WorldEnvironment (StayAtHomeDev [00:07:36], Daniel Ilett [00:10:22], Pixezy [00:06:55]).
  6. Know what moves a material to the transparent pass. Writing ALPHA or reading the screen or depth texture moves it there. It loses shadows and sorting, and it is invisible to other screen-reading materials (docs). Use ALPHA_SCISSOR_THRESHOLD for dissolves: the material stays opaque and the shadow dissolves too. Scissor is still an alpha test: like discard, it gives up early-Z for that mesh (docs), which costs most on mobile tile GPUs, so swap the dissolve material in only for the effect (P18). Stencil readers must be transparent, with a render_priority above the writer's (LowQualityCoding [00:07:35]).
  7. Compute: on screen, stay on the main device. Texture2DRD needs the main RenderingDevice inside RenderingServer.call_on_render_thread, and no submit or sync (The Pathfinders Codex [00:03:07]). To get results back on the CPU, use a local device, free every RID and test parity against a CPU version (DevPoodle [00:02:21], Crigz [00:11:24]).
  8. Bake shaders from a windowed export. The shader baker runs only when the export process has a rendering device. A --headless export with shader_baker/enabled=true silently packs nothing extra [added, run 2026-10-02].
Installs
63
GitHub Stars
1.0K
First Seen
12 days ago