Skip to content

Commit 77ed592

Browse files
committed
wgsl changes
1 parent 17237ae commit 77ed592

5 files changed

Lines changed: 186 additions & 77 deletions

File tree

public/home/js/backgroundRenderer.js

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ export class BackgroundRenderer {
1717
this.resolutionX = 1;
1818
this.resolutionY = 1;
1919
this.dpr = 1;
20+
21+
// CRT glitch burst state
22+
this.timeSinceLastGlitch = 0;
23+
this.nextGlitchDelay = 5 + Math.random() * 5; // 5-10s
24+
this.glitchFramesRemaining = 0;
25+
this.glitchIntensity = 0;
26+
this.glitchSeed = 0;
2027
}
2128

2229
/**
@@ -108,12 +115,29 @@ export class BackgroundRenderer {
108115

109116
this.time += deltaTime;
110117

111-
// Write uniforms — only time (offset 0) and resolution (offsets 56, 60) matter
118+
// --- Glitch burst timing ---
119+
this.timeSinceLastGlitch += deltaTime;
120+
if (this.glitchFramesRemaining > 0) {
121+
this.glitchFramesRemaining--;
122+
this.glitchIntensity = 0.6 + Math.random() * 0.4; // 0.6-1.0
123+
this.glitchSeed = Math.random();
124+
} else {
125+
this.glitchIntensity = 0;
126+
if (this.timeSinceLastGlitch >= this.nextGlitchDelay) {
127+
this.timeSinceLastGlitch = 0;
128+
this.nextGlitchDelay = 5 + Math.random() * 5; // 5-10s
129+
this.glitchFramesRemaining = 6 + Math.floor(Math.random() * 6); // 6-12 frames
130+
}
131+
}
132+
133+
// Write uniforms
112134
const data = new Float32Array(16);
113-
data[0] = this.time; // time
114-
data[1] = this.dpr; // dpr (device pixel ratio)
115-
data[14] = this.resolutionX; // resolutionX (was padding1)
116-
data[15] = this.resolutionY; // resolutionY (was padding2)
135+
data[0] = this.time; // time
136+
data[1] = this.dpr; // dpr
137+
data[2] = this.glitchIntensity; // glitchIntensity
138+
data[3] = this.glitchSeed; // glitchSeed
139+
data[14] = this.resolutionX; // resolutionX
140+
data[15] = this.resolutionY; // resolutionY
117141

118142
this.device.queue.writeBuffer(this.uniformBuffer, 0, data.buffer, 0, data.byteLength);
119143

public/home/js/shaderUniforms.js

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,31 @@ export class ShaderUniforms {
1717
noiseStrength: 0.05,
1818
displacementAmount: 0.02,
1919
animationPhase: 0.0,
20-
// Ripple effect
21-
rippleX: 0.0,
22-
rippleY: 0.0,
23-
rippleTime: -999.0, // Negative = no active ripple
24-
rippleStrength: 0.8, // Increased from 0.3
2520
// Scale pulsing (sync to audio)
2621
scalePulse: 1.0,
2722
// Parallax strength
2823
parallaxStrength: 0.0 // Set in main.js to 0.15
2924
};
3025

26+
// 4 concurrent ripple slots: each is {x, y, time, strength}
27+
this.ripples = [
28+
{ x: 0, y: 0, time: -999, strength: 0.8 },
29+
{ x: 0, y: 0, time: -999, strength: 0.8 },
30+
{ x: 0, y: 0, time: -999, strength: 0.8 },
31+
{ x: 0, y: 0, time: -999, strength: 0.8 },
32+
];
33+
this.nextRippleSlot = 0;
34+
3135
// Create uniform buffer
32-
// Size: 16 floats * 4 bytes = 64 bytes (must be multiple of 16 for alignment)
33-
this.bufferSize = 64;
36+
// Size: 28 floats * 4 bytes = 112 bytes (must be multiple of 16 for alignment)
37+
this.bufferSize = 112;
3438
this.buffer = device.createBuffer({
3539
size: this.bufferSize,
3640
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
3741
});
3842

3943
// Typed array for updating buffer
40-
this.uniformData = new Float32Array(16);
44+
this.uniformData = new Float32Array(28);
4145

4246
// Events for animation triggers
4347
this.eventCallbacks = [];
@@ -108,12 +112,14 @@ export class ShaderUniforms {
108112
}
109113

110114
/**
111-
* Trigger a ripple effect at position
115+
* Trigger a ripple effect at position (round-robin across 4 slots)
112116
*/
113117
triggerRipple(x, y) {
114-
this.values.rippleX = x;
115-
this.values.rippleY = y;
116-
this.values.rippleTime = this.values.time;
118+
const slot = this.ripples[this.nextRippleSlot];
119+
slot.x = x;
120+
slot.y = y;
121+
slot.time = this.values.time;
122+
this.nextRippleSlot = (this.nextRippleSlot + 1) % 4;
117123
}
118124

119125
/**
@@ -142,14 +148,19 @@ export class ShaderUniforms {
142148
this.uniformData[5] = this.values.noiseStrength;
143149
this.uniformData[6] = this.values.displacementAmount;
144150
this.uniformData[7] = this.values.animationPhase;
145-
this.uniformData[8] = this.values.rippleX;
146-
this.uniformData[9] = this.values.rippleY;
147-
this.uniformData[10] = this.values.rippleTime;
148-
this.uniformData[11] = this.values.rippleStrength;
149-
this.uniformData[12] = this.values.scalePulse;
150-
this.uniformData[13] = this.values.parallaxStrength;
151-
this.uniformData[14] = 0.0; // padding
152-
this.uniformData[15] = 0.0; // padding
151+
this.uniformData[8] = this.values.scalePulse;
152+
this.uniformData[9] = this.values.parallaxStrength;
153+
this.uniformData[10] = 0.0; // padding (vec4 alignment at offset 48)
154+
this.uniformData[11] = 0.0; // padding
155+
// 4 ripple slots: each vec4(x, y, time, strength)
156+
for (let i = 0; i < 4; i++) {
157+
const r = this.ripples[i];
158+
const base = 12 + i * 4;
159+
this.uniformData[base] = r.x;
160+
this.uniformData[base + 1] = r.y;
161+
this.uniformData[base + 2] = r.time;
162+
this.uniformData[base + 3] = r.strength;
163+
}
153164

154165
this.device.queue.writeBuffer(
155166
this.buffer,

public/home/shaders/background.frag.wgsl

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
struct Uniforms {
44
time: f32,
55
dpr: f32,
6-
mouseY: f32,
7-
aspectRatio: f32,
8-
noiseScale: f32,
9-
noiseStrength: f32,
10-
displacementAmount: f32,
11-
animationPhase: f32,
12-
rippleX: f32,
13-
rippleY: f32,
14-
rippleTime: f32,
15-
rippleStrength: f32,
16-
scalePulse: f32,
17-
parallaxStrength: f32,
6+
glitchIntensity: f32,
7+
glitchSeed: f32,
8+
_pad0: f32,
9+
_pad1: f32,
10+
_pad2: f32,
11+
_pad3: f32,
12+
_pad4: f32,
13+
_pad5: f32,
14+
_pad6: f32,
15+
_pad7: f32,
16+
_pad8: f32,
17+
_pad9: f32,
1818
resolutionX: f32,
1919
resolutionY: f32,
2020
}
@@ -64,5 +64,63 @@ fn main(input: FragmentInput) -> @location(0) vec4<f32> {
6464
let flicker = sin(uniforms.time * 60.0) * 0.08 + 0.92;
6565
finalColor *= flicker;
6666

67+
// --- HORIZONTAL TEAR ---
68+
// Slowly drifting band of static, like CRT AC interference
69+
let normY = screenPos.y / uniforms.resolutionY;
70+
let normX = screenPos.x / uniforms.resolutionX;
71+
72+
// Band drifts upward, wrapping around
73+
let tearY = fract(uniforms.time * 0.06);
74+
let distFromTear = min(abs(normY - tearY), 1.0 - abs(normY - tearY)); // wrap-aware
75+
76+
// Soft band shape (~3% screen height with soft edges)
77+
let tearBand = smoothstep(0.04, 0.015, distFromTear);
78+
79+
// Horizontal edge fade so canvas boundary stays hidden
80+
let hFade = smoothstep(0.0, 0.2, normX) * smoothstep(1.0, 0.8, normX);
81+
let tearStrength = tearBand * hFade;
82+
83+
// Horizontal offset (tear/jitter)
84+
let tearJitter = tearStrength * sin(normY * 80.0 + uniforms.time * 4.0) * 10.0;
85+
86+
// Extra static noise in the band
87+
let tearNoise = hash(vec2<f32>(cssPos.x + tearJitter, cssPos.y) + vec2<f32>(uniforms.time * 137.0, uniforms.time * 59.0));
88+
finalColor += tearStrength * (tearNoise - 0.5) * 0.12;
89+
90+
// Chromatic fringing in the tear band
91+
finalColor.r += tearStrength * 0.015;
92+
finalColor.b -= tearStrength * 0.01;
93+
94+
// Slight brightness boost
95+
finalColor *= 1.0 + tearStrength * 0.15;
96+
97+
// --- GLITCH BURST ---
98+
if (uniforms.glitchIntensity > 0.0) {
99+
let intensity = uniforms.glitchIntensity;
100+
let seed = uniforms.glitchSeed;
101+
102+
// Horizontal tear: offset a band of scanlines
103+
let bandCenter = seed; // 0-1 normalized Y position
104+
let bandWidth = 0.08 + seed * 0.12; // 8-20% of screen
105+
let normalizedY = cssPos.y / (uniforms.resolutionY / uniforms.dpr);
106+
let inBand = step(bandCenter - bandWidth, normalizedY) * step(normalizedY, bandCenter + bandWidth);
107+
let tearOffset = inBand * intensity * (seed * 2.0 - 1.0) * 40.0; // pixel offset
108+
109+
// Re-sample with tear (shift the hash for grain variation)
110+
let tornPos = vec2<f32>(cssPos.x + tearOffset, cssPos.y);
111+
let tornGrain = hash(tornPos + vec2<f32>(uniforms.time * 100.0, uniforms.time * 73.0));
112+
finalColor += inBand * (tornGrain - 0.5) * 0.1 * intensity;
113+
114+
// Chromatic separation: shift R and B channels in opposite x-directions
115+
let chromaShift = intensity * 0.015;
116+
let scanlineR = sin((cssPos.y + tearOffset) * 1.5) * 0.35 + 0.65;
117+
let scanlineB = sin((cssPos.y - tearOffset * 0.5) * 1.5) * 0.35 + 0.65;
118+
finalColor.r += chromaShift * scanlineR * vignette * 0.3;
119+
finalColor.b += chromaShift * scanlineB * vignette * 0.3;
120+
121+
// Brightness flash
122+
finalColor *= 1.0 + intensity * 0.3;
123+
}
124+
67125
return vec4<f32>(max(finalColor, vec3<f32>(0.0)), 1.0);
68126
}

public/home/shaders/logo.frag.wgsl

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ struct Uniforms {
1010
noiseStrength: f32,
1111
displacementAmount: f32,
1212
animationPhase: f32,
13-
rippleX: f32,
14-
rippleY: f32,
15-
rippleTime: f32,
16-
rippleStrength: f32,
1713
scalePulse: f32,
1814
parallaxStrength: f32,
19-
padding1: f32,
20-
padding2: f32,
15+
_pad0: f32,
16+
_pad1: f32,
17+
ripple0: vec4<f32>,
18+
ripple1: vec4<f32>,
19+
ripple2: vec4<f32>,
20+
ripple3: vec4<f32>,
2121
}
2222

2323
struct FragmentInput {
@@ -149,6 +149,11 @@ fn main(input: FragmentInput) -> @location(0) vec4<f32> {
149149
let flicker = sin(uniforms.time * 60.0) * 0.03 + 0.97;
150150
finalColor *= flicker;
151151

152+
// --- COLOR DRIFT --- (~60s cycle, ±0.03 hue shift)
153+
var driftHsv = rgb2hsv(finalColor);
154+
driftHsv.x = fract(driftHsv.x + sin(uniforms.time * 0.5) * 0.12);
155+
finalColor = hsv2rgb(driftHsv);
156+
152157
return vec4<f32>(finalColor, 1.0);
153158
}
154159

public/home/shaders/logo.vert.wgsl

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ struct Uniforms {
1010
noiseStrength: f32,
1111
displacementAmount: f32,
1212
animationPhase: f32,
13-
rippleX: f32,
14-
rippleY: f32,
15-
rippleTime: f32,
16-
rippleStrength: f32,
1713
scalePulse: f32,
1814
parallaxStrength: f32,
19-
padding1: f32,
20-
padding2: f32,
15+
_pad0: f32,
16+
_pad1: f32,
17+
ripple0: vec4<f32>,
18+
ripple1: vec4<f32>,
19+
ripple2: vec4<f32>,
20+
ripple3: vec4<f32>,
2121
}
2222

2323
struct VertexInput {
@@ -76,6 +76,37 @@ fn fbm(p: vec2<f32>, octaves: i32) -> f32 {
7676
return value;
7777
}
7878

79+
// Apply a single ripple effect and return displaced position
80+
fn applyRipple(pos: vec2<f32>, ripple: vec4<f32>, currentTime: f32) -> vec2<f32> {
81+
let rippleX = ripple.x;
82+
let rippleY = ripple.y;
83+
let rippleTime = ripple.z;
84+
let rippleStrength = ripple.w;
85+
86+
let timeSinceRipple = currentTime - rippleTime;
87+
if (timeSinceRipple < 0.0 || timeSinceRipple >= 2.0) {
88+
return vec2<f32>(0.0, 0.0);
89+
}
90+
91+
let rippleCenter = vec2<f32>(rippleX, rippleY);
92+
let distToRipple = length(pos - rippleCenter);
93+
94+
let rippleSpeed = 0.8;
95+
let rippleRadius = timeSinceRipple * rippleSpeed;
96+
let rippleWidth = 0.3;
97+
98+
let distFromWave = abs(distToRipple - rippleRadius);
99+
let rippleIntensity = smoothstep(rippleWidth, 0.0, distFromWave);
100+
let rippleDecay = 1.0 - (timeSinceRipple / 2.0);
101+
102+
if (distToRipple > 0.01) {
103+
let rippleDir = normalize(pos - rippleCenter);
104+
let rippleAmount = rippleIntensity * rippleDecay * rippleStrength;
105+
return rippleDir * rippleAmount * sin(distToRipple * 10.0 - timeSinceRipple * 5.0);
106+
}
107+
return vec2<f32>(0.0, 0.0);
108+
}
109+
79110
// Smooth layer separation based on index
80111
fn layerOffset(layerIdx: f32, time: f32) -> vec2<f32> {
81112
// Each layer moves in a different circular pattern
@@ -103,42 +134,22 @@ fn main(input: VertexInput) -> VertexOutput {
103134
// Layer-based displacement (creates depth/parallax)
104135
let layerDisplacement = layerOffset(input.layerIndex, uniforms.time);
105136

106-
// Combine displacements
137+
// Combine displacements with breathing modulation (~8s period, ±15%)
138+
let breathing = sin(uniforms.time * 0.8) * 0.15 + 1.0;
107139
let noiseDisplacement = vec2<f32>(
108140
noise2D(pos + vec2<f32>(0.0, uniforms.time * 0.2)) * uniforms.displacementAmount,
109141
noise2D(pos + vec2<f32>(100.0, uniforms.time * 0.2)) * uniforms.displacementAmount
110-
);
142+
) * breathing;
111143

112144
// Apply all displacements
113145
pos += noiseDisplacement * uniforms.noiseStrength;
114146
pos += layerDisplacement;
115147

116-
// --- RIPPLE EFFECT ---
117-
// Check if there's an active ripple (rippleTime >= 0 and recent)
118-
let timeSinceRipple = uniforms.time - uniforms.rippleTime;
119-
if (timeSinceRipple >= 0.0 && timeSinceRipple < 2.0) {
120-
let rippleCenter = vec2<f32>(uniforms.rippleX, uniforms.rippleY);
121-
let distToRipple = length(pos - rippleCenter);
122-
123-
// Expanding wave pattern
124-
let rippleSpeed = 0.8;
125-
let rippleRadius = timeSinceRipple * rippleSpeed;
126-
let rippleWidth = 0.3;
127-
128-
// Wave intensity based on distance from wave front
129-
let distFromWave = abs(distToRipple - rippleRadius);
130-
let rippleIntensity = smoothstep(rippleWidth, 0.0, distFromWave);
131-
132-
// Decay over time
133-
let rippleDecay = 1.0 - (timeSinceRipple / 2.0);
134-
135-
// Apply ripple displacement
136-
if (distToRipple > 0.01) {
137-
let rippleDir = normalize(pos - rippleCenter);
138-
let rippleAmount = rippleIntensity * rippleDecay * uniforms.rippleStrength;
139-
pos += rippleDir * rippleAmount * sin(distToRipple * 10.0 - timeSinceRipple * 5.0);
140-
}
141-
}
148+
// --- RIPPLE EFFECTS (4 concurrent slots) ---
149+
pos += applyRipple(pos, uniforms.ripple0, uniforms.time);
150+
pos += applyRipple(pos, uniforms.ripple1, uniforms.time);
151+
pos += applyRipple(pos, uniforms.ripple2, uniforms.time);
152+
pos += applyRipple(pos, uniforms.ripple3, uniforms.time);
142153

143154
// --- PARALLAX EFFECT ---
144155
// Mouse-based parallax (layers at different depths move differently)

0 commit comments

Comments
 (0)