Interactables¶
Make objects players can pick up, carry and throw — or levers, knobs and buttons they operate in place — and give them events (a gun that fires an animation + sound, a button that opens a door) all from one component, no scripting required. Drop SSInteractable (Add Component ▸ Social Scape/Interactable) on an object and configure it in the inspector; the runtime wires up the behaviour (and the networking, if you turn it on) when your world loads.
The one component¶
Everything is on SSInteractable. Pick a Mode, optionally turn on Networked, and optionally tick Use input / events to add events.
| Mode | For | How the player interacts |
|---|---|---|
| Grab | A prop, tool, ball, gun — anything picked up | Desktop: aim at it, right‑click to grab; carry, rotate, throw. VR: reach out and grip. |
| Constrained | A lever, knob, valve, door — moves in place on a hinge/slider | Grab the handle (right‑click / grip) and drag; its Joint limits the motion |
| Press | A button | Desktop: aim and left‑click. VR: point and pull the trigger. Fires in place — no carry. |
Every interactable needs a non‑trigger Collider
All three modes are hit against colliders (the desktop centre reticle raycast, and the VR controller's near‑grab / pointer), so the object needs a Collider — on the object itself or a child, and not marked Is Trigger. The runtime never adds or checks one: a missing (or trigger‑only) collider makes the object silently non‑interactable, with no error. The only exception is a flat uGUI Button on a world‑space Canvas, which is clicked through its graphic with no collider (see Press).
Grab¶
The default. The object can be picked up and carried.
| Field | What it does |
|---|---|
Carry mode |
RigidFollow — snaps precisely to your hold point (best for most props). PhysicsCarry — follows with spring physics, so it bumps and collides with the world. |
Grab mode |
Toggle (default) — grab to pick up, grab again to drop. Hold — hold the grab button/grip to carry, release to drop. Applies on desktop and VR. |
Follow strength |
(PhysicsCarry only) how tightly it follows — lower is looser/springier. Default 0.5. |
Fixed hold |
(Desktop) Lock the object to a fixed pose in the hand — a fishing rod, torch, tool — instead of the adjustable carry. Reveals Hold offset (right/up/forward, m), Hold rotation (deg), and an optional Hold anchor (a child transform marking the grip). The player can't scroll or rotate it; drop still works. VR ignores it (held in your real hand). |
Networked |
Replicate it so other players see it grabbed, carried and dropped (see Networking). |
Can be transferred |
(Networked only) On: another player can take it straight from your hands (a ball, a relay baton). Off (default): they must wait until you drop it. |
Two-handed |
(VR only) Allow two hands on it at once — the second hand aims it along the two‑hand axis (a rifle, shotgun, bow, pool cue). Desktop stays single‑grab. |
Sliding second grip |
(VR + two‑handed) Give it the pool‑cue feel: the object slides through your first (bridge) hand while the second hand strokes it back and forth and pivots it about the bridge. Set Slide axis to point down the object's length. Off = the second hand only aims it. |
Controls while carrying (desktop): scroll wheel = push away / pull closer · hold middle‑mouse + move = rotate it. Dropping/throwing is on the grab button (right‑mouse) itself:
- Grab mode = Toggle — a quick right‑click drops it; hold right‑click to charge a throw and release to launch. Either way it keeps your motion, so flicking it throws it.
- Grab mode = Hold — release the grab button to drop (a flick still throws it).
In VR you grip to hold and release to drop; a native flick throws it. Throwing respects the object's Rigidbody (mass, drag), so a heavy object throws slower.
Fixed hold — a fishing rod, torch or tool
Turn on Fixed hold and the object stops floating adjustably in front of the camera and instead sits at a fixed spot in the hand on desktop — ideal for a fishing rod you cast, a torch you carry, or any tool that should read as held, not carried. Set Hold offset (metres: right / up / forward from the view) and Hold rotation (degrees) for the pose, and tune them in Play mode until it looks right. If your model's pivot isn't at the grip, drop a child object at the handle and assign it as the Hold anchor. Pair it with a Grab Pose to also shape the fingers. In VR the object is already held in your real hand, so this setting is ignored there.
The same grab reaches for avatars, too
When you're not pointing at a grabbable prop, the same input (right‑click / grip) reaches for a nearby Social Bone or poseable limb on an avatar or NPC. A prop under the reticle always wins, so the two never clash — it's one grab that does the right thing.
Two‑handed aiming and the pool cue (VR)
Tick Two‑handed and a VR player can grab the object with both hands — the second hand aims it along its length (great for a rifle or bow). Add Sliding second grip and the object also slides through the first hand as the second hand strokes it — the classic pool‑cue feel. The whole two‑handed pose replicates to other players automatically. The feel (stroke length, roll) is best tuned in a headset.
Reading the stroke from a script. A Grab cue has no GetValue() — that reader is Constrained‑only and always returns 0 for a Grab. Instead, read the draw distance geometrically from the cue's own transform (it slides in world space and replicates), e.g. the tip‑to‑ball distance. Use Interactable.GetGrabCount() (returns 0/1/2) — == 2 means the VR two‑handed grip is active.
Throwing respects physics
Drops and throws use the object's Rigidbody (mass, drag, limits). A heavy object throws slower than a light one.
Constrained (levers, knobs, doors)¶
For something that moves in place rather than being carried away. You build the mechanism with a standard Unity Joint + Rigidbody; SSInteractable lets the player drag it and the Joint does the constraining.
- Add a Rigidbody and a Joint to the object (and a non‑trigger Collider, on the object or a child, so the handle can be grabbed):
- HingeJoint — a lever, a knob, a door, a hammer (rotates around an axis).
- ConfigurableJoint — a slider, a pull‑handle, a valve, a gun slide / pump / charging handle (moves along an axis). Free one linear axis, lock the rest, and set a Linear Limit = the travel distance.
- Set the Joint's anchor/axis and its limits (and a spring, if you want it to return).
- Set
SSInteractableMode = Constrained.Follow strengthcontrols how strongly it chases your hand.
Grabbing the handle drags it toward where you're aiming; the Joint keeps it on its hinge/slider and within its limits. Letting go lets the Joint settle (spring back, or rest at its limit). Works on desktop and in VR.
Shortcut for a sliding handle: the Slider component
For a straight‑line slide (a gun slide/pump, a drawer, a pull‑handle) you don't have to hand‑wire the joint. Add the SS Slider component (Social Scape/Slider), set the slide axis, travel, and spring return, and press Build / update slider — it bakes the Rigidbody + ConfigurableJoint + a Constrained interactable for you. For a gun slide, make the slider object a child of the gun body so it rides the gun.
Reading the handle from a script. How far the handle has moved is exposed as a 0–1 value — 0 at rest, 1 fully open/racked — for both a HingeJoint (angle across its limits) and a linear ConfigurableJoint (travel across its Linear Limit):
Interactable.GetValue()— read the 0–1 position any time (see the NexusScript interactables API).- Reserved callbacks the runtime calls on your script as the handle moves:
OnValueChanged(value)— every time it moves.OnValueMax()/OnValueMin()— once when it reaches the open/racked end / returns to rest.OnRackCycle()— once per full pull‑and‑return, e.g. pump the slide → chamber a round.
This is how you build a shotgun you pump to reload or a pistol you rack to chamber: put the slide/pump on a ConfigurableJoint (Constrained), gate your Fire event on a chambered flag, set chambered = true in OnRackCycle(), and clear it when you fire.
Constrained motion is local for now
The handle's motion (and its value) is currently local to each player — others don't yet see the slide move. The gun firing (a networked Held‑input event) is seen by everyone; the mechanical slide animation isn't replicated yet.
Press (buttons)¶
A momentary button. Set Mode = Press, tick Use input / events, and add an event with the On use trigger (below). Aim at it and left‑click (desktop) or point and pull the trigger (VR) to fire it — no carrying.
Press needs a Collider — for a flat UI panel, use a uGUI Button instead
A Press interactable is hit by a physics ray (the desktop reticle and the VR controller ray cast against colliders), so the object needs a Collider. That's the right tool for a 3D world button — a switch on a machine, a wall button. For a flat menu panel (a world‑space Canvas) don't use Press at all: a normal uGUI Button is clicked through its graphic with no collider — wire it to a script method with button.AddClickListener("Method"). See UI ▸ Clickable world UI.
Adding an interactable from an editor script
Wiring these up from a custom editor tool? Call SocialScape.SDK.SdkComponents.AddPressButton(go) or SocialScape.SDK.SdkComponents.AddInteractable(go, SSInteractionMode.Press) — the SocialScape.SDK assembly is auto‑referenced, so no reflection is needed. The stable assembly‑qualified name is "SocialScape.SDK.SSInteractable, SocialScape.SDK", SSInteractionMode = Grab(0) / Constrained(1) / Press(2), and the SerializedObject field path for the mode is mode.
Tooltip (the look‑at prompt)¶
A floating prompt shown above the object while a player looks at it — the "what does this do?" answer that sits next to the highlight.
Fill in Prompt (the action) and you're done:
| Field | What it does |
|---|---|
| Prompt (the action) | The label — Open the door, Pick up the cue. Blank = no prompt. |
| Show the input | Puts the input in front of the label: E Open the door. On by default. |
| Input to show | Optional. When the object has several inputs, name the Event or the SSInputActions action whose key to show. Blank = automatic. |
| Offset (m) | Nudges the prompt. It already sits above the object's visible top, measured from the renderers, so a big prop needs no tuning. |
Write the action, not the key
Put Open the door in the prompt — not Press E to open the door. The input is added for you, resolved from the binding that actually fires it, so the same prop reads E for a desktop player and the controller button in a headset. A key typed into the label can't do that, and it goes stale the moment you rebind.
Where the key comes from, first match wins:
- Input to show, if you named one — an Event on this object, or an action on an
SSInputActionscomponent. - Automatic — the first Held input event on this object that has a binding. Bind
<Keyboard>/eand the prompt readsEwith nothing else to fill in. - The built‑in interact button for the mode, for a Grab or Press with no input of your own: Right Mouse / Left Click on desktop, Grip / Trigger in VR.
The inspector shows you the composed line ("Players will see: …") as you type, so you can check it before testing. The prompt clears when you look away and when you pick the object up.
Use input / events¶
Tick Use input / events to reveal the Events list. Each event is a Trigger (when) → Effects (what), and you can add as many as you like. This is the no‑scripting way to make interactables do things.
Triggers (when an event fires):
| Trigger | Fires when… |
|---|---|
| Held input | While the object is held, a bound input fires it — a key, a mouse button, or a controller binding. This is how a gun shoots. |
| On pickup / On drop | The object is grabbed / released. |
| On hover enter / On hover exit | Your reticle starts / stops pointing at it. |
| On use | A generic "use" — what a Press button fires. |
| On custom | A named custom Signal you send from another event fires it — set the Signal name to match, so one event can chain into another. |
Binding an input (Held input): the Input field is a standard Unity input binding. Click + and add a binding — a key (e.g. E), a mouse button, or a controller control such as the right‑hand trigger. Add several bindings to one event and any of them fires it (so E and the right trigger both shoot).
Effects (what happens): add one or more per event —
| Effect | Does |
|---|---|
| Animator trigger / bool | Sets a parameter on an Animator (the shoot/reload animation). |
| Play audio | Plays an AudioSource (or a one‑shot clip) — the gunshot. |
| Toggle active | Enables/disables GameObjects (a laser sight, a light). |
| Spawn | Instantiates a prefab at a point with a forward impulse (a projectile, a muzzle flash). |
| Destroy | Removes GameObjects. |
| Set text | Writes a variable's value onto a TextMeshPro / UI Text label (Score: {value}). |
| Teleport | Moves the player who used it to a destination transform. |
| Video control | Play / Pause / Load / … a Video Player by name. |
| Event | Calls any method you wire up with a UnityEvent. |
Per event you can also set Networked (other players see/hear it — see below) and an optional NexusScript method to call, so you can mix easy effects with custom scripting on the same event.
Conditions, variables & operations too
Events here use the same logic engine as World Triggers: add Variables (Object / shared World / per‑player Player scope), gate an event with Conditions (incl. Player GUID allow‑lists for a VIP button), and use Operations (Increment, Wrap 0→9, Set…) as actions. See World Triggers ▸ Logic for the full vocabulary — it works identically on interactables.
Example — a gun¶
SSInteractable, Mode = Grab, tick Use input / events.- Add an event, name it "Shoot", Trigger = Held input, and bind a key (e.g.
F) and the right‑hand trigger (VR). (Left‑click stays free — grab and drop are on right‑click / grip.) - Add effects: Animator trigger (fire animation), Play audio (gunshot), Spawn (projectile at the muzzle with a forward impulse).
- Tick the event's Networked so everyone sees the shot.
- For a correct grip + kick, add a Grab Pose and Haptics. For real, server‑validated damage (not just a visual projectile), use the Weapon component — it fires automatically on left‑click (desktop) / trigger (VR), so with Weapon you can skip the Held‑input event above.
Now: right‑click / grip to pick up the gun; pull the trigger (or your bound key) to fire.
Example — a button that opens a door¶
SSInteractable, Mode = Press, tick Use input / events.- Add an event, Trigger = On use, effect Animator trigger (the door's open animation) or Toggle active. Tick Networked so everyone sees the door open.
Networking¶
Tick Networked to replicate an interactable so other players see it. Two things use it:
- The object itself (Grab) — others see it grabbed, carried and dropped, and the Can be transferred rule applies.
- Events — tick an event's Networked box and other players see/hear that event's effects (the shot animation, the muzzle flash, the door opening).
You don't configure anything else — the identifier and sync are handled for you (see World Objects ▸ Networking is automatic). Leave Networked off for purely local things (a hover glow only you need to see).
\"Networked\" means the two ticks above — not a script field
Don't confuse the component‑level Networked tick (replicates the object) with a per‑event Networked tick (replicates one event's effects). Both are unrelated to a NexusScript field a creator happens to name networked — that's just an ordinary script variable and has no bearing on replication.
Quick reference¶
| Want | Mode | Set up |
|---|---|---|
| A pickup‑and‑throw prop | Grab | Just the component (+ a Collider). |
| A gun / tool that fires | Grab | Use input / events → Held input → effects. |
| A two‑handed rifle / bow (VR) | Grab | Tick Two‑handed — the second hand aims it. |
| A pool cue (VR) | Grab | Tick Two‑handed + Sliding second grip; set the slide axis down its length. |
| A lever / knob / door | Constrained | Add a Joint + Rigidbody (+ a non‑trigger Collider); set limits. |
| A pump shotgun / rack‑to‑fire | Grab body + Constrained slide | Slide on a ConfigurableJoint; script OnRackCycle() → chambered, gate Fire. |
| A 3D button (prop / machine) | Press | Add a Collider; Use input / events → On use → effects (or script OnUsed()). |
| A button on a flat UI panel | (uGUI) | World‑space Canvas + Button — no collider; wire with Button.AddClickListener. See UI. |
| A "press E to…" prompt | any | Fill in Tooltip ▸ Prompt with the action only — the key is added for you. |
| Others see it | any | Tick Networked (and per‑event Networked). |
Making it feel right (VR + desktop)¶
Held objects can look and feel authored, not floaty:
- Hand poses — a Grab Pose makes the hand grip the object correctly (a gun grip, a mug handle), retargeted to any avatar in VR and on desktop.
- Weapons — the Weapon component gives real, server‑validated hitscan/area damage (with recoil + muzzle flash), instead of a purely visual spawned projectile.
- Haptics — a Haptic Feedback component adds a click on grab, a kick on fire.
Next¶
- React to the world (timers, zones, players joining) with the same logic → World Triggers & Logic
- World setup → Worlds · moving platforms & zones → World Objects
- Health, damage & respawn → Health & combat
- Custom logic beyond effects → NexusScript
Component class names (for scripts and search): SSInteractable (+ SSInteractableTooltip renders the look-at prompt, SSGrabPose for grips, SSWorldTriggerInteractable for OnInteract triggers).