Skip to content
1 / 5
Lesson 01 of 05

Camera Shake System

Implement trauma-based camera shake that feels organic and never repetitive.

Bad camera shake: tween the camera to random positions in a loop. Feels mechanical.

Good camera shake: trauma-based system. Add trauma (0-1) on impact. Each frame, shake magnitude = trauma². Decay trauma over time. Use Perlin noise (math.noise) for smooth, non-repeating random offsets.

Why trauma²? At trauma=0.3, shake=0.09 (barely noticeable). At trauma=1.0, shake=1.0 (maximum). This feels natural — only big hits truly shake.

Multiple hits stack trauma additively up to 1.0, then it decays at a fixed rate.

luau
1-- LocalScript: trauma-based camera shake
2local RunService = game:GetService('RunService')
3local camera = workspace.CurrentCamera
4
5local trauma = 0
6local DECAY = 0.8
7local MAX_ANGLE = 0.15
8local MAX_OFFSET = 0.3
9local noiseT = 0
10
11local function addTrauma(amount)
12 trauma = math.clamp(trauma + amount, 0, 1)
13end
14
15RunService.RenderStepped:Connect(function(dt)
16 if trauma <= 0 then return end
17 trauma = math.max(0, trauma - DECAY * dt)
18 local shake = trauma * trauma
19 noiseT += dt * 15
20 local ox = math.noise(noiseT, 0) * shake * MAX_OFFSET
21 local oy = math.noise(0, noiseT) * shake * MAX_OFFSET
22 local az = math.noise(noiseT, noiseT) * shake * MAX_ANGLE
23 camera.CFrame = camera.CFrame
24 * CFrame.new(ox, oy, 0)
25 * CFrame.Angles(0, 0, az)
26end)
27
28-- Usage
29addTrauma(0.6) -- heavy hit
30addTrauma(0.2) -- light hit
READY · 30 lines