{"id":"shader--gpu-checker","name":"Make choices per pixel","owner":"yeho","package":"examples.gpu-shaders","kind":"shader","signature":"[gpu] compute Paint(buffer of int pixels, int width, int height, float time)","description":"Use integer cells and a branch to paint a crisp two-color checker.","context":"Every pixel can make its own decision. A GPU branch is still ordinary if logic, subject to the compute provider’s admitted subset.","parameters":[],"returns":"","members":[],"tags":["complete-program","compute","gpu","image","shader","yeho"],"updated":"2026-09-09","source":{"repository":"demonhunterlabs","path":"app/lib/yeho-gpu-shaders.ts","sha256":"b90b7f5c4d2972b6acdd763cc6b27a547bf8c74de763fbebd390fde9afda6076"},"status":"native-metal-example","notes":["Change both divisors from 16 to 8. Try replacing the teal values with a warm orange.","The dedicated shader verifier executes this program on Metal and compares every output channel with a separate CPU reference. Evidence: https://demonhunterlabs.com/learning/gpu-shaders/verification.json","The program writes shader.ppm in its current directory. Native image generation is separate from presenting frames in a game window."],"examples":[{"id":"complete","title":"03 / Make choices per pixel","description":"Use integer cells and a branch to paint a crisp two-color checker.","code":"[gpu]\ncompute Paint(buffer of int pixels, int width, int height, float time)\n{\n    int index = compute.index\n    if index >= pixels.count { return }\n    int row = index / width\n    int column = index - row * width\n    float u = Math.IntToFloat(column) / Math.IntToFloat(width - 1)\n    float v = Math.IntToFloat(row) / Math.IntToFloat(height - 1)\n    int cellX = column / 16\n    int cellY = row / 16\n    int sum = cellX + cellY\n    float r = 0.02\n    float g = 0.04\n    float b = 0.08\n    if sum / 2 * 2 == sum\n    {\n        r = 0.08\n        g = 0.9\n        b = 0.7\n    }\n    int red = Math.RoundToInt(Math.ClampFloat(r, 0.0, 1.0) * 255.0)\n    int green = Math.RoundToInt(Math.ClampFloat(g, 0.0, 1.0) * 255.0)\n    int blue = Math.RoundToInt(Math.ClampFloat(b, 0.0, 1.0) * 255.0)\n    pixels[index] = red * 65536 + green * 256 + blue\n}\n\n// CPU: allocate an image and submit one GPU invocation per pixel.\nint width = 128\nint height = 128\nbuffer of int pixels\npixels.Resize(width * height)\ncomputeTask job = dispatch Paint(pixels, width, height, 0.0)\nwait job\nif job.failed { Console.Error(job.error.message) Process.Exit(1) }\n\n// CPU: save the completed RGB pixels as a portable PPM image.\ntext image = \"P3\\n\" + Text.From(width) + \" \" + Text.From(height) + \"\\n255\\n\"\nfor row from 0 < height\n{\n    text line = \"\"\n    for column from 0 < width\n    {\n        int pixel = pixels[row * width + column]\n        int red = pixel / 65536\n        int green = (pixel - red * 65536) / 256\n        int blue = pixel - red * 65536 - green * 256\n        line = line + Text.From(red) + \" \" + Text.From(green) + \" \" + Text.From(blue) + \" \"\n    }\n    image = image + line + \"\\n\"\n}\nFile.WriteText(\"shader.ppm\", image)\nConsole.Log(\"Wrote shader.ppm\")\n","manifest":"manifestVersion = \"2\"\npackage = \"learning.shaders.gpu_checker\"\nversion = \"0.1.0\"\nlanguageEdition = \"yeho-core-2026.1\"\n\n[app]\nkind = \"headless\"\n","tags":["gpu","shader","image"],"run":"metal","expected":"Wrote shader.ppm","verification":"type checked","sha256":"be775fef91382bb2c38ba8e338890a6ead5c6a0ed98c279c7792900ff42fd4f7","checked":"2026-09-09","diagnostic":"","observedOutput":null,"checkedBackend":null}],"searchTerms":[],"url":"https://demonhunterlabs.com/academy/api?item=shader--gpu-checker","json":"https://demonhunterlabs.com/reference/items/shader--gpu-checker.json","markdown":"https://demonhunterlabs.com/reference/text/shader--gpu-checker.md"}
