Skip to main content

Stage 8: Spinning KillBricks + grab & ride

Course progressStage 8 of 10
~50 min
Before you start

Make sure you've finished Stage 7: Rolling Rocks + lean to dodge. You'll reuse the gripping flag and GetUserCFrame hand-reading from your Stage 1 climb — the grab is the climb's trigger, pointed at a new target.

Build

a long arm sweeping over a deadly gap, anchored and spinning

Learn

how to spin a part smoothly every frame, and how to lock yourself onto a moving thing

Ship

a sweeping arm you cross by timing on a laptop — or grab and ride in VR

The big idea

A giant arm sweeps in slow circles over a deadly drop. Fall into the KillBrick pit below and you respawn. The arm is your way across — but it never stops moving.

You'll spin it yourself, in code, the smooth way: every frame, nudge its rotation a tiny bit with CFrame.Angles. Run that on Heartbeat (which fires every physics step) and the arm turns in a continuous, even sweep. It's the same "do a little, every frame" rhythm as the moving block from your very first stretch challenge — now driving a centerpiece.

On a laptop you beat it by timing: wait until the arm bridges the gap, then run across before it sweeps away. In VR you get something better — you grab and ride. Reach out, squeeze the trigger near the arm, and your body locks on; the arm carries you around the circle, and you let go when you're over the far side. The grab is literally your Stage 1 climb trigger, aimed at the arm instead of a wall. You're not learning a new move — you're pointing an old one somewhere new.

New words
Heartbeat
a RunService event that fires every physics step — where smooth, frame-by-frame motion lives
CFrame.Angles
a rotation you can multiply onto a part's CFrame to turn it
dt (delta time)
the seconds since the last frame; multiplying by it keeps motion even on any computer
ToObjectSpace
a CFrame method that gives one CFrame's position relative to another — how we 'lock on' to the arm
grab & ride
gripping a moving part so you're carried with it — the climb trigger, reused

Build it

Step 1 — Build the gap, pit, and exit

Build this part

SpinPath

Block
Open recipe
Size
14 × 1 × 14
Color
Medium stone grey
Material
Slate
Anchored
✓ Yes
Place
Just past the Stage 8 pad — the platform where you board
Build this part

KillBrickPit

Block
Open recipe
Size
40 × 1 × 40
Color
Really red
Material
Neon
Anchored
✓ Yes
Place
Far below the gap between SpinPath and the exit — the deadly floor

Add a Killer attribute (boolean, true). Your Stage 4 scan makes it deadly — no new code.

Build a far exit platform across the gap from SpinPath, the same size, with the deadly pit between them. The arm will sweep across this gap.

Step 2 — Build and spin the SweepArm

Build this part

SweepArm

Block
Open recipe
Size
28 × 2 × 4
Color
Bright blue
Material
Metal
Anchored
✓ Yes
Place
Centered over the middle of the gap, at platform height, long enough to reach BOTH platforms

Its center sits over the gap's center so the ends sweep in a circle. Anchored — the script turns it.

Insert a server Script into SweepArm and type:

local arm = script.Parent
local RunService = game:GetService("RunService")

local SPIN_SPEED = 35 -- degrees per second; slower = easier to board

RunService.Heartbeat:Connect(function(dt)
-- Turn the arm a little every frame, evenly on any computer.
arm.CFrame = arm.CFrame * CFrame.Angles(0, math.rad(SPIN_SPEED) * dt, 0)
end)

Press ▶ Play. The arm sweeps in slow circles over the pit. Wait until it lines up across the gap, then run along it to the exit before it turns away. Fall in the red pit and you respawn. Tune SPIN_SPEED and the arm's length until there's a fair window to cross. Fully testable today.

Step 3 — Place the Stage 9 checkpoint

  • Insert a SpawnLocation on the far exit platform. Size [6, 1, 6], anchored, a new color (try Toothpaste). Check AllowTeamChangeOnTouch, uncheck Neutral, match TeamColor.
  • Add a StageNumber attribute (number) = 9.
  • Add a Team named Stage 9, matching TeamColor, AutoAssignable unchecked.

Cross the arm, touch the pad, reset — you should respawn there.

Step 4 — Add VR grab & ride

Open VRController. This lets you grip the arm and ride it. It reuses your gripping flag (Stage 1), your hand-reading, and a new CFrame trick to lock on. Paste at the bottom:

-- ===== VR grab & ride (added in Stage 8) =====
local sweepArm = workspace:WaitForChild("SweepArm")
local GRAB_REACH = 10 -- how near your hand must be to grab the arm
local rideOffset = nil -- where you're locked onto the arm

RunService.RenderStepped:Connect(function()
if not VRService.VREnabled then return end
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root then return end

local handPos = (camera.CFrame * VRService:GetUserCFrame(Enum.UserCFrame.RightHand)).Position
local handNearArm = (sweepArm.Position - handPos).Magnitude <= GRAB_REACH

if gripping and (rideOffset or handNearArm) then
if not rideOffset then
-- Grab: remember exactly where you are on the arm.
rideOffset = sweepArm.CFrame:ToObjectSpace(root.CFrame)
end
-- Ride: hold that same spot as the arm sweeps around.
root.CFrame = sweepArm.CFrame * rideOffset
elseif rideOffset then
-- Let go: drop where you are.
rideOffset = nil
end
end)

Press ▶ Play on your laptop. Output stays clean and nothing changes — gripping only comes from a VR trigger, so there's nothing to grab. Today's pass is the clean run; the ride happens at the Stage 10 playtest.

In VR

Stand at the edge of SpinPath, reach toward the sweeping arm, and squeeze the trigger as it passes. You snap onto it — and now you're swinging around the circle, the pit gliding far below your feet. Watch the far platform come around, and at the right moment release the trigger to step off onto solid ground. It's the climb grip from Stage 1, but instead of pulling yourself up a wall, you're hitching a ride on a carousel over a chasm.

Script anatomy

How grab & ride locks you onto the arm

The grip is your Stage 1 trigger. The new idea is 'lock on': record your spot relative to the arm once, then re-apply it every frame so you move exactly as the arm moves.

local sweepArm = workspace:WaitForChild("SweepArm")
local GRAB_REACH = 10
local rideOffset = nil

RunService.RenderStepped:Connect(function()
if not VRService.VREnabled then return end
local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if not root then return end

local handPos = (camera.CFrame * VRService:GetUserCFrame(Enum.UserCFrame.RightHand)).Position
local handNearArm = (sweepArm.Position - handPos).Magnitude <= GRAB_REACH

if gripping and (rideOffset or handNearArm) then
if not rideOffset then
rideOffset = sweepArm.CFrame:ToObjectSpace(root.CFrame)
end
root.CFrame = sweepArm.CFrame * rideOffset
elseif rideOffset then
rideOffset = nil
end
end)
  1. Lines 1–3The arm, the reach, and where we're locked.

    We grab the SweepArm once. GRAB_REACH is how near your hand must be. rideOffset starts nil — it's empty until you actually grab, then it holds your spot on the arm.

  2. Lines 10–11Is your hand on the arm?

    Same hand-to-world math as the climb (camera CFrame times the hand offset), then a distance check to the arm. gripping comes free from your Stage 1 trigger handler.

  3. Lines 13–16Grab: record your spot relative to the arm.

    ToObjectSpace asks 'where am I, measured from the arm's own frame?' Saving that once is the lock-on. Because it's relative to the arm, it stays valid no matter how the arm turns.

  4. Line 18Ride: re-apply that spot every frame.

    sweepArm.CFrame * rideOffset rebuilds your world position from the arm's current rotation. Do it each frame and you're carried around perfectly, glued to the arm.

  5. Lines 19–21Let go: forget the lock.

    Release the trigger and rideOffset goes back to nil. We stop setting your CFrame, gravity takes over, and you drop onto the platform below your hands.

Understand it

The spin is the smooth-motion lesson finished. Back in the Stage 1 stretch you moved a block with wait() in a loop; here you use Heartbeat and multiply by dt. That dt is the secret to even motion: a fast computer runs more frames with smaller dt, a slow one fewer frames with bigger dt, and multiplying rotation by dt makes the arm turn the same speed on both. CFrame.Angles(0, angle, 0) is a pure turn around the up axis, and multiplying it onto the arm's CFrame each frame adds a little rotation — the foundation of every spinning thing in games.

Grab & ride is the lock-on lesson, and it's a CFrame superpower. ToObjectSpace converts your position into the arm's own coordinate system — "two studs out and one up, from the arm's point of view." That description doesn't change as the arm rotates, so re-applying it with sweepArm.CFrame * rideOffset every frame keeps you pinned to the same handhold while the world swings around you. It's the exact inverse trick of reading your hand's world position; together, ToObjectSpace and * offset are how games attach anything to anything — a sword to a hand, a turret to a tank, a player to a ride.

And notice the grab itself: zero new input code. The gripping flag from your Stage 1 climb already knows when the trigger is down. You just asked a different question with it — "am I near the arm?" instead of "am I near a wall?" That's the whole course in one move.

Try this

Learning beat

Try this

Three short experiments. Predict before you run, then test your guess.

Predict first

SPIN_SPEED is 35 degrees per second. Predict how the laptop crossing changes at 15 (slow) versus 90 (fast). One gives a generous window to run across; one barely lets you. Find the speed that's tense but fair — then notice the VR grab makes speed matter less. Why?

Compare

Grab & ride sets root.CFrame = sweepArm.CFrame * rideOffset every frame. Imagine instead you only set it once at grab time. What would happen as the arm kept turning — would you ride, or get left behind? What does that tell you about why the ride must run every frame?

Connect

ToObjectSpace + * offset attaches you to a moving thing. In Stage 10 you'll build a victory portal. If you wanted a trophy to float and spin attached to a pedestal, which two tools would you reach for? You've now got the kit to stick anything to anything.

Test your stage

  • Press ▶ Play — the SweepArm turns in a smooth, even circle over the pit.
  • Time a run across when the arm bridges the gap; reach the exit without falling.
  • Fall into the red KillBrickPit and confirm you respawn (no new kill code — the Stage 4 scan handles it).
  • Touch the Stage 9 pad, reset, and confirm you respawn there.
  • Output is empty on a clean Play — no errors from the spin script or VRController.
  • Design check. Is there a clear, learnable moment to cross — a beat where the arm lines up and you know it's time? If crossing feels like luck, slow SPIN_SPEED or lengthen the arm.

If it breaks

  • The arm wobbles or drifts instead of spinning in place. Its center must sit over the gap's center. If the center is off, it sweeps in a lopsided circle. Reposition so the pivot is centered.
  • The arm doesn't reach both platforms. Make it longer, or move the platforms closer. Its ends need to bridge the gap when aligned.
  • The pit doesn't kill me. KillBrickPit needs the Killer attribute, and your Stage 4 KillBricks script must be in ServerScriptService (it runs once at start, so the pit must exist before Play).
  • sweepArm errors in VRController. It does workspace:WaitForChild("SweepArm") — the part must be named exactly SweepArm in Workspace.
  • The ride is jittery (in VR). Setting CFrame every frame can fight the character's own physics a little. A slower SPIN_SPEED smooths it; full polish happens at the playtest.
  • Nothing to grab on my laptop. Expected — gripping only comes from a VR trigger. Cross by timing today; the ride is verified at the Stage 10 playtest.
Coach notes

Two big CFrame ideas land here, and they're worth slowing down for. First, dt: show what happens without it (multiply by a fixed number) — the arm spins at different speeds on different laptops. That's why every smooth-motion script multiplies by dt. Second, ToObjectSpace + * offset — the "stick anything to anything" pattern. Frame grab & ride as the climax of the reuse story: the grip is from Stage 1, the hand math is from Stage 1, and only the lock-on is new.

The most common build issue is an off-center arm that sweeps lopsided — eyeball the pivot over the gap center, or set the arm's Position to the gap center exactly. As always, the ride can't be felt today; a clean Play plus a successful timed crossing is the pass.