This document describes the integrated UI controls rendered directly in the WGSL shader for patternv0.37.
As of the latest update, the v0.37 shader includes a complete hardware-style interface rendered directly on the WebGPU canvas. All playback controls, volume/pan adjustments, and status displays are now part of the shader rendering, eliminating the need for separate HTML controls.
┌────────────────────────────────────────────────────────────┐
│ Tempo: 150 BPM Position: Order 00 Row 62 │ <- Top Info Bar
│ │
│ Volume Panning │
│ │ │ │
│ [ ] ← Slider Slider → [ ] │ <- Side Sliders
│ │ │ │
│ [ ] CIRCULAR [ ] │
│ │ PATTERN │ │
│ [█] ← Handle DISPLAY Handle → [█] │
│ │ │ │
│ [ ] [ ] │
│ │ │ │
│ │
│ ╔════════════════════╗ │
│ ║ CIRCULAR PATTERN ║ │ <- Pattern Display
│ ║ (Tracker Data) ║ │
│ ║ ║ │
│ ╚════════════════════╝ │
│ │
│ ( ) ( ) ( ) ( ) │ <- Bottom Buttons
│ LOOP PLAY STOP OPEN │
│ │
│ ──────────────────────────────── │ <- Song Position Bar
│ ▲ Position Marker │
│ │
│ ┌──────────────────┐ │
│ │ Shader Selector │ ← Bottom-Left Overlay │
│ └──────────────────┘ │
└────────────────────────────────────────────────────────────┘
- Location: x = -0.42 (left side), y = 0.0 (center)
- Height: 0.3 normalized units
- Range: 0.0 (bottom) to 1.0 (top)
- Interaction: Click or drag within slider region
- Visual: Green circular handle, vertical track
- Label: "VOLUME" text below slider
- Location: x = 0.42 (right side), y = 0.0 (center)
- Height: 0.3 normalized units
- Range: -1.0 (left/bottom) to 1.0 (right/top)
- Interaction: Click or drag within slider region
- Visual: Color-coded handle (red=left, blue=right), vertical track
- Label: "PANNING" text below slider
- Location: y = -0.48 (top of canvas)
- Format: 7-segment style digits (3 digits max)
- Color: Cyan/blue glow
- Labels: "Tempo:" (left) and "BPM" (right)
- Location: Left side, y = -0.45
- Format: Two 2-digit numbers
- Shows: Current Order (pattern) and Row
- Color: Yellow/orange
- Label: "Position:"
-
Loop Button: x = -0.32
- Color: Orange when active, dim when inactive
- Icon: Ring/circle shape
-
Play Button: x = -0.13
- Color: Green, brighter when playing
- Icon: Triangle (play symbol)
-
Stop Button: x = 0.13
- Color: Red
- Icon: Square (stop symbol)
-
Open File Button: x = 0.32
- Color: Blue
- Icon: Upload arrow
- Location: y = -0.45 (near bottom)
- Width: 0.8 (80% of canvas)
- Height: 0.03
- Interaction: Click to seek to position
- Visual: Rail with progress indicator
- Position: Absolute positioned over canvas
- Location: bottom: 16px, left: 16px
- Content:
- Quick switcher buttons (Horizontal/Circular)
- Full shader dropdown
- Style: Semi-transparent dark background with blur
The handleCanvasClick function in PatternDisplay.tsx maps screen coordinates to shader coordinates:
- Screen to UV: Normalize mouse position to 0..1 range
- UV to Shader P: Convert to shader coordinate system (p = uv - 0.5)
- Hit Testing: Check if click is within interactive regions
- Center: (0, 0)
- Top-left: (-0.5, -0.5)
- Bottom-right: (0.5, 0.5)
- Y-axis: Negative up, positive down (standard WebGPU)
App.tsx (React State)
↓
├─ volume (0-1)
├─ pan (-1 to 1)
├─ isLooping (boolean)
├─ BPM (number)
└─ playhead position
↓
PatternDisplay.tsx
↓ (pack into uniforms)
BezelUniformBuffer (GPU)
↓ (96 bytes, 24 floats)
chassisv0.37.wgsl (Shader)
↓ (render)
Canvas Display
↓ (user interaction)
Mouse Events → handleCanvasClick
↓ (callbacks)
App.tsx (Update State)
The BezelUniforms structure in chassisv0.37.wgsl:
struct BezelUniforms {
// Canvas & rendering (0-15): 64 bytes
canvasW: f32, // [0]
canvasH: f32, // [1]
bezelWidth: f32, // [2]
surfaceR: f32, // [3]
surfaceG: f32, // [4]
surfaceB: f32, // [5]
bezelR: f32, // [6]
bezelG: f32, // [7]
bezelB: f32, // [8]
screwRadius: f32, // [9]
recessKind: f32, // [10]
recessOuterScale: f32, // [11]
recessInnerScale: f32, // [12]
recessCorner: f32, // [13]
dimFactor: f32, // [14] (also indicates play state)
_pad1: f32, // [15]
// Audio controls (16-23): 32 bytes
volume: f32, // [16] 0.0 to 1.0
pan: f32, // [17] -1.0 to 1.0
bpm: f32, // [18]
isLooping: u32, // [19] 0 or 1
currentOrder: u32, // [20]
currentRow: u32, // [21]
_pad2: f32, // [22]
_pad3: f32, // [23]
}To add new interactive elements to the shader:
- Update BezelUniforms in chassisv0.37.wgsl
- Update buffer size in PatternDisplay.tsx (line ~994)
- Pack new data in render loop (line ~1280+)
- Add drawing code in shader fragment function
- Add hit testing in handleCanvasClick
- Add callback prop to PatternDisplay interface
The shader includes a drawDigit function for 7-segment style numbers:
- Supports digits 0-9
- Returns signed distance field
- Can be combined with smoothstep for anti-aliasing
For arbitrary text, use the drawText helper (currently just boxes, can be extended).
- All UI elements rendered in a single shader pass
- Distance field functions are efficient
- Uniforms updated once per frame
- Mouse interactions handled on CPU (React)
To test the shader UI:
- Build:
npm run build - Run:
npm run dev - Browser: Chrome/Edge with WebGPU enabled
- Load: Any tracker module file (.mod, .xm, .it, .s3m)
- Select: Choose "patternv0.37" from shader dropdown
- Interact: Click sliders, buttons, seek bar
- ✅ Volume slider responds to clicks, handle moves
- ✅ Pan slider responds to clicks, handle moves with color change
- ✅ BPM displays current tempo
- ✅ Position shows order and row
- ✅ Loop button changes color when active
- ✅ Play/Stop buttons respond and change state
- ✅ Seek bar allows position jumping
- ✅ Shader selector positioned at bottom-left
- Enable chrome://flags/#enable-unsafe-webgpu
- Use Chrome Canary or Edge Canary
- Check browser compatibility
- Ensure v0.37 shader is selected
- Check console for click coordinate logs
- Verify uniforms are being updated (check GPU debugger)
- Check canvas dimensions match expected (1024x1024 for v0.37)
- Verify bezel texture loaded
- Check uniform buffer size (should be 96 bytes / 24 floats)
Potential additions:
- Song title text rendering (texture-based or SDF fonts)
- VU meters for channel visualization
- Equalizer display
- Waveform preview
- Pattern name display
- Instrument list overlay