--[[ ======================================================================== Entity & Puzzle Chams - Rayfield UI ======================================================================== Game: Doors-like / Backrooms-style horror (uses workspace.Entities, workspace.Ignored.Interacts, GameSettings.currentLevel) Features: • Entity Chams -> Highlights every model in workspace.Entities (Howler, Starfish, Hounds, Smiler, TheWatcher, DeformedHowler, etc.) - works for ALL chapters. • Puzzle Chams -> Highlights ONLY the essential puzzle items per chapter. Excludes clutter like Locker, Drawer, Door, Beartrap, PartyPlushie, shelves, etc. How it works: • Entities are read live from workspace.Entities (auto-refresh). • Puzzle items are read from workspace.Ignored.Interacts by their ItemName attribute, filtered through an allowlist of essential puzzle types so we never highlight lockers, drawers or shelves. Usage: Paste into your executor, run, use the Rayfield UI. ======================================================================== ]] --====================== SERVICES ======================-- local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Workspace = game:GetService("Workspace") local RunService = game:GetService("RunService") local CoreGui = game:GetService("CoreGui") local LocalPlayer = Players.LocalPlayer --====================== RAYFIELD ======================-- local Rayfield local ok, err = pcall(function() Rayfield = loadstring(game:HttpGet('https://sirius.menu/rayfield'))() end) if not Rayfield then warn("[Chams] Failed to load Rayfield UI: " .. tostring(err)) return end --====================== STATE ======================-- local State = { EntityChamsEnabled = false, PuzzleChamsEnabled = false, EntityColor = Color3.fromRGB(255, 25, 25), -- outline (red) EntityFillColor = Color3.fromRGB(255, 0, 0), PuzzleColor = Color3.fromRGB(0, 255, 200), -- outline (cyan) PuzzleFillColor = Color3.fromRGB(0, 200, 255), FillTransparency = 0.45, OutlineTransparency = 0, ThroughWalls = true, } -- Track currently-applied Highlight instances so we can clean up. local EntityHighlights = {} -- [Model] = Highlight local PuzzleHighlights = {} -- [Instance] = Highlight --====================== ESSENTIAL PUZZLE ALLOWLIST ======================-- -- Anything NOT in this list is treated as clutter (lockers, shelves, -- drawers, doors, hazards, decorative items) and is NOT highlighted. local ESSENTIAL_PUZZLE_ITEMS = { -- Keys / access "Key", "Keycard", "CardLock", -- Tools needed to solve puzzles "Crowbar", "Woodplanks", "WoodPlanks", "Screwdriver", "Gasoline", "Matches", -- Puzzle interactables (keypads, levers, valves, wires, etc.) "Valve", "Level9Valve", "Wire", "Lever", "Plate", "Padlock", "Keypad", "Computer", "Level3Computer", "Level9Console", "Button", "Starbutton", "ContainerConsole", "MultiContainerConsole", "PlsdonateButton", -- Toll / coin puzzle "TollCoin", "TollDeposit", -- Hidden-secret paintings / book buttons (essential for puzzles) "Painting", "PaintingV2", "BookButton", } -- EXPLICITLY EXCLUDED (so the script never picks them up even if -- someone adds them to the allowlist by mistake): local EXCLUDED_ITEMS = { "Locker", "Drawer", "Door", "Beartrap", "PartyPlushie", "Shelf", "Shelf1", "Shelf2", "Bookshelf", } local function normalize(s) return s and string.lower(string.gsub(tostring(s), "%s+", "")) or "" end local EssentialSet = {} for _, v in ipairs(ESSENTIAL_PUZZLE_ITEMS) do EssentialSet[normalize(v)] = true end local ExcludedSet = {} for _, v in ipairs(EXCLUDED_ITEMS) do ExcludedSet[normalize(v)] = true end local function isEssentialPuzzle(itemName) local n = normalize(itemName) if n == "" then return false end if ExcludedSet[n] then return false end return EssentialSet[n] == true end --====================== HIGHLIGHT HELPERS ======================-- local HIGHLIGHT_NAME = "__ChamsHighlight" local function makeHighlight(target, outlineColor, fillColor, depthMode) if not target then return nil end local existing = target:FindFirstChild(HIGHLIGHT_NAME) if existing then return existing end local h = Instance.new("Highlight") h.Name = HIGHLIGHT_NAME h.Adornee = target h.FillColor = fillColor h.OutlineColor = outlineColor h.FillTransparency = State.FillTransparency h.OutlineTransparency = State.OutlineTransparency h.DepthMode = depthMode or Enum.HighlightDepthMode.AlwaysOnTop h.Parent = target return h end local function killHighlight(target) if not target then return end local h = target:FindFirstChild(HIGHLIGHT_NAME) if h then h:Destroy() end end --====================== ENTITY CHAMS ======================-- local function getEntitiesContainer() return Workspace:FindFirstChild("Entities") end local function refreshEntityChams() local container = getEntitiesContainer() if not container then return end -- Remove highlights for entities that no longer exist for model, h in pairs(EntityHighlights) do if not model.Parent or not model:IsDescendantOf(container) then if h then h:Destroy() end EntityHighlights[model] = nil end end -- Add highlights for new entities for _, ent in ipairs(container:GetChildren()) do if ent:IsA("Model") and not EntityHighlights[ent] then local h = makeHighlight( ent, State.EntityColor, State.EntityFillColor, State.ThroughWalls and Enum.HighlightDepthMode.AlwaysOnTop or Enum.HighlightDepthMode.Occluded ) if h then EntityHighlights[ent] = h end end end end local function clearEntityChams() for model, h in pairs(EntityHighlights) do if h then h:Destroy() end end table.clear(EntityHighlights) end --====================== PUZZLE CHAMS ======================-- local function getInteractsRoot() local ignored = Workspace:FindFirstChild("Ignored") if not ignored then return nil end return ignored:FindFirstChild("Interacts") end local function getItemNameFromInstance(inst) if not inst or not inst:IsA("Instance") then return nil end -- Direct attribute local n = inst:GetAttribute("ItemName") if n then return n end -- PrimaryPart attribute (for Models) if inst:IsA("Model") and inst.PrimaryPart then n = inst.PrimaryPart:GetAttribute("ItemName") if n then return n end end -- Some items put the attribute on a child part if inst:IsA("Model") then for _, d in ipairs(inst:GetDescendants()) do if d:IsA("BasePart") then n = d:GetAttribute("ItemName") if n then return n end end end end return nil end -- Walks the Interacts folder and returns a list of {target=Instance, name=string} -- for every essential puzzle item found. local function collectPuzzleTargets() local out = {} local root = getInteractsRoot() if not root then return out end local seen = {} for _, obj in ipairs(root:GetDescendants()) do -- Determine the ItemName on this object (or its parent if it's a part) local name = getItemNameFromInstance(obj) if not name and obj.Parent then name = obj.Parent:GetAttribute("ItemName") end if name and isEssentialPuzzle(name) then -- Use the Model parent if available, otherwise the part itself. local target = obj if obj.Parent and obj.Parent:IsA("Model") then target = obj.Parent elseif obj:IsA("Model") then target = obj end if target and not seen[target] then seen[target] = true table.insert(out, { target = target, name = name }) end end end return out end local function refreshPuzzleChams() -- Drop stale highlights for inst, h in pairs(PuzzleHighlights) do if not inst.Parent then if h then h:Destroy() end PuzzleHighlights[inst] = nil end end -- Apply new highlights for _, entry in ipairs(collectPuzzleTargets()) do local target = entry.target if not PuzzleHighlights[target] then local h = makeHighlight( target, State.PuzzleColor, State.PuzzleFillColor, State.ThroughWalls and Enum.HighlightDepthMode.AlwaysOnTop or Enum.HighlightDepthMode.Occluded ) if h then PuzzleHighlights[target] = h end end end end local function clearPuzzleChams() for inst, h in pairs(PuzzleHighlights) do if h then h:Destroy() end end table.clear(PuzzleHighlights) end --====================== REFRESH LOOP ======================-- -- Throttled loop instead of every Heartbeat - 0.25s is responsive enough -- and avoids lag spikes when the map re-streams puzzle items. local loopRunning = false local loopThread local function startLoop() if loopRunning then return end loopRunning = true loopThread = task.spawn(function() while loopRunning and (State.EntityChamsEnabled or State.PuzzleChamsEnabled) do if State.EntityChamsEnabled then local ok1 = pcall(refreshEntityChams) if not ok1 then warn("[Chams] entity refresh error") end end if State.PuzzleChamsEnabled then local ok2 = pcall(refreshPuzzleChams) if not ok2 then warn("[Chams] puzzle refresh error") end end task.wait(0.25) end loopRunning = false end) end local function stopLoop() loopRunning = false end --====================== BUILD RAYFIELD UI ======================-- local Window = Rayfield:CreateWindow({ Name = "Entity & Puzzle Chams", LoadingTitle = "Loading Chams...", LoadingSubtitle = "Rayfield UI", ConfigurationSaving = { Enabled = false }, KeySystem = false, }) --========== Chams Tab ==========-- local ChamsTab = Window:CreateTab("Chams", 4483362458) ChamsTab:CreateSection("Toggles") local EntityToggle = ChamsTab:CreateToggle({ Name = "Entity Chams", Description = "Highlights every entity in workspace.Entities (works for all chapters).", CurrentValue = false, Flag = "EntityChams", Callback = function(value) State.EntityChamsEnabled = value if value then refreshEntityChams() startLoop() Rayfield:Notify({ Title = "Entity Chams", Content = "Enabled - highlighting all entities.", Duration = 3, Image = 4483362458, }) else clearEntityChams() if not State.PuzzleChamsEnabled then stopLoop() end end end, }) local PuzzleToggle = ChamsTab:CreateToggle({ Name = "Puzzle Chams (essential only)", Description = "Highlights ONLY essential puzzle items. Lockers, drawers, shelves, doors are skipped.", CurrentValue = false, Flag = "PuzzleChams", Callback = function(value) State.PuzzleChamsEnabled = value if value then refreshPuzzleChams() startLoop() Rayfield:Notify({ Title = "Puzzle Chams", Content = "Enabled - highlighting essential puzzle items only.", Duration = 3, Image = 4483362458, }) else clearPuzzleChams() if not State.EntityChamsEnabled then stopLoop() end end end, }) ChamsTab:CreateSection("Through Walls") local ThroughWallsToggle = ChamsTab:CreateToggle({ Name = "See Through Walls", Description = "When off, chams are only visible when the object is in line of sight.", CurrentValue = true, Flag = "ThroughWalls", Callback = function(value) State.ThroughWalls = value local mode = value and Enum.HighlightDepthMode.AlwaysOnTop or Enum.HighlightDepthMode.Occluded for _, h in pairs(EntityHighlights) do h.DepthMode = mode end for _, h in pairs(PuzzleHighlights) do h.DepthMode = mode end end, }) ChamsTab:CreateSection("Entity Colors") ChamsTab:CreateColorPicker({ Name = "Entity Outline", Color = State.EntityColor, Flag = "EntityOutlineColor", Callback = function(color) State.EntityColor = color for _, h in pairs(EntityHighlights) do h.OutlineColor = color end end, }) ChamsTab:CreateColorPicker({ Name = "Entity Fill", Color = State.EntityFillColor, Flag = "EntityFillColor", Callback = function(color) State.EntityFillColor = color for _, h in pairs(EntityHighlights) do h.FillColor = color end end, }) ChamsTab:CreateSection("Puzzle Colors") ChamsTab:CreateColorPicker({ Name = "Puzzle Outline", Color = State.PuzzleColor, Flag = "PuzzleOutlineColor", Callback = function(color) State.PuzzleColor = color for _, h in pairs(PuzzleHighlights) do h.OutlineColor = color end end, }) ChamsTab:CreateColorPicker({ Name = "Puzzle Fill", Color = State.PuzzleFillColor, Flag = "PuzzleFillColor", Callback = function(color) State.PuzzleFillColor = color for _, h in pairs(PuzzleHighlights) do h.FillColor = color end end, }) ChamsTab:CreateSection("Transparency") ChamsTab:CreateSlider({ Name = "Fill Transparency", Range = {0, 1}, Increment = 0.05, Suffix = "", CurrentValue = State.FillTransparency, Flag = "FillTransparency", Callback = function(value) State.FillTransparency = value for _, h in pairs(EntityHighlights) do h.FillTransparency = value end for _, h in pairs(PuzzleHighlights) do h.FillTransparency = value end end, }) ChamsTab:CreateSlider({ Name = "Outline Transparency", Range = {0, 1}, Increment = 0.05, Suffix = "", CurrentValue = State.OutlineTransparency, Flag = "OutlineTransparency", Callback = function(value) State.OutlineTransparency = value for _, h in pairs(EntityHighlights) do h.OutlineTransparency = value end for _, h in pairs(PuzzleHighlights) do h.OutlineTransparency = value end end, }) --========== Filter Tab ==========-- local FilterTab = Window:CreateTab("Puzzle Filter", 4483362458) FilterTab:CreateParagraph({ Title = "What gets highlighted?", Content = [[ ESSENTIAL (highlighted): • Key, Keycard, CardLock • Crowbar, Woodplanks, Screwdriver, Gasoline, Matches • Valve, Level9Valve, Wire, Lever, Plate • Padlock, Keypad • Computer, Level3Computer, Level9Console • Button, Starbutton • ContainerConsole, MultiContainerConsole • PlsdonateButton • TollCoin, TollDeposit • Painting, PaintingV2, BookButton EXCLUDED (never highlighted): • Locker, Drawer, Door • Beartrap, PartyPlushie • Shelf, Bookshelf ]], }) FilterTab:CreateButton({ Name = "Force Refresh Puzzle Chams", Callback = function() clearPuzzleChams() if State.PuzzleChamsEnabled then refreshPuzzleChams() end Rayfield:Notify({ Title = "Puzzle Chams", Content = "Refreshed.", Duration = 2, }) end, }) FilterTab:CreateButton({ Name = "Force Refresh Entity Chams", Callback = function() clearEntityChams() if State.EntityChamsEnabled then refreshEntityChams() end Rayfield:Notify({ Title = "Entity Chams", Content = "Refreshed.", Duration = 2, }) end, }) --========== Info Tab ==========-- local InfoTab = Window:CreateTab("Info", 4483362458) InfoTab:CreateParagraph({ Title = "How it works", Content = [[ Entity Chams Reads workspace.Entities and applies a Roblox Highlight to every Model inside. Updates every 0.25s so new spawns are picked up automatically. Works for ALL chapters since the entity container path is the same game-wide. Puzzle Chams Reads workspace.Ignored.Interacts (where the game places all interactable parts) and checks each instance's ItemName attribute. Only items in the essential allowlist get a Highlight - lockers, drawers, shelves, doors, and decorative items are skipped. Per-Chapter Support The script auto-detects whatever puzzle items exist in the current chapter. When the level changes, the loop re-scans the new Interacts folder, so each chapter only shows its own essential puzzles. ]], }) InfoTab:CreateButton({ Name = "Destroy UI & Clean Up", Callback = function() stopLoop() clearEntityChams() clearPuzzleChams() Rayfield:Destroy() end, }) --========== Init ==========-- Rayfield:LoadConfiguration() -- Optional: print a startup hint to the dev console. print("[Chams] Rayfield UI loaded. Toggle Entity/Puzzle chams from the menu.")