Screen Shake, Hit Stop and Screen Flash

Screen shake, camera shake, UI shake, hit stop and full-screen flash — all authored in one FeedbackDefinition and triggered by a single service call.

What the system is for

Game feel lives in the details: the frame the camera lurches on a heavy hit, the split-second time freeze that makes contact land, the white flash that tells the player something important just happened. These effects are simple in isolation but painful to coordinate. Each one touches a different system — the camera, Time.timeScale, a canvas overlay — and they all need to agree on intensity, timing and pause state.

The screen feedback channels in Serenity model each effect as a first-class channel that runs through the same IFeedbackService pipeline as gamepad rumble and adaptive triggers. One FeedbackDefinition ScriptableObject mixes all of them. One IFeedbackService.Play call fires the whole bundle.

The Unity problem

Implementing screen shake means hooking into the active camera every frame and applying a positional offset that does not fight whatever camera controller is already running. Hit stop means dipping Time.timeScale without breaking a paused game. Screen flash means creating a full-screen canvas overlay and animating its alpha outside of scaled time so it is still visible during the stop. UI shake means finding every root canvas and offsetting it in screen space without touching world-space objects. None of those are hard individually, but wiring them to a common intensity setting, a global pause manager and the same authoring surface takes real effort.

Without a shared layer those effects are usually implemented ad hoc: a coroutine here, a static helper there, a magic number baked into a script. The result is effects that ignore the global intensity accessibility setting, that fight the pause manager, or that leave orphaned canvases in the hierarchy.

How Serenity approaches it

Serenity defines three effect value objects — ScreenFlashEffect (Color, PeakAlpha, DurationSeconds, optional AnimationCurve), ScreenShakeEffect (Amplitude, Frequency, DurationSeconds) and UiScreenShakeEffect (same shape as ScreenShakeEffect but targeting UI space) — and HitStopEffect (TargetTimeScale, DurationSeconds). Each maps to a dedicated channel that handles the Unity-specific wiring: ScreenFlashChannel lazily creates a FeedbackScreenOverlay canvas and drives it on unscaled time; ScreenShakeChannel auto-attaches a UnityCameraShakeApplier to the active camera and re-resolves it every frame so it survives camera transitions; UiScreenShakeChannel discovers root canvases through UiShakeRegistry and drives UnityUiShakeReceiver components attached to them automatically; HitStopChannel dips Time.timeScale and restores it, guarding against conflicts with the pause manager through IGameModeService.IsPaused.

All four effects are authored inside the same FeedbackDefinition ScriptableObject alongside gamepad rumble, LED color and adaptive trigger effects. AnimationCurveFeedbackCurve wraps UnityEngine.AnimationCurve behind an IFeedbackCurve interface so the Application layer stays free of engine types. Camera shake and UI shake scale with the global intensity setting from IFeedbackSettings, giving players an accessibility slider for visual intensity. Hit stop deliberately ignores global intensity so gameplay timing stays deterministic.

How it fits into Serenity

Screen feedback lives in the Serenity.Feedback namespace and follows the foundation's layered structure. The Application layer defines ScreenFlashEffect, ScreenShakeEffect, UiScreenShakeEffect and HitStopEffect as plain data objects, IFeedbackCurve as the envelope abstraction, and IFeedbackService as the single trigger point. The Infrastructure layer provides the Unity channel implementations: ScreenFlashChannel, ScreenShakeChannel, UiScreenShakeChannel and HitStopChannel, plus the FeedbackScreenOverlay MonoBehaviour, UnityCameraShakeApplier and UnityUiShakeReceiver. FeedbackDefinition is the ScriptableObject that holds the authored effect list and is resolved by UnityFeedbackDefinitionProvider at runtime.

Screen feedback cooperates with three other Serenity systems. The Ui aggregate supplies the root canvas discovery that UiScreenShakeChannel uses through UiShakeRegistry. Game Mode supplies the pause state that HitStopChannel checks before dipping timeScale. The Event Dispatcher lets any system fire a PlayFeedbackSignal without taking a direct dependency on IFeedbackService, so designers can wire feedback to game events in the inspector without touching code.

Practical workflow

  1. Create a FeedbackDefinition ScriptableObject asset in your project.
  2. Add a ScreenShakeEffect, UiScreenShakeEffect, ScreenFlashEffect or HitStopEffect — or any combination — to the effect list.
  3. Set amplitude, frequency, duration and color values directly in the inspector; optionally assign an AnimationCurveFeedbackCurve for envelope shaping.
  4. Register the definition with the feedback service through the initialization pipeline.
  5. Call IFeedbackService.Play("your-definition-id") from code, or drop a PlayFeedbackSignal into an Event Dispatcher binding for no-code triggering.
  6. Adjust the global intensity setting in IFeedbackSettings to scale camera and UI shake across all definitions at once for accessibility.

What you get

  • ScreenFlashEffect — full-screen RGB flash with PeakAlpha and optional AnimationCurve, driven on unscaled time so it is visible during hit stop
  • ScreenShakeEffect — camera positional jitter with Amplitude, Frequency and DurationSeconds; offset applied additively so it survives any camera controller
  • UiScreenShakeEffect — independent UI/HUD/menu shake channel in screen space, separate from camera shake so menus and world camera never fight
  • HitStopEffect — brief dip of Time.timeScale with TargetTimeScale and DurationSeconds; pause-aware and intentionally excluded from global intensity scaling
  • ScreenFlashChannel — lazily instantiates a FeedbackScreenOverlay canvas; no manual setup required
  • ScreenShakeChannel — auto-attaches UnityCameraShakeApplier to the active camera and re-resolves it each frame for camera-transition safety
  • UiScreenShakeChannel — auto-discovers root canvases via UiShakeRegistry and attaches UnityUiShakeReceiver with no manual wiring
  • Single FeedbackDefinition ScriptableObject mixes screen effects with gamepad rumble, LED and adaptive-trigger effects; one IFeedbackService.Play fires all of them

When to use this

  • Games that need impactful hit reactions — melee, shooting, explosions — and want screen shake, flash and hit stop to fire as a coordinated bundle.
  • Projects that already use the Serenity Feedback system for gamepad rumble and want to extend the same definitions to cover screen effects without extra code.
  • Teams that want visual-intensity effects to respect an accessibility setting so players can reduce or disable shake and flash globally.
  • Codebases where designers need to tune and trigger feedback effects from the inspector without modifying scripts.

Related systems

Use Serenity screen feedback when you want camera shake, UI shake, screen flash and hit stop to live in the same ScriptableObject, scale with one accessibility slider and fire from a single service call — without touching the camera controller, the canvas hierarchy or Time.timeScale directly.

Back to the home page