Everything you need to wire any DataBus channel to any property on any Unity object. Start with the concept, walk through every channel and target type with worked examples, then copy-paste recipes straight into your scene.
A binding is a single rule that says: "read this number from the DataBus, transform it, and apply it to that property on that object."
One binding drives one property. If you want a light to react to your arm, a material colour to cycle with music, and a particle system to burst on beat — that's three bindings. They're cheap, and the editor UI makes them fast to create.
The 4E Data Flow System is a giant post office. Your body, the music, the keyboard — all write numbers into named mailboxes on the DataBus. A binding is a little delivery worker that stands by one mailbox, grabs whatever number is in it every frame, transforms it, and hands it to one Unity property.
The worker can do smart things too: hold the value, reshape it, only work on certain days, or fire a pulse when something important happens. That's what binding modes are for.
Every binding, regardless of what it drives, has the same five-stage pipeline. Most stages are optional — a minimal binding is just a source and a target.
pose/joint/rightElbow/bend). Plus an Active toggle to mute the binding without deleting it.DriverMappingRunner.LateUpdate(). Idle bindings are nearly free — no work happens until someone writes to the channel they're listening to.Bindings are stored directly on the DriverMappingRunner component in your scene, under the Scene Bindings list. You drag scene objects straight into each binding's target field.
Use when: you're building a single scene, or each scene needs its own unique mapping.
Bindings are stored inside a DriverMapping ScriptableObject asset (create via Assets → Create → 4E → Driver Mapping). The asset holds the recipe — channels, ranges, modes, curves. Scene references are supplied separately through the Asset Targets list on the runner.
Start() from the runner's Asset Targets list.Use when: multiple scenes should react the same way, or you want to A/B test two mapping presets on the same show.
DriverBinding.Apply() each frameThis is the literal order of operations, taken from DriverBinding.cs:
Source channels come from the DataBus — populated by MediaPipe (body + face + hands), audio analysis, time-based LFOs, and keyboard/mouse input. This is not every channel the system writes, but it's a complete cheat sheet of the ones you'll use in practice.
MediaPipe tracks 33 body points. The PoseChannelSource writes the raw landmark positions plus several derived channels — joint bend angles, limb raise angles, overall body centre, and movement velocity.
| Channel | Range | What it measures |
|---|---|---|
| pose/joint/name/bend | 0–180° | Angle at the joint. 180 = straight, 0 = fully folded. |
| pose/joint/name/bendNorm | 0–1 | Same angle, normalised. Ready to use without a remap. |
| pose/joint/name/raise | 0–180° | Limb angle vs world axis. 0 = above head, 180 = at side. |
| pose/joint/name/raiseNorm | 0–1 | Same, normalised. |
| pose/body/velocity | 0–1 | How much the whole body is moving. 0 = still, 1 = fast. |
| pose/body/centre/x | −1 to 1 | Lean left (−1) or right (+1). |
| pose/body/centre/y | −1 to 1 | Crouch (−1) or stand tall (+1). |
| pose/body/centre/z | −1 to 1 | Forward / back. Noisy — MediaPipe Z is a rough estimate. |
| pose/landmark/name/x|y|z | −1 to 1 | Raw landmark position. Available for all 33 points. |
| pose/landmark/name/visibility | 0–1 | How confident MediaPipe is that it sees this landmark. |
bend / bendNormleftElbow, rightElbow, leftWrist, rightWrist, leftKnee, rightKnee, leftHip, rightHip, headTilt
raise / raiseNormleftUpperArm, rightUpperArm, leftForeArm, rightForeArm, leftThigh, rightThigh, shoulderWidth, hipWidth
nose, leftEyeInner, leftEye, leftEyeOuter, rightEyeInner, rightEye, rightEyeOuter, leftEar, rightEar, mouthLeft, mouthRight, leftShoulder, rightShoulder, leftElbow, rightElbow, leftWrist, rightWrist, leftPinky, rightPinky, leftIndex, rightIndex, leftThumb, rightThumb, leftHip, rightHip, leftKnee, rightKnee, leftAnkle, rightAnkle, leftHeel, rightHeel, leftFootIndex, rightFootIndex
MediaPipe's face mesh gives you 478 raw landmark points plus 52 ARKit-compatible blendshape values that capture expressions like smile, blink, brow raise, and jaw open. Blendshapes are the usual choice — landmarks are more useful for bespoke measurements.
| Channel | Range | What it measures |
|---|---|---|
| face/blendshape/jawOpen | 0–1 | How open the mouth is. |
| face/blendshape/mouthSmileLeft | 0–1 | Left-side smile intensity. |
| face/blendshape/eyeBlinkLeft | 0–1 | Left eye closed amount. |
| face/blendshape/browInnerUp | 0–1 | Eyebrows raised. |
| face/blendshape/cheekPuff | 0–1 | Cheeks puffed out. |
| face/landmark/i/x|y|z | 0–1 | Raw face mesh point. 478 points available (i = 0–477). |
browDownLeft, browDownRight, browInnerUp, browOuterUpLeft, browOuterUpRight, cheekPuff, cheekSquintLeft, cheekSquintRight, eyeBlinkLeft, eyeBlinkRight, eyeLookDownLeft, eyeLookDownRight, eyeLookInLeft, eyeLookInRight, eyeLookOutLeft, eyeLookOutRight, eyeLookUpLeft, eyeLookUpRight, eyeSquintLeft, eyeSquintRight, eyeWideLeft, eyeWideRight, jawForward, jawLeft, jawOpen, jawRight, mouthClose, mouthDimpleLeft, mouthDimpleRight, mouthFrownLeft, mouthFrownRight, mouthFunnel, mouthLeft, mouthLowerDownLeft, mouthLowerDownRight, mouthPressLeft, mouthPressRight, mouthPucker, mouthRight, mouthRollLower, mouthRollUpper, mouthShrugLower, mouthShrugUpper, mouthSmileLeft, mouthSmileRight, mouthStretchLeft, mouthStretchRight, mouthUpperUpLeft, mouthUpperUpRight, noseSneerLeft, noseSneerRight, _neutral
Each hand gets 21 tracked points: wrist, four joints per finger (MCP, PIP, DIP, tip). Hand labels are already swapped to user perspective — hand/right is your right hand, not the camera's.
| Channel | Range | What it measures |
|---|---|---|
| hand/left/detected | 0 or 1 | Whether the left hand is currently visible. |
| hand/right/detected | 0 or 1 | Whether the right hand is currently visible. |
| hand/left/i/x|y|z | −1 to 1 | Left hand landmark position. i = 0 to 20. |
| hand/right/i/x|y|z | −1 to 1 | Right hand landmark position. |
0 wrist · 4 thumb tip · 8 index tip · 12 middle tip · 16 ring tip · 20 pinky tip. Indices 1–3, 5–7, 9–11, 13–15, 17–19 are the intermediate finger joints.
Requires an AudioAnalysisSource component in the scene with an AudioSource playing music. FFT analysis splits the spectrum into low / mid / high bands and runs a beat detector.
| Channel | Range | What it measures |
|---|---|---|
| audio/amplitude | 0–1 | Overall volume level. |
| audio/bass | 0–1 | Low-frequency energy (kick drums, bass guitar). |
| audio/mid | 0–1 | Mid frequencies (vocals, guitars, snare body). |
| audio/high | 0–1 | High frequencies (hi-hats, cymbals, sibilance). |
| audio/beat | 0 or 1 | 1 on the frame a beat is detected, otherwise 0. |
The TimeSource writes automatic oscillators and a BPM clock — useful when you want something to pulse or cycle without any performer input. Three pre-configured LFOs ship with the system.
| Channel | Range | What it measures |
|---|---|---|
| time/lfo/slow | 0–1 | Sine wave, ~4-second cycle (0.25 Hz). Good for ambient drift. |
| time/lfo/medium | 0–1 | Sine wave, ~1-second cycle (1 Hz). Natural breathing feel. |
| time/lfo/fast | 0–1 | Sine wave, ~0.25-second cycle (4 Hz). Rapid pulsing. |
| time/clock/pulse | 0 or 1 | Fires once per beat at the configured BPM (default 120). |
The InputSource writes keyboard and mouse state to the DataBus using Unity's new Input System. Great for dress-rehearsing effects before you've got MediaPipe running.
| Channel | Range | What it measures |
|---|---|---|
| input/key/name | 0 or 1 | Key is currently held down. E.g. input/key/space, input/key/digit1. |
| input/key/name/down | 0 or 1 | 1 on the single frame the key was pressed. Useful for one-shot triggers. |
| input/mouse/x | 0–1 | Mouse horizontal position, normalised to screen width. |
| input/mouse/y | 0–1 | Mouse vertical position, normalised to screen height. |
A channel usually speaks in its own units — degrees for a joint bend, 0–1 for a blendshape, −1 to 1 for a landmark position. Your target usually wants something else. Remap is the built-in converter.
| Field | Type | What it does |
|---|---|---|
| useRemap | bool | Master toggle. When off, the raw channel value passes through unchanged. Default: true. |
| inputMin | float | The raw value that maps to outputMin. |
| inputMax | float | The raw value that maps to outputMax. |
| outputMin | float | The value written when input ≤ inputMin. |
| outputMax | float | The value written when input ≥ inputMax. |
| clamp | bool | If true, output is restricted to [outputMin, outputMax]. Leave on for most cases. Default: true. |
| invert | bool | Flip the mapping: high input → low output. Useful for "hand down = loud" instead of "hand up = loud". |
inputMin = 60, inputMax = 180, outputMin = 0, outputMax = 1. When the elbow is at 120°, the output is 0.5.inputMin and inputMax. This ensures the full range of your movement maps to the full range of the output.0–180 → 0–1; pick a face blendshape and you get 0–1 → 0–100. You usually only need to tune, not build from scratch.A response curve is a Unity AnimationCurve that reshapes the remapped value non-linearly. It operates in normalised 0–1 space between outputMin and outputMax, so swapping your output range doesn't invalidate the curve. X axis = input, Y axis = output.
| Field | Type | What it does |
|---|---|---|
| useResponseCurve | bool | Master toggle. Default: false. |
| responseCurve | AnimationCurve | Standard Unity curve editor, 0 to 1 on both axes. Default: linear ramp. |
| Shape | Effect | Use case |
|---|---|---|
| Linear | Even response across full range | Default — most cases |
| Ease-in (x²) | Subtle at low values, dramatic at high | Volume, particle counts, intensity |
| Ease-out (√x) | Punchy at low values, gentle at high | Position, scale, blendshapes where small motion should read strong |
| S-curve | Gentle at the edges, sharp in the middle | Crossfades, audio transitions, natural animation |
| Step (flat then jump) | Dead zone, then sudden response | Threshold effects without using Switch mode |
The default mode is Direct — the remapped value just passes straight through to the target. The other five modes add logic: on/off switches, two-channel gates, rising-edge latches, stepped sequences, and decaying pulses. Pick the one that matches the feel you want, not just the math.
The remapped value passes through unchanged. Source → Remap → Target.
Settings: none
Above the threshold → outputMax. Below → outputMin. No in-between.
Settings: modeThreshold
pose/joint/rightUpperArm/raiseNorm, threshold 0.5 → Target LightIntensity, out 0→5. Arm above shoulder = light ON at 5. Below = light OFF.face/blendshape/mouthSmileLeft, threshold 0.4 → Target AnimatorBool "IsHappy". Smile past a certain point and the animator transitions to the happy state.pose/body/velocity, threshold 0.3 → Target ParticleEmission, out 0→200. Stand still = no particles. Start dancing = full emission rate. No gradient — it's either on or off.Passes the signal only when a separate gate channel is above 0.5. When the gate is closed, output snaps to outputMin.
Settings: gateChannel (a DataBus channel key)
pose/joint/rightElbow/bend, gate hand/left/detected. The elbow bend only drives the target when your left hand is visible. Hide your left hand to disengage the effect without losing the right-arm position.pose/body/velocity, gate input/key/space. Hold spacebar to enable the motion-driven effect. Release to freeze the target. Great for "arming" an effect from the control desk.audio/bass, gate audio/beat. The bass-reactive effect only fires exactly on the beat frame — between beats, nothing happens. Creates a very rhythmic, gated feel.On rising edge above the threshold, capture the current value and hold it forever — until a separate reset channel fires.
Settings: modeThreshold, resetChannel
hand/left/0/y → Target MaterialColor. Threshold 0.3, reset input/key/space. Move your hand to pick a colour; as soon as you lift it past the threshold the colour locks in. Press Space to unlock and pick a new one.pose/joint/rightElbow/bendNorm → Target Transform LocalPositionY. Threshold 0.5, reset hand/right/detected. Bend your arm to set an object's height; it stays there until you show your right hand to the camera.audio/bass → Target LightIntensity. Threshold 0.7, reset time/clock/pulse. The first loud bass hit freezes the light at peak brightness; the next BPM pulse releases it. Produces a strobe-hold effect tied to the song's tempo.Each time the signal crosses the threshold from below, step to the next value in sequenceValues[]. Wraps back to the start after the last value.
Settings: modeThreshold, sequenceValues (float array)
[0, 0.33, 0.66, 1.0] → Target AudioCrossfade. Each arm raise switches to the next of four audio tracks, cycling through them.[0, 90, 180, 270] → Target Transform LocalRotationY. Each gesture rotates the object 90° to the next position. Four gestures = full turn.[1, 0] → Target LightIntensity. Each trigger alternates between 1 and 0 — i.e. the binding is a clap-activated toggle.On rising edge above the threshold, snap to outputMax. Then decay back to outputMin over pulseDecay seconds.
Settings: modeThreshold, pulseDecay (seconds)
audio/beat, decay 0.15s → Target LightIntensity, out 0→10. Light flashes on every beat and fades quickly. Classic beat-reactive stage lighting.pose/joint/rightElbow/bendNorm, threshold 0.7, decay 0.5s → Target ParticleEmission, max 500. A quick arm bend triggers a half-second particle burst that fades away.input/key/space/down, decay 1.0s → Target Transform UniformScale, out 1→3. Press Space and the object pulses to 3× size, then shrinks back to normal over one second.These fields only matter when the corresponding mode is selected — they're hidden in the inspector otherwise.
| Field | Type | Used by |
|---|---|---|
| modeThreshold | float | Switch, Latch, Sequence, Pulse. The rising-edge trigger level, in remapped space. Default: 0.5. |
| gateChannel | string | Gate. The DataBus channel that must be > 0.5 for the signal to pass. |
| resetChannel | string | Latch. The DataBus channel that clears the latched value when it rises above 0.5. |
| sequenceValues | float[] | Sequence. The list of values to step through. Default: [0, 0.5, 1]. |
| pulseDecay | float | Pulse. Seconds to decay from outputMax back to outputMin. Default: 0.3. |
> 0.5 test on whatever's in the DataBus — they ignore your binding's remap. If the channel you're using for a gate doesn't cleanly cross 0.5, pre-process it through a ThresholdProcessor first so you get a clean 0/1 signal.The final stage before the target. A lerp-based low-pass filter: output = lerp(newValue, lastValue, smoothing). A value of 0 is instant; values approaching 0.99 feel molasses-slow.
| Field | Type | What it does |
|---|---|---|
| smoothing | float (0–0.99) | Smoothing factor. Default: 0. |
| Value | Feel | Best for |
|---|---|---|
| 0 | Instant — no smoothing at all | Triggers, switches, beat flashes, clap detection |
| 0.1–0.3 | Light smoothing | Most body tracking — removes MediaPipe jitter without killing response |
| 0.4–0.6 | Medium smoothing | Slow, flowing effects — colour sweeps, material blends |
| 0.7–0.9 | Heavy smoothing | Ambient, gradual changes — lighting washes, slow drift |
| 0.99 | Very slow — barely moves | Ultra-slow ambient drift, almost frozen |
SmoothProcessor upstream and leave the binding smoothing near 0.The targetType field selects which inspector fields are shown and which Unity API gets written each frame. One target per binding — if you need to drive a light's intensity and its colour, make two bindings pointing at the same Light.
Move, rotate, or scale a scene object on one axis.
What to drag: any scene object — the binding uses its Transform component.
| Field | Type | Notes |
|---|---|---|
| targetTransform | Transform | The object to move, rotate, or scale. |
| transformProperty | enum | LocalPositionX/Y/Z (metres) · LocalRotationX/Y/Z (degrees) · LocalScaleX/Y/Z · UniformScale. |
pose/joint/rightElbow/bend → Remap In 60–180, Out 0–360 → Target Cube → LocalRotationY.Deform a 3D mesh using morph targets (facial expressions, body morphs). Drives SkinnedMeshRenderer.SetBlendShapeWeight.
What to drag: a SkinnedMeshRenderer — the inspector dropdown shows all available blendshapes by name.
Output range: 0–100 (Unity blendshapes use 0–100, not 0–1).
| Field | Type | Notes |
|---|---|---|
| targetMesh | SkinnedMeshRenderer | The mesh that holds the blendshapes. |
| blendShapeIndex | int | Index in the mesh's blendshape list. Use the inspector dropdown. |
| blendShapeName | string | Optional: set blendShapeIndex = -1 and this name is resolved to an index on first Apply. Handy if your mesh reorders blendshapes. |
face/blendshape/jawOpen → Remap In 0–1, Out 0–100 → Target Character mesh → "MouthOpen" shape.Sets a float parameter on an Animator Controller continuously every frame. Use it for blend trees, speed multipliers, or any parameter that should track a smooth value.
What to drag: an Animator component.
Output range: 0–1 typically, but can be any float range your blend tree expects.
| Field | Type | Notes |
|---|---|---|
| targetAnimator | Animator | The Animator component on the character/object. |
| animatorParam | string | Parameter name — must match the Animator Controller exactly. |
pose/body/velocity → Remap In 0–1, Out 0–1 → Target Character Animator → Float "Speed".Sets a bool parameter on an Animator Controller. The parameter becomes true when the value is at or above boolThreshold, and false when below.
What to drag: an Animator component.
| Field | Type | Notes |
|---|---|---|
| targetAnimator | Animator | The Animator component. |
| animatorParam | string | Parameter name — must match the Animator Controller exactly. |
| boolThreshold | float | Value at or above this = true. Default: 0.5. |
face/blendshape/mouthSmileLeft, threshold 0.4 → Target Character Animator → Bool "IsHappy".Fires a trigger parameter once when the value crosses above boolThreshold (rising edge). The value must dip back below the threshold before the trigger can fire again — no repeated firing while held.
What to drag: an Animator component.
| Field | Type | Notes |
|---|---|---|
| targetAnimator | Animator | The Animator component. |
| animatorParam | string | Parameter name — must match the Animator Controller exactly. |
| boolThreshold | float | Rising-edge threshold. Default: 0.5. |
pose/joint/rightUpperArm/raiseNorm, threshold 0.3 → Target Character Animator → Trigger "Wave".Drive any numeric shader property — metallic, smoothness, emission strength, dissolve amount, custom properties on your own shaders. Writes to an instance of the material, not the shared asset.
What to drag: a Renderer (MeshRenderer / SkinnedMeshRenderer).
| Field | Type | Notes |
|---|---|---|
| targetRenderer | Renderer | The Renderer whose material instance will be written. |
| materialProperty | string | Shader property name, e.g. _Metallic, _EmissionStrength. Default: _Value. |
| materialIndex | int | Which sub-material on the Renderer to target. Default: 0. |
Common URP Lit properties: _Metallic (0–1), _Smoothness (0–1), _BumpScale (0–2).
audio/bass → Remap In 0–1, Out 0–1 → Target Floor renderer → _Metallic.Sweep through rainbow colours. The channel value 0–1 is treated as hue and converted to RGB via HSV. 0 = red, 0.33 = green, 0.66 = blue, 1 = red again.
What to drag: a Renderer. The binding writes to the named colour property on its material instance.
| Field | Type | Notes |
|---|---|---|
| targetRenderer | Renderer | Same as MaterialFloat. |
| materialProperty | string | Colour property name. Falls back to _BaseColor then _Color if the named property doesn't exist. |
| materialIndex | int | Sub-material index. |
| matColorSaturation | float | HSV saturation. 1 = vivid, 0 = greyscale. Default: 1. |
| matColorBrightness | float | HSV value/brightness. 1 = full, 0 = black. Default: 1. |
time/lfo/slow → Remap In 0–1, Out 0–1 → Target Sphere renderer → _BaseColor._BaseColor, not _Color. The built-in render pipeline uses _Color. For emission, URP Lit uses _EmissionColor and the material's Emission keyword must be enabled in the material inspector — otherwise you'll write a value that never appears.Set Light.intensity.
What to drag: a Light component (Point / Spot / Directional / Area).
Typical output range: 0–8. 0 = off, 1 = standard indoor light, 8 = very bright.
| Field | Type | Notes |
|---|---|---|
| targetLight | Light | The Light component. |
pose/body/velocity → Remap In 0–1, Out 0.2–8 → Target Point Light → LightIntensity.Set Light.range — how far a Point or Spot light reaches before falling off.
Typical output range: 1–50. Has no effect on Directional lights.
audio/bass → Remap In 0–1, Out 3–20 → Target Point Light → LightRange.Set Light.color. Like MaterialColor, treats the value as hue and converts to RGB via HSV.
| Field | Type | Notes |
|---|---|---|
| targetLight | Light | The Light component. |
| lightColorSaturation | float | HSV saturation. Default: 1. |
| lightColorBrightness | float | HSV value/brightness. Default: 1. |
pose/landmark/rightWrist/y → Remap In −0.8–0.8, Out 0–1 → Target Spot Light → LightColor.Set emission.rateOverTime. The binding multiplies your output by maxEmissionRate so you can keep the output in a familiar 0–1 range.
| Field | Type | Notes |
|---|---|---|
| targetParticles | ParticleSystem | The particle system to drive. |
| maxEmissionRate | float | Upper bound in particles/second when output = 1. Default: 100. |
audio/amplitude → Remap In 0–1, Out 0–1 → Max rate 200 → Target Particle System.Set AudioSource.volume. The binding auto-plays the AudioSource on first apply if it has a clip assigned but isn't already playing.
What to drag: an AudioSource with a clip assigned. Enable Loop for continuous effects.
Output range: 0–1 (0 = silent, 1 = full).
hand/left/0/y → Remap In −0.5–0.5, Out 0–1 → Target AudioSource → AudioVolume.Set AudioSource.pitch. 0.5 = one octave down, 1 = normal, 2 = one octave up. Internally clamped to [−3, 3].
pose/body/velocity → Remap In 0–1, Out 0.8–1.5 → Target AudioSource → AudioPitch.Blend between two audio sources. v = 0 is full Source 1, v = 1 is full Source 2. Auto-plays both if they have clips.
What to drag: two AudioSources, each with a different clip. Enable Loop on both.
| Field | Type | Notes |
|---|---|---|
| targetAudio | AudioSource | Source 1 — fades in as output approaches 0. |
| targetAudio2 | AudioSource | Source 2 — fades in as output approaches 1. |
hand/left/0/y → Remap In −0.5–0.5, Out 0–1, Smoothing 0.3 → Target Track A + Track B.Play the audio when the value rises above audioPlayThreshold. Stop when it falls back below.
| Field | Type | Notes |
|---|---|---|
| targetAudio | AudioSource | The source to start/stop. |
| audioPlayThreshold | float | Rising-edge threshold for Play. Default: 0.5. |
pose/joint/rightUpperArm/raiseNorm, mode Switch, threshold 0.5 → Target AudioSource → AudioPlayStop.Moves the AudioSource's local position on the X axis (left/right). Creates spatial audio effects — the sound seems to move horizontally in 3D space.
What to drag: an AudioSource component. Must have Spatial Blend set to 1 (fully 3D).
Output range: -10 to 10 (metres from the source's origin).
hand/right/0/x → Remap In −1–1, Out −5–5 → Target AudioSource → AudioSpatialX.Moves the AudioSource's local position on the Y axis (up/down). Creates vertical spatial audio movement.
What to drag: an AudioSource component. Must have Spatial Blend set to 1 (fully 3D).
Output range: -10 to 10 (metres from the source's origin).
hand/left/0/y → Remap In −0.5–0.5, Out −3–3 → Target AudioSource → AudioSpatialY.Moves the AudioSource's local position on the Z axis (forward/back). Creates depth-based spatial audio movement.
What to drag: an AudioSource component. Must have Spatial Blend set to 1 (fully 3D).
Output range: -10 to 10 (metres from the source's origin).
pose/body/centre/z → Remap In −1–1, Out −5–5 → Target AudioSource → AudioSpatialZ.Set the decay time of an AudioReverbZone component found on the same GameObject as the AudioSource.
Output range: clamped to [0.1, 20] seconds.
pose/body/centre/z → Remap In −1–1, Out 0.5–10 → Target AudioSource → AudioReverbZone.Drives ANY public float, bool, or int field on ANY component — the most flexible target type. Specify the component type name and the field or property name, and the binding writes to it via C# reflection. If there's no dedicated target for what you want, this is the fallback.
What to drag: a GameObject that has the component you want to drive.
Supported member types: float, bool, int, double. Anything else (Vector3, string, Color) silently fails — check the Console for a warning.
| Field | Type | Notes |
|---|---|---|
| reflectionTarget | GameObject | The GameObject hosting the component. |
| reflectionComponentType | string | Class name, e.g. Light, FogController, PostProcessVolume. Case-insensitive Contains-match on short or full type name. |
| reflectionMemberName | string | Exact public field or property name. Private/serialised-private fields are not supported. |
audio/bass → Remap In 0–1, Out 0.1–2.5 → Target GameObject with MyVFXController script → field glowAmount.DriverBinding.cs and its switch statement. Reflection is slower than a direct write (still cheap, just not free) and has no inspector help.These six target types let any DataBus channel drive a Unity UI element in real time. They are the fastest way to build a HUD, dashboard, or interactive overlay that reacts to body movement, audio, or any other source. All six work with standard UnityEngine.UI components — no extra packages required. For TextMeshPro, use Reflection on the text property until dedicated TMP targets are added.
Drive a UGUI Slider.value. The Slider's own Min/Max range defines the visible bounds, so your outputMin / outputMax should match.
What to drag: a UGUI Slider component.
| Field | Type | Notes |
|---|---|---|
| targetSlider | Slider | The Slider whose value will be written each frame. |
pose/joint/rightElbow/bendNorm → Remap In 0–1, Out 0–1 → Target Slider (Min 0, Max 1).Set a Toggle.isOn based on whether the value crosses a threshold. Toggle is true when the value is at or above boolThreshold, false otherwise.
What to drag: a UGUI Toggle component.
| Field | Type | Notes |
|---|---|---|
| targetToggle | Toggle | The Toggle to drive. |
| boolThreshold | float | The value at or above which the toggle becomes ON. Default: 0.5. |
face/blendshape/mouthSmileLeft, threshold 0.4 → Target Toggle "HappyMode".Fire a Button.onClick event once on the rising edge above boolThreshold. Same rising-edge logic as AnimatorTrigger — the value must dip back below before the next click can fire.
What to drag: a UGUI Button component. Wire its onClick event in the inspector to whatever you want to trigger (load scene, play sound, advance dialogue, etc).
| Field | Type | Notes |
|---|---|---|
| targetButton | Button | The Button whose onClick fires. |
| boolThreshold | float | Rising-edge trigger level. Default: 0.5. |
pose/joint/rightUpperArm/raiseNorm, threshold 0.7 → Target Button "Confirm".Pulse binding mode for cleaner gesture-to-click behaviour. Pulse-mode signal is naturally a sharp rising edge, which makes it impossible to accidentally retrigger.Drive an Image.fillAmount (clamped 0–1). The most flexible UI target — works for horizontal bars, vertical bars, and radial gauges depending on the Image's Fill Method setting.
What to drag: a UGUI Image with Image Type = Filled in its inspector. Then choose the Fill Method (Horizontal / Vertical / Radial 90 / Radial 180 / Radial 360) to get the visual style you want.
| Field | Type | Notes |
|---|---|---|
| targetImage | Image | The Image whose fill amount will be written. Must have Image Type = Filled. |
pose/body/velocity → Remap In 0–1, Out 0–1 → Target Image (Filled, Horizontal).UGUITextValue on top of it for a complete dial widget.Set Image.color. Treats the value as hue and converts to RGB via HSV — same model as MaterialColor and LightColor. Saturation and brightness stay fixed.
| Field | Type | Notes |
|---|---|---|
| targetImage | Image | The Image whose color will be written. |
| imageColorSaturation | float | HSV saturation. Default: 1. |
| imageColorBrightness | float | HSV value/brightness. Default: 1. |
hand/right/detected → Remap In 0–1, Out 0–0.33 → Target Image (status indicator pill).Write the value into a UGUI Text using a C# format string. Great for live counters, percentage readouts, score displays, and "current value" labels next to gauges.
What to drag: a UGUI Text component.
| Field | Type | Notes |
|---|---|---|
| targetText | Text | The Text to write into. |
| textFormat | string | C# format string. The channel value is the only argument ({0}). Default: "{0:F2}". |
| Format | Output | Use case |
|---|---|---|
| {0:F0} | 5300 | Whole numbers — score, count, energy |
| {0:F2} | 0.75 | Two decimal places — debug values, raw channels |
| {0:P0} | 75% | Percentage — gauge labels, progress |
| {0:N0} | 1,117 | Thousand separators — large counters |
| Score: {0:F0} | Score: 5300 | Labelled value |
| {0:F1} m/s | 1.2 m/s | Value with units |
pose/body/velocity → Remap In 0–1, Out 0–9999 → Target Text → Format "{0:F0}".v.ToString("F2") silently. Test your format strings in Play mode and watch the Text update live.Drives a named property on a PaulXTrack component, which routes the value through OSC to PaulXStretch running inside Reaper. Set your output range to the property's display range — the binding produces the display value, and PaulXTrack handles the JUCE-skew normalised-to-OSC conversion internally.
| Field | Type | What it does |
|---|---|---|
| targetPaulXTrack | PaulXTrack | Drag a scene GameObject that has a PaulXTrack component (an AudioSlot). |
| paulXProperty | PaulXProperty | Which PaulXStretch parameter to control: StretchAmount, PitchShift, FreqShift, FilterLow, FilterHigh, Spread, Compress, MainVolume, Freeze. |
| Property | Output range | What it does |
|---|---|---|
| StretchAmount | 0.1 – 1024 | Time stretch factor. 1.0 = real-time. 10 = 10× slower. 1024 = drone. Log-skewed internally. |
| PitchShift | -24 – +24 | Semitones. ±12 = one octave. |
| FreqShift | -1000 – +1000 | Constant frequency offset in Hz. |
| FilterLow / FilterHigh | 20 – 20000 | Low/high cutoff in Hz. |
| Spread | 0 – 1 | Frequency spread (smearing). |
| Compress | 0 – 1 | Dynamic range compression. |
| MainVolume | -24 – +12 | Output gain in dB. |
| Freeze | 0 or 1 | Hold current spectral frame. Treated as bool (≥ 0.5 = frozen). |
EKO_Audio.RPP project loaded and OSC control surface active on port 8000. PaulXTrack sends OSC via PaulXDispatcher. If Reaper isn't running, the binding still evaluates but the audio doesn't change (graceful degradation).Drives a Unity-native audio filter property directly on a UnityAudioFX component. Zero latency — writes directly to Unity's audio components on the audio thread. No Reaper, no OSC, no network. Set your output range to the property's native range.
| Field | Type | What it does |
|---|---|---|
| targetUnityAudioFX | UnityAudioFX | Drag a scene GameObject that has an AudioSource + audio filter components + UnityAudioFX. |
| unityAudioFXProperty | UnityAudioFXProp | Which filter property to control (see table below). |
| Property | Filter | Range | What it does |
|---|---|---|---|
| Volume | AudioSource | 0 – 1 | Master volume. |
| Pitch | AudioSource | -3 – 3 | Playback speed. 1 = normal, 2 = octave up. |
| PanStereo | AudioSource | -1 – 1 | Stereo pan. -1 = full left, +1 = full right. |
| SpatialBlend | AudioSource | 0 – 1 | 0 = 2D, 1 = fully 3D positioned. |
| LowPassCutoff | AudioLowPassFilter | 10 – 22000 Hz | Frequencies above this are removed. Lower = more muffled. |
| LowPassResonance | AudioLowPassFilter | 1 – 10 | Resonant peak at the cutoff. Higher = sharper, more "synthy". |
| HighPassCutoff | AudioHighPassFilter | 10 – 22000 Hz | Frequencies below this are removed. Higher = thinner. |
| EchoDelay | AudioEchoFilter | 10 – 5000 ms | Time between echo repeats. |
| EchoDecay | AudioEchoFilter | 0 – 1 | How quickly echoes fade. Higher = longer tail. |
| EchoWet | AudioEchoFilter | 0 – 1 | Mix of echo effect. 0 = dry, 1 = full echo. |
| DistortionLevel | AudioDistortionFilter | 0 – 1 | Overdrive intensity. |
| ChorusRate | AudioChorusFilter | 0 – 20 Hz | Speed of the chorus modulation. |
| ChorusDepth | AudioChorusFilter | 0 – 1 | Intensity of the chorus effect. |
| ReverbDecayTime | AudioReverbFilter | 0.1 – 20 s | Length of the reverb tail. Short = room, long = cathedral. |
| ReverbDryLevel | AudioReverbFilter | -10000 – 0 dB | Dry signal level. Lower = less dry, more reverb-heavy. |
AudioLowPassFilter and the LowPassCutoff/Resonance properties appear. Remove it and they disappear. No manual wiring needed.DriverMappingRunner component. If you're starting fresh, create an empty GameObject called 4E_Runner and add the runner component. Also make sure the 4E_DataBus and a source (like 4E_PoseChannelSource) exist — see SetupGuide if you haven't done the initial wiring.DataFlowMonitor. Confirm that pose channels are being written. If nothing is flowing, fix the source first — bindings reading from an empty bus will silently do nothing.inputMin = your "rest" value, inputMax = your "full range" value.DriverMapping ScriptableObjects are template libraries — they store the recipe (channels, remap ranges, modes, curves, target types) but hold no scene references. They're reusable across any scene in the project.
The DriverMappingRunner in your scene has a sceneBindings list where actual scene object references live and persist with the scene. To get bindings from an asset into the runner, you deploy them.
sceneBindings list. The binding's recipe (channel, remap, mode, curve, target type) is copied — but the target field is left empty for you to assign.sceneBindings (matched by channel key + target type) are skipped to avoid duplicates.sceneBindings, and drag your scene objects into the target fields. These references persist with the scene — the asset keeps its templates clean for reuse.SkinnedMeshRenderer that has a mouth blendshape (e.g. jawOpen or mouthOpen).pose/joint/rightElbow/bendDirectBlendShapejawOpeninputMin (e.g. to 90°). If it never fully opens, lower inputMax (e.g. to 160°).0.7. If sluggish, lower to 0.3.pose/landmark/rightWrist/yDirectLightColorAdd a second binding on the same light — same channelKey, but target LightIntensity and output 0.5 → 4.0. Now raising your hand both cycles the hue and increases brightness.
You need a channel that spikes when you clap. Two options:
audio/beat from AudioAnalysisSource.pose/body/velocity as a proxy, tuning the threshold to your energy level.audio/beat (or your chosen trigger)PulseParticleEmissionEach time the beat channel crosses 0.5, emission snaps to 500/s and decays to 0 over 0.4s. The particle system pulses on each hit.
The first time your right elbow bends past halfway, capture that bend value and hold it. Press spacebar to release the lock. Useful for "aim and freeze" style interactions.
pose/joint/rightElbow/bendLatchinput/key/spaceMaterialFloat or whatever you want driven> 0.5 test. Key channels (input/key/space) work cleanly. For noisy analogue channels, pre-process with a ThresholdProcessor first.Each time you raise your right arm above the threshold, the binding steps to the next value in the sequence. Useful for cycling colours, advancing to the next song section, or stepping through camera angles.
pose/landmark/rightWrist/ySequence[0.0, 0.25, 0.5, 0.75, 1.0]MaterialFloat (or Animator / Light / etc.)The sequence wraps — after the last value, the next trigger cycles back to index 0.
The signal passes through unchanged when the gate channel is above 0.5. When the gate drops, the output snaps to outputMin. This lets you engage and disengage an effect using a separate gesture.
pose/joint/rightElbow/bendGatehand/left/detected (opens gate when left hand is visible)hand/left/detected is 0 or 1 — it crosses 0.5 cleanly. For analogue channels (like a landmark Y position), pre-process with a ThresholdProcessor if it doesn't cross 0.5 cleanly.You've got your own FogController script on a GameObject, with a public float field density. You want to drive it from body velocity.
pose/body/velocityDirectReflectionFogControllerdensitySupported member types: float, bool, int, double. Anything else will fail to write silently — check the Console for the warning.
These recipes are the building blocks of the sample dashboard generated by Window > 4E > Create Sample Dashboard. Each one is a single binding (or two coordinated bindings) that produces one HUD widget. Combine them to build a full TouchDesigner-style control panel.
The generated dashboard lives under [4E_Dashboard] in the scene. It has a header with six clickable tabs and a body that shows one tab panel at a time. Each panel is a 4×3 grid of 12 cards, and the widget choice inside each tab is motion-matched to the data it visualises — vertical bars for vertical motion, horizontal meters for side-to-side motion, radial gauges for rotational motion.
| Tab | Purpose | Typical widgets |
|---|---|---|
| ALL | General mix — one of every widget type | Gauge, donut, key metrics, bars, big number, sliders, status, gesture button, histogram, two line graphs, heatmap |
| BODY | Pose joints, limb raises, velocity | Two radial gauges (elbow bends), two donuts (velocity + head tilt), vertical bars for arm/leg raise, horizontal KeyMetrics for widths / wrist X |
| HANDS | Fingertip positions + detection | Two radial gauges (hand openness proxies), two donuts (L/R detected), vertical bars for right fingertip Y, horizontal KeyMetrics for hand X |
| FACE | Blendshapes — jaw, smile, blink, brow | Gauges for jaw/eye-wide, donuts for pucker/cheek, vertical bars for blink + brow, horizontal KeyMetrics for smile + mouth stretch |
| dB REAPER | PaulXStretch parameters via OSC | Sliders and gauges for stretch amount, pitch shift, filter cutoffs, freeze toggle |
| dB UNITY | Unity built-in audio filters | Sliders and gauges for low-pass, high-pass, reverb, chorus, echo parameters |
Click a tab in the header to swap panels. Press F9 to show or hide the whole dashboard — the toggle component lives on the Canvas so it keeps working even while the root is hidden.
Wire Sample Dashboard (Self-Test LFOs) drives every widget from time/lfo/* so you can see the whole thing animate without a camera. Wire Sample Dashboard (Real Channels) swaps in motion-matched pose / hand / face channels per tab. Start with self-test to verify layout, then switch to real channels when you're ready to move.UISprite (or any sprite), Image Type = Filled, Fill Method = Radial 360, Fill Origin to Top.pose/joint/rightElbow/bendNormUGUIImageFillAmountpose/joint/rightElbow/bendNorm (same)UGUITextValue{0:F0}%Both bindings read the same channel but produce different visualisations of it. The smoothing on the ring keeps it from jittering; the label updates instantly.
audio/bassaudio/midaudio/highaudio/amplitudeUGUIImageFillAmountAdd four bindings to your DriverMappingRunner, one per bar, swapping the channelKey and targetImage. Press Play and you have a live audio EQ visualiser.
pose/body/velocityUGUITextValue{0:N0} (thousand separators) or {0:F0}The trick is heavy smoothing — without it the number flickers wildly because every frame's velocity is slightly different. With smoothing 0.6 the counter rises and falls smoothly like a real telemetry display.
hand/right/detectedDirectUGUIImageColorThe remap from 0–1 to 0.0–0.33 is the trick: hue 0 is red, hue 0.33 is green. Channel value 0 (no hand) → red, 1 (hand visible) → green.
If your channel is gradient (e.g. pose/landmark/nose/visibility), set the output range to 0.0–0.33 with no clamp tweaks — values around 0.5 will naturally land on yellow/amber.
pose/joint/rightElbow/bendNormUGUISliderValueNote: the binding writes the slider value every frame, so manual mouse drags get overwritten. If you want the slider to be truly bidirectional (binding writes when channel is "active", user controls when not), use Gate mode with a "performer present" channel.
onClick in the inspector to whatever you want to trigger — load scene, advance dialogue, fire VFX, etc.pose/joint/rightUpperArm/raiseNormPulseUGUIButtonTriggerWhy Pulse + ButtonTrigger together: Pulse turns the slow continuous arm-raise into a sharp spike, then decays. The button fires once on the rising edge and can't fire again until the pulse fully decays and you do the gesture again. Eliminates accidental retriggers when the user holds the pose.
The current AudioAnalysisSource only exposes three bands (audio/bass / audio/mid / audio/high). For a true 12-band histogram you'd need to extend AudioAnalysisSource to write per-FFT-bin channels. For now, two practical patterns:
Per-bar binding values:
UGUIImageFillAmountWindow > 4E > Create Sample Dashboard generates the full 6-tab dashboard built from these exact recipes. Then Wire Sample Dashboard (Self-Test LFOs) auto-binds every widget to time-based LFOs so you can press Play and see the whole thing animate without any input setup. Wire Sample Dashboard (Real Channels) swaps in the motion-matched pose / hand / face channels for live use. Press F9 at runtime to show / hide the dashboard.These recipes use the two audio target types. dB Reaper recipes require Reaper running with PaulXStretch on each track. dB Unity recipes work entirely in Unity with no external dependencies. Both can be driven by body movement, video feed, or the F11 channel slider panel.
AudioLowPassFilter + UnityAudioFX on the same GameObject.pose/joint/rightUpperArm/raiseNormUnityAudioFXPropertyLowPassCutoffThe most immediately satisfying audio binding. Raise your right arm and the sound opens up. Lower it and it goes muffled. Everyone understands it the first time.
AudioEchoFilter + UnityAudioFX.pose/landmark/leftWrist/yUnityAudioFXPropertyEchoDelaypose/body/velocityUnityAudioFXPropertyDistortionLevelPaulXTrack on a scene GameObject pointing at Reaper AudioSlot_01.pose/joint/rightUpperArm/raiseNormPaulXTrackPropertyStretchAmountThe signature PaulXStretch gesture. Arm down = real-time playback. Arm up = time bends into an ambient drone. The transition is smooth because of the log-skew on the stretch parameter — most of the slider travel covers the musically useful 1–50× range.
pose/joint/rightUpperArm/raiseNormSwitchPaulXTrackPropertyFreezeUses Switch mode so the freeze is binary (on/off), not gradual. The threshold of 0.7 means you have to deliberately raise your arm high — accidental shoulder shrugs won't trigger it. Combine with Recipe 18 for "stretch while moving, freeze when you stop".
pose/joint/headTilt/bendNormPaulXTrackPropertyPitchShiftpose/body/velocityUnityAudioFXPropertyReverbDecayTimeThe inversion is the key: most bindings are "more motion = more effect". This one is the opposite — stillness is the gesture. Standing perfectly still in front of the camera creates a 15-second reverb cathedral. Start moving and the space shrinks. Beautiful for meditative performance.
Every dashboard widget is driven by a DriverBinding — the same pipeline described in the Pipeline section. The job of a UI binding is to squeeze the useful slice of a channel's range into the widget's native display range. This section is a complete guide to doing that well.
A channel rarely spans the exact range a widget expects. A blendshape is 0–1, a bend angle is 0–180, a body velocity hovers between 0 and about 0.1 in seated use. A donut wants 0–1 fill. A big-number text might want 0–9999. A colour image might want 0–0.33 (hue red→green).
The remap stage is where you tell the binding: "when the channel is at this, the widget should show that". Get that right and the widget feels alive. Get it wrong and the widget is either pinned at full, frozen at empty, or jitters between two values with no middle.
| Knob | Lives in | What it controls |
|---|---|---|
| inputMin / inputMax | DriverBinding > Value Mapping | The slice of the channel you care about. Anything below inputMin reads as "empty", anything above inputMax reads as "full". |
| outputMin / outputMax | DriverBinding > Value Mapping | What the widget shows at "empty" and "full". For a radial gauge fillAmount, that's 0 and 1. For a big number, maybe 0 and 9999. |
| clamp | DriverBinding > Value Mapping | Leave on. Prevents the widget from overshooting past outputMin/outputMax when the channel exceeds your input range. |
| smoothing | DriverBinding > Smoothing | How much to average across frames (0 = instant, 0.9 = syrupy). Add enough to kill MediaPipe jitter; not so much that the widget feels laggy. |
That's it. Mode, response curve, invert — all useful, all optional. For 95% of dashboard widgets, these four knobs are the whole job.
Say you're driving a donut chart from face/blendshape/mouthSmileLeft. The channel technically goes from 0 to 1, but in practice the blendshape only ever reaches 0.6 with a big grin, and anything below 0.3 is just resting face noise. You want:
face/blendshape/mouthSmileLeftUGUIImageFillAmountface/blendshape/mouthSmileLeft — same channelUGUITextValue{0:F0}% — zero decimals, trailing %0.2 (not smiling) → below inputMin → ring = 0, label = "0%".0.3 (starting to smile) → exactly at inputMin → ring = 0, label = "0%".0.45 (halfway through your range) → (0.45 − 0.3) / (0.6 − 0.3) = 0.5 → ring = 0.5, label = "50%".0.6 (full grin) → at inputMax → ring = 1.0, label = "100%".0.8 (even bigger grin, somehow) → clamped → ring = 1.0, label = "100%".
Both bindings share the same channel and the same input range. Only the output range differs, because the donut ring natively wants 0–1 and the label natively wants 0–100. This twin-binding pattern — one for the visual, one for the number — is how every gauge / donut card in the sample dashboard is wired.
Guessing inputMin / inputMax is the most common source of "my widget doesn't move" bugs. Don't guess — measure.
smile into the search field).inputMax to your comfortable peak, not the theoretical max. If the real peak is 0.6 and you use 1.0, the widget will only ever fill to 60% — and that last 40% of "no one can reach it" range is wasted visual space.| Widget target | outputMin | outputMax | Notes |
|---|---|---|---|
| UGUIImageFillAmount | 0 | 1 | Native Unity range. Same for radial gauges, donuts, and vertical / horizontal bars. |
| UGUISliderValue | 0 | 1 | Assuming the Slider's Min/Max are 0 and 1, which the generator uses. |
| UGUIImageColor (hue) | 0.0 | 0.33 | 0 = red, 0.17 = yellow, 0.33 = green. Leave saturation/brightness at 1. |
| UGUIImageColor (full spectrum) | 0 | 1 | Full hue wheel. Good for ambient "channel activity" backgrounds. |
| UGUITextValue — percent | 0 | 100 | Pair with {0:F0}% format. |
| UGUITextValue — big counter | 0 | 9999 | Pair with {0:N0} for thousand separators. Use heavy smoothing (0.4–0.6). |
| UGUITextValue — degrees | 0 | 180 | Pair with {0:F0}°. Feed from raw bend channel (not bendNorm). |
| UGUIToggleValue | — | — | Remap doesn't apply. Uses boolThreshold instead — default 0.5. |
| UGUIButtonTrigger | — | — | Same. Combine with Pulse mode to fire cleanly once per gesture. |
| Widget | Suggested smoothing | Why |
|---|---|---|
| Radial gauge / donut | 0.15 – 0.25 | The eye reads rings as analog meters — small jitter reads as broken. Moderate smoothing lands in the sweet spot. |
| Horizontal key metrics | 0.15 – 0.25 | Same as gauges. If the value also drives a label, use the same smoothing on both bindings so they stay in sync. |
| Vertical / horizontal bar chart | 0.10 – 0.20 | Lighter — bars look good bouncing with the signal. Too much smoothing makes them feel mushy. |
| Big number counter | 0.40 – 0.60 | Heavy. A counter that flickers between 2,347 and 2,349 every frame is unreadable. |
| Sliders (display-only) | 0.15 – 0.30 | Medium. The handle position needs to feel physical, like a real fader. |
| Status pills (hue colour) | 0.10 – 0.20 | Light. If the channel is binary (hand/*/detected), you can set smoothing to 0 for instant snap. |
| Line graph | 0 (none) | The graph already smooths visually by plotting history. Adding smoothing here gives you double filtering and hides the detail. |
| Heatmap cells | 0.15 | Same logic as bars. |
| Gesture button (Pulse mode) | 0 | Pulse needs a crisp rising edge. Smoothing the input defeats the purpose. |
The four knobs above cover most cases. These two are for when a linear 0→1 response doesn't feel right.
channelKey at the top and an expandable Value Mapping foldout with the four knobs.Wire Sample Dashboard (…) wipes and regenerates every dashboard binding. If you've hand-tuned values in the Inspector and then re-run the wire menu, your edits are gone. Either stop re-running it, or edit the wire code in SampleDashboardGenerator.cs to bake your tuned values into the regeneration.Real performances usually layer multiple bindings on the same object or channel. These are starting points — drop all the rows into one DriverMappingRunner's Scene Bindings list, adjust to taste, press Play.
A single spotlight reacts to your movement, music, and a slow colour drift all at once.
| # | Source | Target | Remap | Mode | Result |
|---|---|---|---|---|---|
| 1 | pose/body/velocity | LightIntensity | 0→1 / 0.2→8 | Direct | Move = bright |
| 2 | time/lfo/slow | LightColor | 0→1 / 0→1 | Direct | Rainbow cycle |
| 3 | audio/beat | LightIntensity | 0→1 / 0→10 | Pulse 0.15s | Beat flash |
Note: bindings 1 and 3 both drive LightIntensity — the Pulse binding writes after the continuous one each frame, so the flash overrides. If you want them to add instead, route binding 3 through a Reflection target on an intermediate script.
Gesture-controlled audio mixing. Hand crossfades between two tracks, body velocity drives tempo, right-hand visibility plays or pauses the whole thing.
| # | Source | Target | Remap | Mode | Result |
|---|---|---|---|---|---|
| 1 | hand/left/0/y | AudioCrossfade | −0.5→0.5 / 0→1 | Direct, Smooth 0.3 | Hand height = track blend |
| 2 | pose/body/velocity | AudioPitch | 0→1 / 0.9→1.2 | Direct, Smooth 0.5 | Movement = tempo |
| 3 | hand/right/detected | AudioPlayStop | 0→1 / 0→1 | Switch 0.5 | Show right hand = play |
A rigged character mirrors your face and head in real time. Bindings 1 and 2 drive facial blendshapes; binding 3 tilts the head with yours.
| # | Source | Target | Remap | Mode | Result |
|---|---|---|---|---|---|
| 1 | face/blendshape/jawOpen | BlendShape "MouthOpen" | 0→1 / 0→100 | Direct | Your mouth = character mouth |
| 2 | face/blendshape/eyeBlinkLeft | BlendShape "EyeBlinkL" | 0→1 / 0→100 | Direct | Your blink = character blink |
| 3 | pose/joint/headTilt/bendNorm | Transform RotationZ | 0→1 / −15→15 | Direct, Smooth 0.2 | Head tilt = character tilt |
Particle emission layered from continuous motion (velocity), discrete pulses (bass hits), and hand-controlled size.
| # | Source | Target | Remap | Mode | Result |
|---|---|---|---|---|---|
| 1 | pose/body/velocity | ParticleEmission (200) | 0→1 / 0→1 | Direct | Movement = particles |
| 2 | audio/bass | ParticleEmission (500) | 0→1 / 0→1 | Pulse 0.3s | Bass hit = burst |
| 3 | hand/left/0/y | Transform UniformScale | −0.5→0.5 / 0.5→3 | Direct, Smooth 0.4 | Hand height = particle size |
DriverMappingRunner has a Mapping Library list. Drag multiple DriverMapping assets into it, set the Swap Key Path (default m), and each press cycles to the next asset. The active asset replaces the assetMapping slot and its bindings take effect immediately.
| Field | Type | Notes |
|---|---|---|
| mappingLibrary | List<DriverMapping> | The assets to cycle through. Must be non-empty to enable swapping. |
| swapKeyPath | string | Input System key path, e.g. m, space, digit1. Default: m. |
| runInLateUpdate | bool | If true, bindings apply in LateUpdate (after animation); if false, in Update. Default: true. |
channelKey. Channel names are case-sensitive and use forward slashes.active toggle is on.DriverMappingRunner exists in the scene and the binding is in its Scene Bindings list (or in an asset wired to its Asset Mapping slot).inputMin = your observed min, inputMax = your observed max.outputMin / outputMax match what the target expects (remember: blendshapes are 0–100, not 0–1).invert.smoothing to 0.4–0.7.SmoothProcessor upstream (spring-damper mode) and leave the binding smoothing at 0.modeThreshold is within your remapped output range. A threshold of 0.5 makes no sense if your output range is 0–100.> 0.5 test on the DataBus value, ignoring your binding's remap. Pre-process with a ThresholdProcessor if needed._BaseColor, not _Color. Emission is _EmissionColor.Renderer.materials[materialIndex], which creates an instance. Changes won't reflect in the shared asset — that's fine for runtime but can be confusing when inspecting.MaterialColor needs a colour property, not a float. If the named property doesn't exist, it falls back to _BaseColor, then _Color. If none exist, a warning is logged.[4E Binding] warnings logged during Initialise(). They tell you whether the component was found and whether the member was found.Light) and fully-qualified (UnityEngine.Light). The match is case-insensitive and uses Contains, so light also works.float, bool, int, and double members are supported. Strings, Vector3s, Colors etc. won't be written.| Key | Panel | Purpose |
|---|---|---|
| F8 | Calibration Tool | Verify coordinate orientation is correct for your camera |
| F9 | Sample Dashboard | Show / hide the generated [4E_Dashboard] overlay |
| F10 | Webcam Preview | See camera feed + all landmarks overlaid |
| F11 | Channel Sliders | Interactive testing — override values with sliders, no camera needed |
| F12 | DataBus Monitor | Read-only view of every channel value in real time |
hand/*/detected to create effects that only work when a specific hand is visible. Simple, reliable "kill switch".audio/beat for beat-reactive flashing effects. Pair with very short pulseDecay (0.1–0.2s) for snappy strobes.