11// patternv0.50.wgsl
2- // Three-Emitter LED Indicator System with Unified Lens Cap
3- // Top: Blue Note-On | Middle: Steady Note Color | Bottom: Amber Control
4- // Based on v0.49 (circular layout with padTopChannel=true)
5- // Note: Requires padTopChannel=true in PatternDisplay to shift music channels 1-32.
2+ // Frosted Glass Circular – Vibrant Note Colours + Blue LED Indicator + Full-Height Caps
3+ //
4+ // Hybrid composition combining v0.48 (vibrant note-data colours from neonPalette)
5+ // and v0.49 (blue LED indicator ring, solid housing, frosted glass caps).
6+ //
7+ // Per-step layering:
8+ // 1. HOUSING (BEHINDS) — Solid dark-metallic body lit with vibrant neonPalette
9+ // colours driven by real note pitch (purple, teal, green,
10+ // orange, red, cyan). Activity from v0.48's distance-based
11+ // energy sweep + trail + noteAge + tickOffset sub-step.
12+ // 2. CAP — Full-height frosted acrylic glass (0.88 × 0.88) in the same vibrant
13+ // hue as the housing. LED-under-glass model with white bevel rim.
14+ // 3. DEPRESSION — On playhead hit: cap scales 4 % smaller + top inner-shadow.
15+ //
16+ // Channel 0: Blue LED indicator ring shows playhead proximity (from v0.49).
17+ //
18+ // Background: bezel.wgsl (hardware photo with dark centre + white frame).
19+ // Transparent gaps + centre circle allow bezel to show through.
620
721struct Uniforms {
822 numRows : u32 ,
@@ -37,11 +51,11 @@ struct ChannelState { volume: f32, pan: f32, freq: f32, trigger: u32, noteAge: f
3751
3852struct VertexOut {
3953 @builtin (position ) position : vec4 <f32 >,
40- @location (0 ) @interpolate (flat ) row : u32 ,
41- @location (1 ) @interpolate (flat ) channel : u32 ,
42- @location (2 ) @interpolate (linear ) uv : vec2 <f32 >,
43- @location (3 ) @interpolate (flat ) packedA : u32 ,
44- @location (4 ) @interpolate (flat ) packedB : u32 ,
54+ @location (0 ) @interpolate (flat ) row : u32 ,
55+ @location (1 ) @interpolate (flat ) channel : u32 ,
56+ @location (2 ) @interpolate (linear ) uv : vec2 <f32 >,
57+ @location (3 ) @interpolate (flat ) packedA : u32 ,
58+ @location (4 ) @interpolate (flat ) packedB : u32 ,
4559};
4660
4761@vertex
@@ -52,38 +66,33 @@ fn vs(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instance
5266 );
5367
5468 let numChannels = uniforms . numChannels ;
55- let row = instanceIndex / numChannels ;
56- let channel = instanceIndex % numChannels ;
69+ let row = instanceIndex / numChannels ;
70+ let channel = instanceIndex % numChannels ;
5771
5872 let invertedChannel = numChannels - 1u - channel ;
59- let ringIndex = select (invertedChannel , channel , (uniforms . invertChannels == 1u ));
60-
61- let center = vec2 <f32 >(uniforms . canvasW * 0 .5 , uniforms . canvasH * 0 .5 );
62- let minDim = min (uniforms . canvasW , uniforms . canvasH );
73+ let ringIndex = select (invertedChannel , channel , uniforms . invertChannels == 1u );
6374
75+ let center = vec2 <f32 >(uniforms . canvasW * 0 .5 , uniforms . canvasH * 0 .5 );
76+ let minDim = min (uniforms . canvasW , uniforms . canvasH );
6477 let maxRadius = minDim * 0 .45 ;
6578 let minRadius = minDim * 0 .15 ;
6679 let ringDepth = (maxRadius - minRadius ) / f32 (numChannels );
80+ let radius = minRadius + f32 (ringIndex ) * ringDepth ;
6781
68- let radius = minRadius + f32 (ringIndex ) * ringDepth ;
69-
70- let totalSteps = 64 .0 ;
82+ let totalSteps = 64 .0 ;
7183 let anglePerStep = 6 .2831853 / totalSteps ;
72- let theta = - 1 .570796 + f32 (row % 64u ) * anglePerStep ;
84+ let theta = - 1 .570796 + f32 (row % 64u ) * anglePerStep ;
7385
7486 let circumference = 2 .0 * 3 .14159265 * radius ;
75- let arcLength = circumference / totalSteps ;
76-
77- let btnW = arcLength * 0 .95 ;
78- let btnH = ringDepth * 0 .95 ;
87+ let arcLength = circumference / totalSteps ;
88+ let btnW = arcLength * 0 .95 ;
89+ let btnH = ringDepth * 0 .95 ;
7990
80- let lp = quad [vertexIndex ];
91+ let lp = quad [vertexIndex ];
8192 let localPos = (lp - 0 .5 ) * vec2 <f32 >(btnW , btnH );
8293
8394 let rotAng = theta + 1 .570796 ;
84- let cA = cos (rotAng );
85- let sA = sin (rotAng );
86-
95+ let cA = cos (rotAng ); let sA = sin (rotAng );
8796 let rotX = localPos . x * cA - localPos . y * sA ;
8897 let rotY = localPos . x * sA + localPos . y * cA ;
8998
@@ -94,25 +103,27 @@ fn vs(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instance
94103 let clipY = 1 .0 - (worldY / uniforms . canvasH ) * 2 .0 ;
95104
96105 let idx = instanceIndex * 2u ;
97- let a = cells [idx ];
98- let b = cells [idx + 1u ];
106+ let a = cells [idx ];
107+ let b = cells [idx + 1u ];
99108
100109 var out : VertexOut ;
101110 out . position = vec4 <f32 >(clipX , clipY , 0 .0 , 1 .0 );
102- out . row = row ;
103- out . channel = channel ;
104- out . uv = lp ;
105- out . packedA = a ;
106- out . packedB = b ;
111+ out . row = row ;
112+ out . channel = channel ;
113+ out . uv = lp ;
114+ out . packedA = a ;
115+ out . packedB = b ;
107116 return out ;
108117}
109118
119+ // ── Helpers ───────────────────────────────────────────────────────────────────
120+
110121fn neonPalette (t : f32 ) -> vec3 <f32 > {
111122 let a = vec3 <f32 >(0 .5 , 0 .5 , 0 .5 );
112123 let b = vec3 <f32 >(0 .5 , 0 .5 , 0 .5 );
113124 let c = vec3 <f32 >(1 .0 , 1 .0 , 1 .0 );
114125 let d = vec3 <f32 >(0 .0 , 0 .33 , 0 .67 );
115- let beatDrift = uniforms . beatPhase * 0 .1 ;
126+ let beatDrift = uniforms . beatPhase * 0 .08 ;
116127 return a + b * cos (6 .28318 * (c * (t + beatDrift ) + d ));
117128}
118129
@@ -467,4 +478,4 @@ fn fs(in: VertexOut) -> @location(0) vec4<f32> {
467478
468479 if (housingMask < 0 .5 ) { return vec4 <f32 >(fs . borderColor , 0 .0 ); }
469480 return vec4 <f32 >(finalColor , 1 .0 );
470- }
481+ }
0 commit comments