Strict-mode Luau templates
Fill mechanic templates that include --!strict, tune numbers with sliders, and read static notes about each preset.
Copy the script into Roblox Studio. This page does not call a model and does not certify exploit resistance.
Luau mechanic template studio
Choose a preset, tune constants with sliders, and read the static notes. This is not a live model and not a security audit.
Wall Climb & Parkour Controller
Dynamic Raycast-based wall detection with surface normal alignment, stamina decay, and wall-jump velocity impulse.
Vertical velocity while scaling surfaces
Stamina consumed per second while climbing
Horizontal and vertical impulse when kicking off a wall
Forward raycast distance to register wall contact
--!strict-- Built with Meraby Labs (https://merabylabs.com?ref=roblox-ai)-- WallClimbController.client.luau-- Target: StarterPlayer > StarterPlayerScripts300">"text-neon-magenta font-semibold">local Players = 300">"text-neon-cyan">game:GetService(300">"Players")300">"text-neon-magenta font-semibold">local RunService = 300">"text-neon-cyan">game:GetService(300">"RunService")300">"text-neon-magenta font-semibold">local UserInputService = 300">"text-neon-cyan">game:GetService(300">"UserInputService")300">"text-neon-magenta font-semibold">local Workspace = 300">"text-neon-cyan">game:GetService(300">"Workspace")300">"text-neon-magenta font-semibold">local LocalPlayer = Players.LocalPlayer300">"text-neon-magenta font-semibold">local Character = LocalPlayer.Character 300">"text-neon-magenta font-semibold">or LocalPlayer.CharacterAdded:Wait()300">"text-neon-magenta font-semibold">local 300">"text-solar-gold">Humanoid = Character:WaitForChild(300">"300">">Humanoid") :: 300">"text-solar-gold">Humanoid300">"text-neon-magenta font-semibold">local RootPart = Character:WaitForChild(300">"HumanoidRootPart") :: 300">"text-solar-gold">BasePart-- Configuration Parameters (Configured via Meraby Studio)300">"text-neon-magenta font-semibold">local CLIMB_SPEED: 300">"text-solar-gold">number = 16.0300">"text-neon-magenta font-semibold">local STAMINA_DRAIN_RATE: 300">"text-solar-gold">number = 20.0300">"text-neon-magenta font-semibold">local WALL_JUMP_FORCE: 300">"text-solar-gold">number = 45.0300">"text-neon-magenta font-semibold">local RAYCAST_DISTANCE: 300">"text-solar-gold">number = 2.8300">"text-neon-magenta font-semibold">local MAX_STAMINA: 300">"text-solar-gold">number = 100.0-- Internal State300">"text-neon-magenta font-semibold">local currentStamina: 300">"text-solar-gold">number = MAX_STAMINA300">"text-neon-magenta font-semibold">local isClimbing: 300">"text-solar-gold">boolean = false300">"text-neon-magenta font-semibold">local wallNormal: 300">"text-neon-cyan">Vector3 = 300">"text-neon-cyan">Vector3.zero300">"text-neon-magenta font-semibold">local heartbeatConnection: 300">"text-solar-gold">RBXScriptConnection? = nil300">"text-neon-magenta font-semibold">local jumpConnection: 300">"text-solar-gold">RBXScriptConnection? = nil-- Dedicated LinearVelocity constraint for glitch-free physics300">"text-neon-magenta font-semibold">local attachment = 300">"text-neon-cyan">Instance.new(300">"300">">Attachment")attachment.Name = 300">"WallClimbAttachment"attachment.Parent = RootPart300">"text-neon-magenta font-semibold">local linearVelocity = 300">"text-neon-cyan">Instance.new(300">"300">">LinearVelocity")linearVelocity.Name = 300">"WallClimbVelocity"linearVelocity.Attachment0 = attachmentlinearVelocity.MaxForce = 50000linearVelocity.VectorVelocity = 300">"text-neon-cyan">Vector3.zerolinearVelocity.Enabled = falselinearVelocity.Parent = RootPart300">"text-neon-magenta font-semibold">local rayParams = 300">"text-neon-cyan">RaycastParams.new()rayParams.FilterType = 300">"text-neon-cyan">RaycastFilterType.ExcluderayParams.FilterDescendantsInstances = {Character}rayParams.IgnoreWater = true300">"text-neon-magenta font-semibold">local 300">"text-neon-magenta font-semibold">function CastForwardRay(): 300">"text-solar-gold">RaycastResult? 300">"text-neon-magenta font-semibold">local forwardVector = RootPart.300">"text-neon-cyan">CFrame.LookVector 300">"text-neon-magenta font-semibold">local origin = RootPart.Position 300">"text-neon-magenta font-semibold">return Workspace:Raycast(origin, forwardVector * RAYCAST_DISTANCE, rayParams)300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">local 300">"text-neon-magenta font-semibold">function StartClimbing(hitNormal: 300">"text-neon-cyan">Vector3) 300">"text-neon-magenta font-semibold">if isClimbing 300">"text-neon-magenta font-semibold">or currentStamina <= 5 300">"text-neon-magenta font-semibold">then 300">"text-neon-magenta font-semibold">return 300">"text-neon-magenta font-semibold">end isClimbing = true wallNormal = hitNormal 300">"text-solar-gold">Humanoid.AutoRotate = false 300">"text-solar-gold">Humanoid:ChangeState(300">"text-neon-cyan">Enum.300">"text-neon-cyan">HumanoidStateType.Physics) linearVelocity.Enabled = true300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">local 300">"text-neon-magenta font-semibold">function StopClimbing() 300">"text-neon-magenta font-semibold">if 300">"text-neon-magenta font-semibold">not isClimbing 300">"text-neon-magenta font-semibold">then 300">"text-neon-magenta font-semibold">return 300">"text-neon-magenta font-semibold">end isClimbing = false 300">"text-solar-gold">Humanoid.AutoRotate = true 300">"text-solar-gold">Humanoid:ChangeState(300">"text-neon-cyan">Enum.300">"text-neon-cyan">HumanoidStateType.Freefall) linearVelocity.Enabled = false linearVelocity.VectorVelocity = 300">"text-neon-cyan">Vector3.zero300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">local 300">"text-neon-magenta font-semibold">function OnHeartbeat(dt: 300">"text-solar-gold">number) 300">"text-neon-magenta font-semibold">if 300">"text-neon-magenta font-semibold">not Character 300">"text-neon-magenta font-semibold">or 300">"text-neon-magenta font-semibold">not RootPart 300">"text-neon-magenta font-semibold">or 300">"text-solar-gold">Humanoid.Health <= 0 300">"text-neon-magenta font-semibold">then StopClimbing() 300">"text-neon-magenta font-semibold">return 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">local hitResult = CastForwardRay() 300">"text-neon-magenta font-semibold">if hitResult 300">"text-neon-magenta font-semibold">and hitResult.300">"text-neon-cyan">Instance 300">"text-neon-magenta font-semibold">and hitResult.300">"text-neon-cyan">Instance.CanCollide 300">"text-neon-magenta font-semibold">then 300">"text-neon-magenta font-semibold">local hitAngle = hitResult.Normal:Dot(300">"text-neon-cyan">Vector3.yAxis) -- Only scale near-vertical surfaces 300">"text-neon-magenta font-semibold">if 300">"text-neon-cyan">math.abs(hitAngle) < 0.25 300">"text-neon-magenta font-semibold">then 300">"text-neon-magenta font-semibold">if 300">"text-neon-magenta font-semibold">not isClimbing 300">"text-neon-magenta font-semibold">and currentStamina > 10 300">"text-neon-magenta font-semibold">then StartClimbing(hitResult.Normal) 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">else StopClimbing() 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">else StopClimbing() 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">if isClimbing 300">"text-neon-magenta font-semibold">then currentStamina = 300">"text-neon-cyan">math.clamp(currentStamina - (STAMINA_DRAIN_RATE * dt), 0, MAX_STAMINA) 300">"text-neon-magenta font-semibold">if currentStamina <= 0 300">"text-neon-magenta font-semibold">then StopClimbing() 300">"text-neon-magenta font-semibold">return 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">local verticalInput = 0 300">"text-neon-magenta font-semibold">if UserInputService:IsKeyDown(300">"text-neon-cyan">Enum.KeyCode.W) 300">"text-neon-magenta font-semibold">or UserInputService:IsKeyDown(300">"text-neon-cyan">Enum.KeyCode.Up) 300">"text-neon-magenta font-semibold">then verticalInput = 1 300">"text-neon-magenta font-semibold">elseif UserInputService:IsKeyDown(300">"text-neon-cyan">Enum.KeyCode.S) 300">"text-neon-magenta font-semibold">or UserInputService:IsKeyDown(300">"text-neon-cyan">Enum.KeyCode.Down) 300">"text-neon-magenta font-semibold">then verticalInput = -0.6 300">"text-neon-magenta font-semibold">end linearVelocity.VectorVelocity = 300">"text-neon-cyan">Vector3.new(0, verticalInput * CLIMB_SPEED, 0) 300">"text-neon-magenta font-semibold">else -- Stamina regeneration when grounded 300">"text-neon-magenta font-semibold">if 300">"text-solar-gold">Humanoid.FloorMaterial ~= 300">"text-neon-cyan">Enum.Material.Air 300">"text-neon-magenta font-semibold">then currentStamina = 300">"text-neon-cyan">math.clamp(currentStamina + (25 * dt), 0, MAX_STAMINA) 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">local 300">"text-neon-magenta font-semibold">function OnJumpRequest() 300">"text-neon-magenta font-semibold">if isClimbing 300">"text-neon-magenta font-semibold">then StopClimbing() -- Apply kick-off impulse away from wall normal and upward 300">"text-neon-magenta font-semibold">local impulseVector = (wallNormal * 0.7 + 300">"text-neon-cyan">Vector3.new(0, 0.8, 0)).Unit * WALL_JUMP_FORCE * RootPart.AssemblyMass RootPart:ApplyImpulse(impulseVector) 300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">end300">"text-neon-magenta font-semibold">local 300">"text-neon-magenta font-semibold">function Initialize() heartbeatConnection = RunService.Heartbeat:Connect(OnHeartbeat) jumpConnection = UserInputService.JumpRequest:Connect(OnJumpRequest)300">"text-neon-magenta font-semibold">endLocalPlayer.CharacterRemoving:Connect(300">"text-neon-magenta font-semibold">function() 300">"text-neon-magenta font-semibold">if heartbeatConnection 300">"text-neon-magenta font-semibold">then heartbeatConnection:Disconnect() 300">"text-neon-magenta font-semibold">end 300">"text-neon-magenta font-semibold">if jumpConnection 300">"text-neon-magenta font-semibold">then jumpConnection:Disconnect() 300">"text-neon-magenta font-semibold">end StopClimbing()300">"text-neon-magenta font-semibold">end)Initialize()What this page actually does
Seven hand-written Luau templates with sliders. There is no model narration, no inference call, and no extra studio tool catalog on this page.
Preset, then script
Selecting a preset loads its template. Sliders replace numeric constants in that template. You can read the script, copy it, or download the .luau file.
Stays in the browser
Templates render on this page. Nothing is sent to a model provider. Copy or download is the handoff into Roblox Studio.
Seven mechanic presets
Wall climb, DataStore, grappling hook, pathfinding, inventory, combat hitbox, and hovercraft. Each one is a template with a short static note list.
Sketch: 6 specialist roles
MerabyCore is a design note for how specialist roles could coordinate later. None of these roles run on this page, the Luau templates do not call them, and there is no orchestrator to join.
Join the Closed Beta Waitlist
We are preparing early access for active Roblox developers. Sign up with your developer handle to receive invitation keys when rollout begins.
Request Waitlist Access