Glitch VFX Playground
Neon city scene routed through DigitalGlitch shader with burst, pulse, and wild distortion modes.
What this code does
- DigitalGlitch Shader: post-process pass distorting the rendered frame with RGB split, offsets, and scanline tear.
- Burst Scheduling: sporadic mode triggers short glitch bursts using configurable interval ranges.
- Pulse & Wild Modes: continuous sine-driven pulses or permanent wild glitching demonstrate different looks.
- Neon City Scene: emissive cubes, holographic panels, and moving lights accentuate the distortion artifacts.
- GUI Controls: tune strength, chromatic split, distortion axes, angle randomness, and glitch timing envelopes.
JavaScript (plain)
const scene = new THREE.Scene()
scene.background = new THREE.Color(0x050509)
const camera = new THREE.PerspectiveCamera(70, width / height, 0.1, 80)
camera.position.set(0, 1.8, 7)
const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true })
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2))
renderer.setSize(width, height)
document.querySelector('#app').appendChild(renderer.domElement)
const composer = new EffectComposer(renderer)
composer.setSize(width, height)
composer.addPass(new RenderPass(scene, camera))
const glitchPass = new GlitchPass()
glitchPass.goWild = false
composer.addPass(glitchPass)
const glitchSettings = {
mode: 'sporadic',
amount: 0.18,
baseAmount: 0.04,
distortionX: 1.1,
distortionY: 0.9,
chromatic: 0.85,
angleRange: 0.6,
seedRange: 0.9,
pulseSpeed: 1.4,
intervalMin: 0.55,
intervalMax: 1.35
}
const glitchUniforms = glitchPass.uniforms
const glitchState = { cooldown: 1.0, burst: 0 }
// Build a neon city scene
const cubes = []
const cubeGeometry = new THREE.BoxGeometry(0.7, 0.7, 0.7)
for (let i = 0; i < 12; i++) {
const material = new THREE.MeshStandardMaterial({
color: new THREE.Color().setHSL(0.55 + i / 16, 0.7, 0.55),
emissive: new THREE.Color().setHSL(0.55 + i / 16, 1.0, 0.35),
emissiveIntensity: 1.2
})
const cube = new THREE.Mesh(cubeGeometry, material)
cube.position.set((Math.random() - 0.5) * 6, Math.random() * 3, (Math.random() - 0.5) * 6)
cube.userData = { baseY: cube.position.y, offset: Math.random() * Math.PI * 2 }
scene.add(cube)
cubes.push(cube)
}
const ambient = new THREE.AmbientLight(0x223355, 0.6)
scene.add(ambient)
const point = new THREE.PointLight(0x2f89ff, 2.6, 18, 2)
point.position.set(-4, 3.6, -4)
scene.add(point)
const clock = new THREE.Clock()
let elapsed = 0
function applyGlitch(strength) {
if (!glitchUniforms) return
if (strength <= 0.0001) {
glitchUniforms.byp.value = 1
return
}
glitchUniforms.byp.value = 0
glitchUniforms.amount.value = strength
glitchUniforms.angle.value = THREE.MathUtils.randFloat(-glitchSettings.angleRange, glitchSettings.angleRange)
glitchUniforms.seed.value = Math.random()
glitchUniforms.seed_x.value = THREE.MathUtils.randFloat(-glitchSettings.seedRange, glitchSettings.seedRange)
glitchUniforms.seed_y.value = THREE.MathUtils.randFloat(-glitchSettings.seedRange, glitchSettings.seedRange)
glitchUniforms.distortion_x.value = THREE.MathUtils.randFloat(glitchSettings.distortionX * 0.4, glitchSettings.distortionX)
glitchUniforms.distortion_y.value = THREE.MathUtils.randFloat(glitchSettings.distortionY * 0.4, glitchSettings.distortionY)
glitchUniforms.col_s.value = glitchSettings.chromatic
}
function updateGlitch(delta) {
let strength = glitchSettings.amount
switch (glitchSettings.mode) {
case 'sporadic':
glitchState.cooldown -= delta
if (glitchState.cooldown <= 0) {
glitchState.cooldown = THREE.MathUtils.randFloat(glitchSettings.intervalMin, glitchSettings.intervalMax)
glitchState.burst = 0.2 + Math.random() * 0.2
}
if (glitchState.burst > 0) {
glitchState.burst -= delta
} else {
strength = 0
}
break
case 'pulse':
const cycle = (Math.sin(elapsed * glitchSettings.pulseSpeed) + 1) * 0.5
strength = THREE.MathUtils.lerp(glitchSettings.baseAmount, glitchSettings.amount, cycle)
break
case 'wild':
strength = glitchSettings.amount * 1.3
break
case 'off':
default:
strength = 0
}
applyGlitch(strength)
}
function animate() {
requestAnimationFrame(animate)
const delta = clock.getDelta()
elapsed += delta
cubes.forEach((cube) => {
cube.rotation.x += 0.25 * delta
cube.rotation.y -= 0.35 * delta
cube.position.y = cube.userData.baseY + Math.sin(elapsed * 1.2 + cube.userData.offset) * 0.35
})
updateGlitch(delta)
composer.render()
}
animate()