Skip to main content

Stage 6: Hidden Hazard Field + reveal wave

Course progressStage 6 of 10
~50 min
Before you start

Make sure you've finished Stage 5: Fireball Cannon + player launcher. You'll reuse your Stage 4 KillBricks scan and the GetUserCFrame hand-reading from Stage 1 — both should already be in your game.

Build

a field of faint, deadly tiles crossed with bounce pads

Learn

how one good scan powers new hazards for free, and how to reveal danger with your hand

Ship

a hazard field you scout by waving your VR hand to light up the hidden tiles

The big idea

This stage is a test of nerve: a field of tiles where some are deadly — and they're nearly invisible. On a screen you can just make out faint ghostly tiles; you cross by reading them carefully and using bounce pads to leap the worst clusters.

Here's the satisfying part: you barely write any new code. In Stage 4 you built a Killer scan that makes any tagged part deadly. So to make these hazards kill, you just tag them Killer — your old script already handles the rest. That's the whole reward of a good pattern: new content, no new wiring. (Stage 4's Connect prompt promised you this exact moment.)

The VR half is a brand-new sense: the reveal wave. Sweep your hand across the field and any hidden tile your hand passes near lights up bright and solid — like running your palm over a wall to feel for a hidden door. You scout the safe lane with your arm before you ever step. It reuses the hand-reading from Stage 1 and the smooth easing from Stage 5; you're combining three old ideas into something that feels totally new.

New words
Transparency
how see-through a part is: 0 is solid, 1 is invisible; 0.7 is a faint ghost
attribute (Hidden)
a second tag, separate from Killer, marking which parts the reveal wave should light up
reuse
letting code you already wrote handle new things — here, the Killer scan powers new hazards with zero edits
proximity
nearness; we light a tile when your hand's distance to it is small
ease (lerp)
sliding a value toward a target a little each frame for a smooth fade — the Stage 5 pattern again

Build it

Step 1 — Build the hazard field

A wide thin floor, studded with faint deadly tiles.

Build this part

HazardField

Block
Open recipe
Size
30 × 1 × 24
Color
Dark stone grey
Material
Slate
Anchored
✓ Yes
Place
Just past the Stage 6 pad — the floor you cross

This floor is safe to walk. The danger sits on top of it.

Now place several deadly tiles flush on top of the field. Make them faint so they're a real challenge to spot. Build four to six.

Build this part

Hazard_1

Block
Open recipe
Size
4 × 1 × 4
Color
Really red
Material
Neon
Anchored
✓ Yes
Place
Somewhere on the HazardField, flush with its top

Set Transparency to 0.7 (faint). After building, add TWO attributes in Step 1.1.

Build this part

Hazard_2

Block
Open recipe
Size
4 × 1 × 4
Color
Really red
Material
Neon
Anchored
✓ Yes
Place
Elsewhere on the field — leave a weaving safe path between tiles

Repeat for Hazard_3, Hazard_4, and as many more as you like (Hazard_5, Hazard_6). Scatter them so there's a winding safe route, but make it tight enough to be scary. Set every hazard's Transparency to 0.7.

1.1 Tag every hazard with TWO attributes

Each hazard needs two labels: one to make it deadly (reusing Stage 4), one to make it revealable.

  • Select Hazard_1. In Properties → Attributes, add:
    • Name: Killer. Type: boolean. Value: checked (true).
    • Name: Hidden. Type: boolean. Value: checked (true).
  • Do the same for every other hazard tile.

Killer makes it deadly (old code). Hidden marks it for the reveal wave (new code).

Step 2 — Make them deadly with NO new script

Press ▶ Play and step on a faint red tile. You die and respawn.

You didn't write a kill script. Your Stage 4 KillBricks script scans for every Killer part when the game starts — these new tiles match, so they're already deadly. This is the payoff of the pattern: you added a whole new hazard type by ticking one checkbox.

If a hazard doesn't kill you

Either the tile is missing its Killer attribute, or your KillBricks script from Stage 4 isn't in ServerScriptService. The scan only catches parts that exist when it runs, so build your tiles before pressing Play.

Step 3 — Add bounce pads

Bounce pads help you leap a tight cluster of hazards. This is the same idea as your Stage 2 jump pad — reuse the pattern.

Build this part

BouncePad_1

Block
Open recipe
Size
5 × 1 × 5
Color
Lime green
Material
Neon
Anchored
✓ Yes
Place
On a safe spot in the field, before a tricky cluster

Insert a server Script into BouncePad_1:

local pad = script.Parent
local BOUNCE_POWER = 75
local onCooldown = {}

pad.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
local root = character and character:FindFirstChild("HumanoidRootPart")
if not (humanoid and root) then return end
if onCooldown[character] then return end
onCooldown[character] = true

local v = root.AssemblyLinearVelocity
root.AssemblyLinearVelocity = Vector3.new(v.X, BOUNCE_POWER, v.Z)

task.wait(0.4)
onCooldown[character] = nil
end)

Add a second bounce pad or two if your field is wide. Press ▶ Play and bounce over a cluster. Recognize this script? It's your jump pad with a new name — you're reusing what you already know.

Step 4 — Place the Stage 7 checkpoint

  • Insert a SpawnLocation on the far side of the field. Size [6, 1, 6], anchored, a new color (try Deep orange). Check AllowTeamChangeOnTouch, uncheck Neutral, match TeamColor.
  • Add a StageNumber attribute (number) = 7.
  • Add a Team named Stage 7, matching TeamColor, AutoAssignable unchecked.

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

Step 5 — Add the VR reveal wave

Open VRController. This reads your right hand each frame and brightens any Hidden tile your hand sweeps near. It reuses the hand-to-world math from Stage 1 and the easing from Stage 5. Paste at the bottom:

-- ===== VR hazard reveal wave (added in Stage 6) =====
local REVEAL_RANGE = 8 -- how close your hand must sweep to light a tile
local FAINT = 0.7 -- resting transparency (matches what you set in Studio)

-- Find every tile tagged Hidden, once.
local hiddenTiles = {}
for _, part in ipairs(workspace:GetDescendants()) do
if part:IsA("BasePart") and part:GetAttribute("Hidden") then
table.insert(hiddenTiles, part)
end
end

RunService.RenderStepped:Connect(function()
if not VRService.VREnabled then return end
local handCFrame = camera.CFrame * VRService:GetUserCFrame(Enum.UserCFrame.RightHand)
local handPos = handCFrame.Position

for _, tile in ipairs(hiddenTiles) do
local near = (tile.Position - handPos).Magnitude <= REVEAL_RANGE
local target = near and 0 or FAINT -- near: solid, else: faint
tile.Transparency = tile.Transparency + (target - tile.Transparency) * 0.2
end
end)

Press ▶ Play on your laptop. The tiles stay faint, Output stays clean — there's no headset hand to sweep, so the loop is skipped. That clean run is today's pass; the reveal lights up at the Stage 10 playtest.

In VR

Standing at the edge of the field, sweep your hand out over the tiles like you're brushing a table. Every hidden tile your palm passes near flares bright and solid for a moment, then fades back to a ghost as your hand moves on. You map the safe lane with your arm before you commit a single step — danger you can feel out, not just guess at.

Script anatomy

How the reveal wave lights danger near your hand

Three old ideas, one new feel: the attribute scan (Stage 1/4), the hand-to-world position (Stage 1), and the smooth ease (Stage 5). Notice you didn't learn a single new structure — you recombined.

local REVEAL_RANGE = 8
local FAINT = 0.7

local hiddenTiles = {}
for _, part in ipairs(workspace:GetDescendants()) do
if part:IsA("BasePart") and part:GetAttribute("Hidden") then
table.insert(hiddenTiles, part)
end
end

RunService.RenderStepped:Connect(function()
if not VRService.VREnabled then return end
local handCFrame = camera.CFrame * VRService:GetUserCFrame(Enum.UserCFrame.RightHand)
local handPos = handCFrame.Position

for _, tile in ipairs(hiddenTiles) do
local near = (tile.Position - handPos).Magnitude <= REVEAL_RANGE
local target = near and 0 or FAINT
tile.Transparency = tile.Transparency + (target - tile.Transparency) * 0.2
end
end)
  1. Lines 1–2Two tunable numbers.

    REVEAL_RANGE is how near your hand must pass to light a tile. FAINT is the resting transparency — keep it equal to the 0.7 you set in Studio so tiles settle back to the same ghostliness.

  2. Lines 4–9Scan for Hidden, not Killer.

    We collect only tiles tagged Hidden. That keeps the reveal focused on this field instead of also lighting up Stage 4's kill bricks. Same scan shape as before, pointed at a different tag.

  3. Lines 13–14Where is the hand in the world?

    Exactly the Stage 1 climb math: the camera CFrame times the hand's VR offset gives the hand's real-world spot, so we can measure its distance to each tile.

  4. Lines 16–20Light the near ones, fade the rest.

    For each tile, if the hand is within range the target is 0 (solid); otherwise FAINT. The ease line slides each tile's transparency a fifth of the way toward its target every frame, so tiles glow on and fade off smoothly as your hand sweeps past.

Understand it

The deadly half of this stage is the reuse lesson made real. You created a brand-new kind of hazard and wrote zero lines to make it deadly — because Stage 4's Killer scan was built to handle any tagged part. This is why programmers obsess over patterns: a good one turns "build a new feature" into "tick a box." The bounce pad made the same point — it's literally your jump pad again.

The reveal wave is the recombination lesson. Look at what it's made of: a Hidden-attribute scan (you've done attribute scans since Stage 1), the hand-to-world position (Stage 1's climb), and the smooth ease (Stage 5's fade). Not one new structure — yet the result is a mechanic that exists in almost no other game. That's how real game features get built: not from exotic new code, but from familiar pieces snapped together in a fresh shape.

We kept the tiles faintly visible (0.7) instead of fully invisible so a laptop player still has a fair chance. The VR reveal isn't required to win — it's a power, an advantage your hands give you. Good VR design adds delight without locking out the people who don't have a headset.

Try this

Learning beat

Try this

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

Predict first

REVEAL_RANGE is 8. Predict how the reveal feels at 2 (tiny) versus 25 (huge). One makes you trace each tile precisely; one lights the whole field at once. Which is more fun to play — and why might "too helpful" be a worse game than "just helpful enough"?

Compare

The tiles rest at FAINT = 0.7. Try 0.95 (almost invisible) and 0.4 (clearly visible). With 0.4, does the reveal wave still feel worth using? What does that tell you about how a power's value depends on how hard the base challenge is?

Connect

Your reveal wave finds parts by the Hidden tag. Stage 8 has a spinning arm you'll want to grab. What attribute might you put on that so a future script can find grabbable parts? You're building a habit: tag the thing, then scan for the tag.

Test your stage

  • Press ▶ Play and step on a faint red tile — you die and respawn (no new kill code needed).
  • Cross the field by weaving the safe lane; use a bounce pad to leap a tight cluster.
  • Touch the Stage 7 pad, reset, and confirm you respawn there.
  • Output is empty on a clean Play — no errors from the bounce pad or VRController.
  • Confirm every hazard has both Killer and Hidden attributes and Transparency 0.7.
  • Design check. Is there a real safe path, or did a hazard sneak into the only route? Walk it yourself with hazards at 0 transparency to check it's possible, then set them back to 0.7. A field with no safe lane isn't hard — it's broken.

If it breaks

  • The tiles don't kill me. They're missing the Killer attribute, or the Stage 4 KillBricks script isn't in ServerScriptService, or you added tiles after pressing Play (the scan runs once at start).
  • The reveal lights up my Stage 4 kill bricks too. Those have Killer but not Hidden. If they're lighting up, you scanned for Killer instead of Hidden in the reveal block — fix the attribute name.
  • camera is red in VRController. The reveal reuses the local camera line from Stage 1 — make sure it's still at the top of the file.
  • Tiles flash on and never fade off (in VR). Your FAINT value doesn't match the tile's resting transparency, or the ease line is missing. They should settle back to 0.7.
  • Nothing reveals on my laptop. Expected — no headset means no hand to sweep, so the loop is skipped. Verified at the Stage 10 playtest.
Coach notes

This is the "it all comes together" stage. Make the reuse explicit and loud: when a camper ticks Killer and the tile kills with no new code, stop the room and name it — "you just added a feature by recombining, not rewriting." That realization is the whole point of the course's spiral design.

The most common real bug is a hazard accidentally blocking the only safe path. Use the design-check trick: temporarily set all hazards to Transparency 0, walk the lane to prove it's possible, then set them back to 0.7. Build the field solvable first, scary second.

As always: the reveal wave can't be felt on a laptop; the clean Play is the pass. If campers want to verify their reveal logic, have them temporarily drop the if not VRService.VREnabled then return end guard and use their mouse — but remind them to put it back.