diff options
| author | skal <pascal.massimino@gmail.com> | 2026-03-21 10:50:02 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-03-21 10:50:02 +0100 |
| commit | 35355b17576e93b035a2a78ecd05771e98f068ee (patch) | |
| tree | a1c1a4563a62ad69c808383fcf0bce1ccf4c5765 /cnn_v3/tools/index.html | |
| parent | e343021ac007549c76e58b27a361b11dd3f6a136 (diff) | |
feat(cnn_v3): HTML WebGPU tool (index.html + shaders.js + tester.js)
3-file tool, 939 lines total. Implements full U-Net+FiLM inference in
the browser: Pack→Enc0→Enc1→Bottleneck→Dec1→Dec0 compute passes,
layer visualisation (Feat/Enc0/Enc1/BN/Dec1/Output), FiLM MLP sliders,
drag-drop weights + image/video, Save PNG, diff/blend view modes.
HOW_TO_CNN.md §7 updated to reflect tool is implemented.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'cnn_v3/tools/index.html')
| -rw-r--r-- | cnn_v3/tools/index.html | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/cnn_v3/tools/index.html b/cnn_v3/tools/index.html new file mode 100644 index 0000000..eba532e --- /dev/null +++ b/cnn_v3/tools/index.html @@ -0,0 +1,147 @@ +<!DOCTYPE html> +<html lang="en"> +<!-- CNN v3 WebGPU tool — see shaders.js + tester.js --> +<head> +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>CNN v3 Tool</title> +<style> +*{box-sizing:border-box;margin:0;padding:0} +body{background:#1a1a1a;color:#e0e0e0;font-family:'Courier New',monospace;display:flex;flex-direction:column;height:100vh} +.hdr{padding:8px 14px;border-bottom:1px solid #404040;display:flex;align-items:center;gap:16px;flex-shrink:0} +h1{font-size:14px}.sub{font-size:10px;color:#555} +.body{flex:1;display:flex;overflow:hidden;gap:1px;background:#404040} +.left,.right{background:#2a2a2a;overflow-y:auto;display:flex;flex-direction:column;gap:10px;padding:10px;flex-shrink:0} +.left{width:284px}.right{width:370px} +.main{flex:1;display:flex;justify-content:center;align-items:center;padding:14px;overflow:auto;position:relative} +.panel{border:1px solid #333;border-radius:3px;overflow:hidden} +.ph{background:#1e1e1e;padding:5px 8px;font-size:10px;font-weight:bold;color:#888;cursor:pointer;display:flex;justify-content:space-between;user-select:none} +.ph:hover{color:#ddd} +.panel.collapsed .pc{display:none} +.pc{padding:9px;font-size:11px} +.dz{border:2px dashed #444;padding:12px 8px;text-align:center;cursor:pointer;font-size:10px;font-weight:bold;background:#222;border-radius:3px;color:#4a9eff;transition:border-color .15s,background .15s} +.dz:hover,.dz.dragover{border-color:#4a9eff;background:#1a2535} +.dz.ok{border-color:#28a745;color:#28a745}.dz.err{border-color:#ff4a4a;color:#ff4a4a} +button{padding:4px 9px;font-size:10px;cursor:pointer;background:#1a1a1a;color:#e0e0e0;border:1px solid #404040;border-radius:2px} +button:hover{border-color:#666;background:#252525} +button.act{background:#4a9eff;border-color:#4a9eff;color:#111} +button:disabled{opacity:.4;cursor:default} +button:disabled:hover{border-color:#404040;background:#1a1a1a} +input[type=range]{width:100%;accent-color:#4a9eff} +label{font-size:10px;color:#888} +.row{display:flex;gap:6px;align-items:center} +.row label{flex-shrink:0;width:82px} +.row span{font-size:10px;min-width:34px;text-align:right} +table{width:100%;border-collapse:collapse} +th{text-align:left;padding:2px 4px;font-size:9px;color:#555;border-bottom:1px solid #333} +td{padding:2px 4px;font-size:9px} +tr:hover td{background:#1e1e1e} +.bf{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);display:flex;gap:10px;align-items:center;background:rgba(28,28,28,.95);padding:6px 12px;border-radius:3px;border:1px solid #404040;z-index:100} +.sep{width:1px;height:16px;background:#444} +canvas{max-width:100%;max-height:100%;image-rendering:pixelated;box-shadow:0 4px 12px rgba(0,0,0,.5)} +.main.dragover::after{content:'Drop PNG/video';position:absolute;inset:14px;display:flex;align-items:center;justify-content:center;border:3px dashed #4a9eff;background:rgba(74,158,255,.08);font-size:20px;color:#4a9eff;pointer-events:none;z-index:10} +.vzbtns{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px} +.chgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:3px} +.chcell{background:#111;border:1px solid #333;overflow:hidden;display:flex;flex-direction:column} +.chcell-lbl{font-size:8px;padding:2px;background:#1e1e1e;color:#666;text-align:center} +.chcell canvas{width:100%;display:block;image-rendering:pixelated;cursor:pointer} +.fgrid{display:grid;grid-template-columns:1fr auto;gap:3px 8px;align-items:center;margin-top:4px} +.fgrid label{font-size:10px;color:#888} +.fgrid span{font-size:10px} +.ftr{background:#222;border-top:1px solid #404040;font-size:11px;display:flex;flex-direction:column;flex-shrink:0} +.ftr-top{padding:6px 14px 0;display:flex;justify-content:space-between} +.st{color:#4a9eff}.sh{color:#555;font-size:10px} +.con{background:#111;padding:4px 14px;font-size:10px;color:#555;max-height:72px;overflow-y:auto;border-top:1px solid #333} +.cl{margin:1px 0}.cl.err{color:#f44}.cl.info{color:#4a9eff} +.mtog{display:flex;gap:4px} +video{display:none} +</style> +</head> +<body> +<div class="hdr"><h1>CNN v3 Testing Tool</h1><span class="sub">U-Net + FiLM · WebGPU</span></div> +<video id="vid" muted loop></video> +<div class="body"> + <div class="left"> + <input type="file" id="wFile" accept=".bin" style="display:none"> + <input type="file" id="fFile" accept=".bin" style="display:none"> + + <div class="dz" id="wDrop" onclick="document.getElementById('wFile').click()">Drop cnn_v3_weights.bin</div> + <div class="dz" id="fDrop" onclick="document.getElementById('fFile').click()">Drop cnn_v3_film_mlp.bin (optional)</div> + + <div class="panel"> + <div class="ph" onclick="togglePanel(this)">Input Mode <span>▼</span></div> + <div class="pc"> + <div class="mtog"> + <button id="mSimple" class="act" onclick="tester.setMode('simple')">Simple (photo)</button> + <button id="mFull" onclick="tester.setMode('full')">Full (G-buffer)</button> + </div> + <div id="fullHelp" style="display:none;margin-top:6px;font-size:9px;color:#555;line-height:1.6"> + Drop PNGs: *albedo*/color · *normal* · *depth* · *matid*/index · *shadow* · *transp*/alpha + </div> + </div> + </div> + + <div class="panel"> + <div class="ph" onclick="togglePanel(this)">Weights Info <span>▼</span></div> + <div class="pc" id="wInfo"><p style="color:#444;text-align:center">No weights loaded</p></div> + </div> + + <div class="panel"> + <div class="ph" onclick="togglePanel(this)">FiLM Conditioning <span>▼</span></div> + <div class="pc"> + <div style="font-size:9px;color:#444;margin-bottom:5px" id="fSt">No FiLM MLP — identity (γ=1, β=0)</div> + <div class="fgrid"> + <label>beat_phase</label><span id="vBP">0.00</span> + <input type="range" id="sBP" min="0" max="1" step=".01" value="0" oninput="tester.fslide('vBP',this)"> + <label>beat_norm</label><span id="vBN">0.00</span> + <input type="range" id="sBN" min="0" max="1" step=".01" value="0" oninput="tester.fslide('vBN',this)"> + <label>audio_int</label><span id="vAI">0.00</span> + <input type="range" id="sAI" min="0" max="1" step=".01" value="0" oninput="tester.fslide('vAI',this)"> + <label>style_p0</label><span id="vP0">0.00</span> + <input type="range" id="sP0" min="-2" max="2" step=".05" value="0" oninput="tester.fslide('vP0',this)"> + <label>style_p1</label><span id="vP1">0.00</span> + <input type="range" id="sP1" min="-2" max="2" step=".05" value="0" oninput="tester.fslide('vP1',this)"> + </div> + </div> + </div> + </div> + + <div class="main" id="mainDrop"> + <div class="bf"> + <div style="display:flex;gap:5px" id="vCtrl"> + <button id="btnPP" disabled onclick="tester.togglePlay()">Play</button> + <button id="btnBk" disabled onclick="tester.stepFrame(-1)">◄</button> + <button id="btnFw" disabled onclick="tester.stepFrame(1)">►</button> + </div> + <div class="sep"></div> + <label>Blend</label> + <input type="range" id="blend" min="0" max="1" step=".01" value="1" style="width:70px" oninput="tester.setBlend(this.value)"> + <span id="blendV">1.0</span> + <div class="sep"></div> + <button onclick="tester.savePNG()">Save PNG</button> + </div> + <canvas id="canvas"></canvas> + </div> + + <div class="right"> + <div class="panel" style="flex:1;display:flex;flex-direction:column;min-height:0"> + <div class="ph">Layer Visualization</div> + <div class="pc" id="layerViz" style="flex:1;overflow:auto"> + <p style="color:#444;text-align:center">Load image + weights</p> + </div> + </div> + </div> +</div> + +<div class="ftr"> + <div class="ftr-top"> + <span class="st" id="status">Drop PNG/video on canvas · drop .bin weights on left</span> + <span class="sh">[SPACE] Original [D] Diff×10</span> + </div> + <div class="con" id="con"></div> +</div> + +<script src="shaders.js"></script> +<script src="tester.js"></script> +</body> +</html> |
