# 6. Worked Example — Third-Person + Cinematic Cutaway
Part of [[Cinemachine 3]]. Prev: [[5.Blends Custom Blends Cut vs Ease]]. Next: [[7.Pitfalls]].
**Goal:** A playable FreeLook third-person camera (`CM_Gameplay`) and a higher-priority cutaway (`CM_Cutaway`) that eases in on interact, with a light Impulse on impact. Input via [[Input System]]. Design framing from [[Level Up! (Review)]].
> **NOT compiled in Unity.** Verify against Cinemachine **3.1.x** and your Input System version.
## 6.1 Scene setup
1. Player capsule / character with a child empty `CameraTarget` at ~1.6m height.
2. **Main Camera** + **Cinemachine Brain**. Default Blend: Ease In Out, 0.5s.
3. Custom Blends asset:
- `CM_Gameplay` → `CM_Cutaway` · Ease In Out · 0.6s
- `CM_Cutaway` → `CM_Gameplay` · Ease Out · 0.4s
4. **GameObject → Cinemachine → FreeLook Camera** → rename `CM_Gameplay`.
- Tracking Target = `CameraTarget`
- Priority = 10
- Orbital Follow: Three Ring or Sphere; damp moderately
- Input Axis Controller → bind Look (Vector2) from your `.inputactions` asset
5. Create second Cinemachine Camera `CM_Cutaway`:
- Position Control: **Follow** or locked framing on an interactable
- Rotation Control: **Hard Look At** or Rotation Composer on the point of interest
- Priority = 0, **disabled** by default
6. Add **CinemachineImpulseListener** to `CM_Gameplay`.
7. On a heavy prop / landing volume: **CinemachineImpulseSource** (or Collision Impulse Source on feet).
Folders: `Assets/_Project/Cinemachine/Cameras`, `Blends`, `Scripts`.
## 6.2 Camera director service
```csharp
using System.Collections;
using UnityEngine;
using Unity.Cinemachine;
/// <summary>
/// Tiny camera "service" — see Architecture and Code Patterns.
/// NOT compiled in Unity.
/// </summary>
public sealed class CameraDirector : MonoBehaviour
{
[SerializeField] CinemachineCamera gameplay;
[SerializeField] CinemachineCamera cutaway;
[SerializeField] int gameplayPriority = 10;
[SerializeField] int cutawayPriority = 30;
[SerializeField] float defaultHold = 2.5f;
Coroutine _cutawayRoutine;
void Awake()
{
if (gameplay != null) gameplay.Priority = gameplayPriority;
if (cutaway != null)
{
cutaway.enabled = false;
cutaway.Priority = 0;
}
}
public void PlayCutaway(Transform lookAt, float holdSeconds = -1f)
{
if (cutaway == null) return;
if (lookAt != null) cutaway.LookAt = lookAt; // confirm property in 3.1.x
if (_cutawayRoutine != null) StopCoroutine(_cutawayRoutine);
_cutawayRoutine = StartCoroutine(CutawayRoutine(holdSeconds < 0 ? defaultHold : holdSeconds));
}
public void CancelCutaway()
{
if (_cutawayRoutine != null) StopCoroutine(_cutawayRoutine);
_cutawayRoutine = null;
RestoreGameplay();
}
IEnumerator CutawayRoutine(float hold)
{
cutaway.enabled = true;
cutaway.Priority = cutawayPriority;
yield return new WaitForSeconds(hold);
RestoreGameplay();
_cutawayRoutine = null;
}
void RestoreGameplay()
{
if (cutaway != null)
{
cutaway.Priority = 0;
cutaway.enabled = false;
}
if (gameplay != null) gameplay.Priority = gameplayPriority;
}
}
```
## 6.3 Interact trigger
```csharp
using UnityEngine;
using UnityEngine.InputSystem;
/// <summary>
/// Press Interact near a point of interest to run the cutaway.
/// NOT compiled in Unity.
/// </summary>
public sealed class CutawayInteractable : MonoBehaviour
{
[SerializeField] CameraDirector director;
[SerializeField] Transform framingTarget;
[SerializeField] InputActionReference interact;
[SerializeField] float range = 3f;
[SerializeField] Transform player;
void OnEnable() => interact?.action.Enable();
void OnDisable() => interact?.action.Disable();
void Update()
{
if (director == null || interact == null || player == null) return;
if (!interact.action.WasPressedThisFrame()) return;
if (Vector3.Distance(player.position, transform.position) > range) return;
director.PlayCutaway(framingTarget != null ? framingTarget : transform);
}
}
```
## 6.4 Landing Impulse
```csharp
using UnityEngine;
using Unity.Cinemachine;
/// <summary>
/// Call from a character landing check or Animation Event.
/// NOT compiled in Unity.
/// </summary>
public sealed class LandingImpulse : MonoBehaviour
{
[SerializeField] CinemachineImpulseSource source;
[SerializeField] float lightLand = 0.35f;
[SerializeField] float hardLand = 1.0f;
public void OnLanded(float impactSpeed)
{
if (source == null) return;
float v = impactSpeed > 8f ? hardLand : lightLand;
source.GenerateImpulse(v);
}
}
```
Hook `OnLanded` from movement code or an Animation Event on the land clip ([[Animation Advanced]]).
## 6.5 Optional Timeline beat
For authored story cutaways, prefer a Timeline asset with a Cinemachine track ([[Timeline Basics]]) that activates `CM_Cutaway` (or dedicated shot cams) instead of the coroutine. Keep `CameraDirector` for *gameplay*-driven moments.
## 6.6 Checklist to Play-mode test
1. Look orbit works via Input Axis Controller.
2. Walk behind a thin wall — Deoccluder (if added) pulls camera forward without exploding into geometry.
3. Interact — Ease into cutaway, hold, Ease back.
4. Hard land — Impulse Listener shakes gameplay cam briefly.
5. No leftover Priority 30 cam after cancel.
## Unverified
- `CinemachineCamera.LookAt` assignment API vs Tracking Target-only mode.
- Exact Impulse `GenerateImpulse` overloads.
- Input Action `WasPressedThisFrame` availability depends on your Input System package (see [[Input System]]).