here2share

WebGPU Rainbow Spiral

Oct 12th, 2026
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 4.00 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>WebGPU Rainbow Spiral</title>
  6. <style>
  7.   body { background:#111; color:white; font-family:monospace; }
  8.   #log { white-space:pre; margin-top:10px; }
  9. </style>
  10. </head>
  11. <body>
  12. <canvas id="c" width="1280" height="1280"></canvas>
  13. <div id="log"></div>
  14.  
  15. <script>
  16. const W = 1280, H = 1280;
  17. const log = document.getElementById("log");
  18. function out(m){ log.textContent += m + "\n"; }
  19.  
  20. const SHADER = `
  21. const palette = array<vec3f, 19>(
  22.     vec3f(255.0, 0.0, 0.0), vec3f(255.0, 64.0, 0.0), vec3f(255.0, 128.0, 0.0),
  23.     vec3f(255.0, 192.0, 0.0), vec3f(255.0, 255.0, 0.0), vec3f(192.0, 255.0, 0.0),
  24.     vec3f(128.0, 255.0, 0.0), vec3f(0.0, 255.0, 0.0), vec3f(0.0, 255.0, 128.0),
  25.     vec3f(0.0, 255.0, 192.0), vec3f(0.0, 255.0, 255.0), vec3f(0.0, 192.0, 255.0),
  26.     vec3f(0.0, 128.0, 255.0), vec3f(0.0, 64.0, 255.0), vec3f(64.0, 0.0, 255.0),
  27.     vec3f(128.0, 0.0, 255.0), vec3f(192.0, 0.0, 255.0), vec3f(255.0, 0.0, 255.0),
  28.     vec3f(255.0, 0.0, 128.0)
  29. );
  30.  
  31. @vertex fn vs_main(@builtin(vertex_index) idx : u32) -> @builtin(position) vec4f {
  32.     var pos = array<vec2f, 3>(
  33.         vec2f(-1.0, -1.0),
  34.         vec2f(3.0, -1.0),
  35.         vec2f(-1.0, 3.0)
  36.     );
  37.     return vec4f(pos[idx], 0.0, 1.0);
  38. }
  39.  
  40. @fragment fn fs_main(@builtin(position) coord: vec4f) -> @location(0) vec4f {
  41.     let cx = 640.0;
  42.     let cy = 640.0;
  43.  
  44.     let dx = coord.x - cx;
  45.     let dy = coord.y - cy;
  46.  
  47.     let r = sqrt(dx*dx + dy*dy);
  48.     if (r > 1000.0 || r < 1.0) {
  49.        return vec4f(0.0, 0.0, 0.0, 0.0);
  50.    }
  51.  
  52.    let angle_deg = 2000.0 - (2.0 * r);
  53.    let angle_rad = angle_deg * 3.1415926535 / 180.0;
  54.  
  55.    var local_angle = atan2(dy, dx);
  56.    if (local_angle < 0.0) {
  57.        local_angle += 2.0 * 3.1415926535;
  58.    }
  59.  
  60.    var source_angle = (local_angle - angle_rad) % (2.0 * 3.1415926535);
  61.    if (source_angle < 0.0) {
  62.        source_angle += 2.0 * 3.1415926535;
  63.    }
  64.  
  65.    let idx = i32(floor(source_angle / ((2.0 * 3.1415926535) / 19.0))) % 19;
  66.    return vec4f(palette[idx] / 255.0, 1.0);
  67. }
  68. `;
  69.  
  70. async function main() {
  71.    out("navigator.gpu = " + !!navigator.gpu);
  72.    if (!navigator.gpu) { out("WebGPU not available in this browser"); return; }
  73.  
  74.    const adapter = await navigator.gpu.requestAdapter();
  75.    if (!adapter){ out("adapter null"); return; }
  76.    out("adapter OK");
  77.  
  78.    const device = await adapter.requestDevice();
  79.    out("device OK");
  80.  
  81.    const module = device.createShaderModule({ code: SHADER });
  82.    const ci = await module.getCompilationInfo();
  83.    for (const m of ci.messages) out("[WGSL " + m.type + "] L" + m.lineNum + ": " + m.message);
  84.    if (ci.messages.length === 0) out("WGSL compilation clean");
  85.  
  86.    const canvas = document.getElementById("c");
  87.    const ctx = canvas.getContext("webgpu");
  88.    const format = navigator.gpu.getPreferredCanvasFormat();
  89.    out("canvas format: " + format);
  90.  
  91.    const pipeline = device.createRenderPipeline({
  92.        layout: "auto",
  93.        vertex: { module, entryPoint: "vs_main" },
  94.        fragment: { module, entryPoint: "fs_main", targets: [{ format: format }] },
  95.        primitive: { topology:"triangle-list" }
  96.    });
  97.  
  98.    ctx.configure({
  99.        device,
  100.        format: format,
  101.        alphaMode: "premultiplied"
  102.    });
  103.  
  104.    device.pushErrorScope("validation");
  105.    const enc = device.createCommandEncoder();
  106.    const pass = enc.beginRenderPass({
  107.        colorAttachments: [{
  108.            view: ctx.getCurrentTexture().createView(),
  109.            clearValue: {r:0,g:0,b:0,a:0},
  110.            loadOp:"clear",
  111.            storeOp:"store"
  112.        }]
  113.    });
  114.    pass.setPipeline(pipeline);
  115.    pass.draw(3);
  116.    pass.end();
  117.  
  118.    device.queue.submit([enc.finish()]);
  119.    const err = await device.popErrorScope();
  120.    if (err) out("[VALIDATION ERROR] " + err.message);
  121.    await device.queue.onSubmittedWorkDone();
  122.    out("draw submitted and complete - spiral should be visible above");
  123. }
  124.  
  125. main().catch(e => out("ERROR: " + (e && e.message)));
  126. </script>
  127. </body>
  128. </html>
  129.  
Advertisement
Add Comment
Please, Sign In to add comment