agentleFS
dylanroscoverdylanroscover/Embody/.claude/skills/glsl-shaders/SKILL.md

glsl-shaders

Skill213 starsChanged 2 months agoMITView on GitHub

MUST READ before writing GLSL or creating a glslTOP, glslmultiTOP, glslMAT or glslPOP: docked DATs, uniforms and the Colors page, TD's built-in functions and samplers, feedback and multi-pass, reading compile errors. Every built-in named here compiled on TD 2025.33230.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read compile results from <name>_info: op.errors() says only "Compile failed".

    line 17
  2. Very specific:

    Verify by looking: capture_top the output (a Quality: FAIL is a black or flat frame) and read <name>_info after every edit.

    line 69

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md
<!-- Generated by Embody/Envoy - Do not remove this comment - sha:ba697c6b4d3a77c7 -->

GLSL Shaders

Three hosts: glslTOP/glslmultiTOP (pixels, or compute over an image), glslMAT (vertex + pixel over geometry), glslPOP (compute over points; the POP side lives in /pop-networks). Every function and parameter below compiled live on TD 2025.33230 (probed 2026-09-25). Anything you add beyond them: check the parameter with describe_op_type and the function with the docked info DAT before trusting it.

The docked-DAT contract

  • Creating a glslTOP/glslmultiTOP docks <name>_pixel, <name>_compute, <name>_info, with pixeldat/computedat already pointing at them. A glslMAT docks <name>_vertex, <name>_pixel, <name>_info (vdat/pdat). A glslPOP docks <name>_compute and <name>_info.
  • Name the operator at creation (glsl_<purpose>): dock names and the *dat references are snapshots taken then and do not follow a later rename.
  • Write the shader INTO the docked DAT (set_dat_content / edit_dat_content). Delete the dock you do not use (_compute for a pixel shader) so it does not ship as dead weight. One exception: several GLSL ops running identical code point at ONE shared DAT and differ by uniforms (tdxn-economy.md).
  • create_op hugs the docks under the host; an execute_python build must place them itself (/create-operator).
  • Read compile results from <name>_info: op.errors() says only "Compile failed". get_op_errors returns them as shaderErrors, and every DAT write to a shader rides back _effects.new_shader_errors. Fix those before building further.

What TD gives you (never redeclare, never paste an alternative)

  • No #version line: TD injects one, and writing your own fails with "'#version' : must occur first in shader". texture(), never texture2D() ("function not supported in this version; use texture() instead").
  • Inputs: sTD2DInputs[i], sTD3DInputs[i], sTD2DArrayInputs[i], sTDCubeInputs[i], indexed per TYPE, not per connector. TD_NUM_2D_INPUTS (and the 3D/array/cube twins) bound a loop and guard a dynamic index. uTD2DInfos[i].res and uTDOutputInfo.res are (1/w, 1/h, w, h). vUV.st is the 0-1 texture coordinate when there is no custom vertex shader. uTDPass is the multi-pass index, uTDCurrentDepth the 3D slice.
  • Lookups: sTDNoiseMap (256x256 random), sTDSineLookup.
  • Functions: TDOutputSwizzle(vec4) on EVERY color you write out (channel order is wrong without it), TDDither, TDPerlinNoise(vec2|vec3|vec4) and TDSimplexNoise(vec2|vec3|vec4) (both in -1..1, available in TOP, MAT and glslPOP shaders on this build), TDHSVToRGB, TDRGBToHSV, TDRotateOnAxis(rad, axis), TDRotateX/Y/Z(rad).
  • Compute in a glslTOP (mode=compute): declare layout(local_size_x = 8, local_size_y = 8) in;, write with TDImageStoreOutput(0, ivec3(gl_GlobalInvocationID.xy, 0), TDOutputSwizzle(color)), read the output back with TDImageLoadOutput(0, ivec3(...)).
  • glslTOP has exactly 3 input connectors. glslmultiTOP takes more and adds POP buffer reads (buffer0pop, buffer0attr, buffer0name -> TDBuffer_<Name>(idx) in the shader). Reach for glslmultiTOP whenever you need a fourth input or a POP attribute.

Uniforms

  • Vectors page: vec0name + vec0valuex/y/z/w, a sequence (grow it with op.seq.vec.numBlocks = N). On a TOP or MAT the SHADER declares the uniform and TD infers the type from the declaration (uniform vec4 uParams;); there is no vec0type here, and an undeclared name silently reads nothing. Pack four values per vec; the values take expressions (absTime.seconds * parent.Fx.par.Speed).
  • Colors page: color0name + color0rgbr/g/b + color0alpha -> uniform vec4 uTint; with a colour swatch in the dialog. Use it for colours instead of a raw vec.
  • Constants page: const0name/const0value are baked in at compile time, so every change RECOMPILES the shader. Runtime values belong on Vectors; constants only for true compile-time switches.
  • glslPOP inverts one rule: its uniforms are AUTO-DECLARED from the Vectors page (uniform highp float uSpeed; by default). Declaring them again is a "Redeclaration" error, and the type comes from vec0type (float, vec2..vec4, int, uint, ...). Samplers, Arrays, Matrices and Buffers pages follow the same shape on every host.

Pixel shader minimum

uniform vec4 uParams;           // Vectors page: vec0name = uParams
layout(location = 0) out vec4 fragColor;
void main() {
    vec4 c = texture(sTD2DInputs[0], vUV.st);
    fragColor = TDOutputSwizzle(c * uParams.x);
}

Output format and resolution are parameters, not shader code: format (rgba8fixed clamps to 0-1 -- data, feedback and HDR need rgba16float or rgba32float), outputresolution (useinput, custom with resolutionw/resolutionh, fit, ...). There is no resolution parameter. premultrgbbyalpha defaults ON and multiplies RGB by your alpha -- turn it off on an op whose alpha carries data. Multiple render targets: numcolorbufs, declare layout(location = 1) out vec4 fragField;, and pull buffer N with a Render Select TOP (set its format to float).

glslMAT

One combined DAT with #ifdef TD_VERTEX_SHADER / #ifdef TD_PIXEL_SHADER guards, set as BOTH vdat and pdat; keep _info.

  • Vertex: TDDeform(TDPos()) gives the world position (never raw TDPos() -- instancing and deformers ride on TDDeform), TDDeformNorm(TDNormal()) the world normal, TDWorldToProj(worldPos) is gl_Position, TDCameraIndex() goes out as a flat int varying, TDPointColor() / TDInstanceColor(c) carry point and instance colour.
  • Pixel: TDCheckDiscard() first; uTDMats[cam].camInverse[3].xyz is the camera position; loop TD_NUM_LIGHTS with TDLightingPBR(i, diffuseColor, specularColor, worldPos, normal, shadowStrength, shadowColor, viewDir, roughness) (a TDPBRResult with .diffuse/.specular) and TD_NUM_ENV_LIGHTS with TDEnvLightingPBR(inout diffuse, inout specular, i, diffuseColor, specularColor, normal, viewDir, roughness, ambientOcclusion); TDFog(color, worldPos, cam); then TDOutputSwizzle(TDDither(color)) into oFragColor[0], declared layout(location = 0) out vec4 oFragColor[TD_NUM_COLOR_BUFFERS];.
  • Transparency needs blending ON and honest srcblend/destblend (one, zero, sa, omsa, ...) with the alpha pair srcblenda/destblenda; cullface=neither shows both faces of filled POP geometry.
  • Extending a PBR look: start from a pbrMAT and pulse outputshader -- TD writes its own vertex and pixel code into a new glslMAT for you to edit.

Feedback and multi-pass

  • Feedback: Constant TOP (clear) -> Feedback TOP -> glsl -> Null TOP; the Feedback TOP's top names the null that closes the loop, resetpulse resets it. Close the loop BEFORE compiling shaders that depend on the fed-back texture. Bound every loop per performance.md: fixed resolution inside it, decay below 1, reset wired, bypassed while wiring.
  • One feedback is one iteration per frame. Iterative solvers use npasses on the GLSL op instead: pass N+1 sees pass N on input 0, uTDPass tells you which.
  • 3D output: type=texture3d, depth=custom, customdepth=N; the shader runs once per slice with uTDCurrentDepth. constantTOP and noiseTOP have no customdepth, so seed a volume from a small glslTOP, not from them.

Discipline

  • A built-in operator beats a shader when one exists (Noise, Ramp, Lookup, Composite, Level TOPs; Math and Lookup CHOPs). GLSL is for what they cannot express: advection, solvers, custom lighting, per-point compute.
  • Bound every loop with a constant and guard dynamic sampler or array indexes with TD_NUM_*: an out-of-bounds index can take TD down (/td-api-reference, Heavy-Build Safety).
  • centroid is a reserved word in GLSL 4.60. me.time.step does not exist: delta time is absTime.stepSeconds (or 1.0 / me.time.rate).
  • Externalize shader DATs with externalize_op (tag glsl) so they diff in git; edit the file, TD recompiles.
  • Verify by looking: capture_top the output (a Quality: FAIL is a black or flat frame) and read <name>_info after every edit. A shader that compiles and renders TD's fallback pattern still reads as an error in the info DAT.

Topics cross-checked against Derivative's TDMCPSkills td-glsl-shaders with permission; every claim above was recompiled live on 2025.33230 before it was written down.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.