--[[ DYNAMIC HEAD TRACKING CONTROL PANEL Version 3.0 | Roblox Luau | R6 + R15 Installation: StarterPlayer > StarterPlayerScripts Features: - Automatically generated professional GUI - Camera-relative head tracking - R6 Motor6D support - R15 Motor6D and AnimationConstraint support - Smooth and fast head rotation - Maximum yaw and pitch settings - Response speed control - Presets: Soft, Balanced, Fast, Reset - Toggle tracking ON/OFF - Animated open/minimize, button feedback and sliders - Draggable and responsive GUI - Character respawn handling - Safe transform baseline to prevent accumulation Note: Client-side joint changes are not guaranteed to replicate to other players. Test in Roblox Studio before publishing. ]] ---------------------------------------------------------------- -- SERVICES ---------------------------------------------------------------- local Players = game:GetService("Players") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local UserInputService = game:GetService("UserInputService") local Workspace = game:GetService("Workspace") local player = Players.LocalPlayer if not player then return end ---------------------------------------------------------------- -- CONFIGURATION ---------------------------------------------------------------- local SETTINGS = { Enabled = true, MaxYawDegrees = 65, MaxPitchDegrees = 30, -- Higher values respond faster. SmoothSpeed = 40, -- Never allow an excessive rotation. HardMaxYawDegrees = 80, HardMaxPitchDegrees = 45, } ---------------------------------------------------------------- -- COLORS ---------------------------------------------------------------- local COLORS = { Background = Color3.fromRGB(17, 24, 39), HeaderTop = Color3.fromRGB(35, 48, 76), HeaderBottom = Color3.fromRGB(25, 34, 53), Card = Color3.fromRGB(28, 38, 57), CardStroke = Color3.fromRGB(53, 69, 96), Track = Color3.fromRGB(48, 61, 83), Accent = Color3.fromRGB(104, 125, 255), AccentLight = Color3.fromRGB(143, 157, 255), Green = Color3.fromRGB(51, 190, 130), GreenDark = Color3.fromRGB(30, 87, 70), Red = Color3.fromRGB(223, 99, 109), Yellow = Color3.fromRGB(245, 190, 85), Text = Color3.fromRGB(240, 244, 255), Secondary = Color3.fromRGB(160, 174, 200), Muted = Color3.fromRGB(106, 122, 148), } ---------------------------------------------------------------- -- GENERAL HELPERS ---------------------------------------------------------------- local globalConnections = {} local activeTweens = setmetatable({}, { __mode = "k" }) local function keepConnection(connection) table.insert(globalConnections, connection) return connection end local function create(className, parent, properties) local object = Instance.new(className) for property, value in pairs(properties or {}) do object[property] = value end object.Parent = parent return object end local function corner(parent, radius) return create("UICorner", parent, { CornerRadius = UDim.new(0, radius), }) end local function stroke(parent, color, thickness, transparency) return create("UIStroke", parent, { Color = color, Thickness = thickness or 1, Transparency = transparency or 0, }) end local function tween(object, duration, goals, style, direction) if not object or not object.Parent then return nil end local previous = activeTweens[object] if previous then previous:Cancel() end local info = TweenInfo.new( duration, style or Enum.EasingStyle.Quint, direction or Enum.EasingDirection.Out ) local animation = TweenService:Create( object, info, goals ) activeTweens[object] = animation animation.Completed:Connect(function() if activeTweens[object] == animation then activeTweens[object] = nil end end) animation:Play() return animation end local function makeLabel( parent, name, text, position, size, textSize, textColor, font, alignment ) return create("TextLabel", parent, { Name = name, Position = position, Size = size, BackgroundTransparency = 1, BorderSizePixel = 0, Text = text, TextSize = textSize or 12, TextColor3 = textColor or COLORS.Text, Font = font or Enum.Font.GothamMedium, TextXAlignment = alignment or Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, TextWrapped = false, ZIndex = 5, }) end local function makeButton( parent, name, text, position, size, background, hoverBackground, textSize ) local button = create("TextButton", parent, { Name = name, Position = position, Size = size, BackgroundColor3 = background, BorderSizePixel = 0, AutoButtonColor = false, Text = text, TextColor3 = COLORS.Text, TextSize = textSize or 12, Font = Enum.Font.GothamBold, ZIndex = 6, Active = true, }) corner(button, 10) local buttonScale = create("UIScale", button, { Scale = 1, }) if hoverBackground then button.MouseEnter:Connect(function() tween(button, 0.15, { BackgroundColor3 = hoverBackground, }) end) button.MouseLeave:Connect(function() tween(button, 0.15, { BackgroundColor3 = background, }) end) end -- Small animated press feedback. button.Activated:Connect(function() local pressTween = tween( buttonScale, 0.07, { Scale = 0.96 }, Enum.EasingStyle.Quad ) if pressTween then pressTween.Completed:Connect(function(playbackState) if playbackState == Enum.PlaybackState.Completed and buttonScale.Parent then tween( buttonScale, 0.16, { Scale = 1 }, Enum.EasingStyle.Back ) end end) end end) return button end ---------------------------------------------------------------- -- CREATE GUI ---------------------------------------------------------------- local playerGui = player:WaitForChild("PlayerGui") -- Prevent duplicated interfaces if the script is restarted. local oldGui = playerGui:FindFirstChild("DynamicHeadTrackingUI") if oldGui then oldGui:Destroy() end local screenGui = create("ScreenGui", playerGui, { Name = "DynamicHeadTrackingUI", ResetOnSpawn = false, IgnoreGuiInset = true, DisplayOrder = 100, ZIndexBehavior = Enum.ZIndexBehavior.Sibling, }) ---------------------------------------------------------------- -- MAIN PANEL ---------------------------------------------------------------- local PANEL_WIDTH = 370 local PANEL_HEIGHT = 468 local panel = create("CanvasGroup", screenGui, { Name = "MainPanel", AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 18, 0.5, 0), Size = UDim2.fromOffset(PANEL_WIDTH, PANEL_HEIGHT), BackgroundColor3 = COLORS.Background, BackgroundTransparency = 0, GroupTransparency = 1, ClipsDescendants = false, BorderSizePixel = 0, ZIndex = 2, }) corner(panel, 18) stroke(panel, COLORS.CardStroke, 1.2, 0.12) local panelScale = create("UIScale", panel, { Scale = 1, }) ---------------------------------------------------------------- -- HEADER ---------------------------------------------------------------- local header = create("Frame", panel, { Name = "Header", Size = UDim2.new(1, 0, 0, 66), BackgroundColor3 = COLORS.HeaderTop, BorderSizePixel = 0, Active = true, ZIndex = 3, }) corner(header, 18) create("UIGradient", header, { Color = ColorSequence.new( COLORS.HeaderTop, COLORS.HeaderBottom ), Rotation = 0, }) makeLabel( header, "Title", "HEAD TRACKING", UDim2.fromOffset(18, 9), UDim2.fromOffset(196, 25), 17, COLORS.Text, Enum.Font.GothamBold ) makeLabel( header, "Subtitle", "CAMERA FOLLOW CONTROL", UDim2.fromOffset(19, 35), UDim2.fromOffset(195, 17), 9, COLORS.Secondary, Enum.Font.GothamBold ) local statusPill = create("Frame", header, { Name = "StatusPill", Position = UDim2.fromOffset(221, 22), Size = UDim2.fromOffset(86, 24), BackgroundColor3 = COLORS.GreenDark, BorderSizePixel = 0, ZIndex = 5, }) corner(statusPill, 12) local statusDot = create("Frame", statusPill, { Position = UDim2.fromOffset(8, 9), Size = UDim2.fromOffset(6, 6), BackgroundColor3 = COLORS.Green, BorderSizePixel = 0, ZIndex = 6, }) corner(statusDot, 6) local statusText = makeLabel( statusPill, "StatusText", "ACTIVE", UDim2.fromOffset(20, 0), UDim2.new(1, -23, 1, 0), 9, COLORS.Text, Enum.Font.GothamBold ) local minimizeButton = makeButton( header, "MinimizeButton", "−", UDim2.fromOffset(322, 19), UDim2.fromOffset(30, 30), COLORS.Card, COLORS.CardStroke, 20 ) ---------------------------------------------------------------- -- LIVE TRACKING CARD ---------------------------------------------------------------- local trackingCard = create("Frame", panel, { Name = "TrackingCard", Position = UDim2.fromOffset(14, 78), Size = UDim2.fromOffset(342, 66), BackgroundColor3 = COLORS.Card, BorderSizePixel = 0, ZIndex = 3, }) corner(trackingCard, 13) stroke(trackingCard, COLORS.CardStroke, 1, 0.4) local iconCircle = create("Frame", trackingCard, { Position = UDim2.fromOffset(13, 14), Size = UDim2.fromOffset(38, 38), BackgroundColor3 = COLORS.HeaderTop, BorderSizePixel = 0, ZIndex = 4, }) corner(iconCircle, 12) stroke(iconCircle, COLORS.CardStroke, 1, 0.3) makeLabel( iconCircle, "TrackingIcon", "◎", UDim2.fromScale(0, 0), UDim2.fromScale(1, 1), 24, COLORS.AccentLight, Enum.Font.GothamBold, Enum.TextXAlignment.Center ) makeLabel( trackingCard, "TrackingTitle", "Camera head tracking", UDim2.fromOffset(62, 12), UDim2.fromOffset(184, 21), 12, COLORS.Text, Enum.Font.GothamBold ) makeLabel( trackingCard, "TrackingDescription", "Body orientation stays independent", UDim2.fromOffset(62, 34), UDim2.fromOffset(186, 16), 9, COLORS.Secondary, Enum.Font.GothamMedium ) local toggleButton = makeButton( trackingCard, "TrackingToggle", "ON", UDim2.fromOffset(265, 17), UDim2.fromOffset(63, 32), COLORS.GreenDark, nil, 11 ) ---------------------------------------------------------------- -- SLIDER PANEL ---------------------------------------------------------------- local sliderCard = create("Frame", panel, { Name = "SettingsCard", Position = UDim2.fromOffset(14, 156), Size = UDim2.fromOffset(342, 194), BackgroundColor3 = COLORS.Card, BorderSizePixel = 0, ClipsDescendants = false, ZIndex = 3, }) corner(sliderCard, 13) stroke(sliderCard, COLORS.CardStroke, 1, 0.4) makeLabel( sliderCard, "SectionTitle", "ROTATION & RESPONSE", UDim2.fromOffset(17, 8), UDim2.fromOffset(300, 18), 10, COLORS.Secondary, Enum.Font.GothamBold ) ---------------------------------------------------------------- -- SETTINGS STATE ---------------------------------------------------------------- local settings = { MaxYawDegrees = SETTINGS.MaxYawDegrees, MaxPitchDegrees = SETTINGS.MaxPitchDegrees, SmoothSpeed = SETTINGS.SmoothSpeed, } local sliderList = {} local sliderControls = {} local function formatSliderValue(key, value) if key == "SmoothSpeed" then return tostring(value) .. " /s" end return tostring(value) .. "°" end local function updateSliderVisual(control, animated) local alpha = (settings[control.key] - control.min) / (control.max - control.min) alpha = math.clamp(alpha, 0, 1) control.valueLabel.Text = formatSliderValue( control.key, settings[control.key] ) local fillGoals = { Size = UDim2.new(alpha, 0, 1, 0), } local knobGoals = { Position = UDim2.new(alpha, 0, 0.5, 0), } if animated then tween(control.fill, 0.24, fillGoals) tween(control.knob, 0.24, knobGoals) else control.fill.Size = fillGoals.Size control.knob.Position = knobGoals.Position end end local function createSlider(key, title, minimum, maximum, yPosition) local titleLabel = makeLabel( sliderCard, key .. "Label", title, UDim2.fromOffset(18, yPosition), UDim2.fromOffset(220, 19), 10, COLORS.Text, Enum.Font.GothamSemibold ) local valueLabel = makeLabel( sliderCard, key .. "Value", "", UDim2.new(1, -98, 0, yPosition), UDim2.fromOffset(80, 19), 10, COLORS.AccentLight, Enum.Font.GothamBold, Enum.TextXAlignment.Right ) local track = create("Frame", sliderCard, { Name = key .. "Track", Position = UDim2.new(0, 18, 0, yPosition + 25), Size = UDim2.new(1, -36, 0, 6), BackgroundColor3 = COLORS.Track, BorderSizePixel = 0, Active = true, ZIndex = 5, }) corner(track, 6) local fill = create("Frame", track, { Name = "Fill", Size = UDim2.new(0, 0, 1, 0), BackgroundColor3 = COLORS.Accent, BorderSizePixel = 0, ZIndex = 6, }) corner(fill, 6) local knob = create("Frame", track, { Name = "Knob", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0, 0, 0.5, 0), Size = UDim2.fromOffset(14, 14), BackgroundColor3 = COLORS.Text, BorderSizePixel = 0, Active = true, ZIndex = 7, }) corner(knob, 7) stroke(knob, COLORS.Accent, 2, 0) local control = { key = key, titleLabel = titleLabel, valueLabel = valueLabel, track = track, fill = fill, knob = knob, min = minimum, max = maximum, } sliderControls[key] = control table.insert(sliderList, control) updateSliderVisual(control, false) return control end createSlider( "MaxYawDegrees", "MAX YAW • LEFT / RIGHT", 10, SETTINGS.HardMaxYawDegrees, 32 ) createSlider( "MaxPitchDegrees", "MAX PITCH • UP / DOWN", 5, SETTINGS.HardMaxPitchDegrees, 82 ) createSlider( "SmoothSpeed", "RESPONSE SPEED", 8, 55, 132 ) ---------------------------------------------------------------- -- PRESETS ---------------------------------------------------------------- makeLabel( panel, "PresetHeading", "QUICK PRESETS", UDim2.fromOffset(17, 353), UDim2.fromOffset(150, 17), 9, COLORS.Secondary, Enum.Font.GothamBold ) local presetButtons = {} local function createPreset(name, text, x, background) local button = makeButton( panel, name, text, UDim2.fromOffset(x, 373), UDim2.fromOffset(80, 34), background, COLORS.HeaderTop, 9 ) presetButtons[name] = button return button end createPreset("Soft", "SOFT", 14, COLORS.Track) createPreset("Balanced", "BALANCED", 100, COLORS.HeaderTop) createPreset("Fast", "FAST", 186, COLORS.GreenDark) createPreset("Reset", "RESET", 272, COLORS.Track) ---------------------------------------------------------------- -- FOOTER ---------------------------------------------------------------- local rigInfoLabel = makeLabel( panel, "RigInformation", "WAITING FOR CHARACTER", UDim2.fromOffset(17, 421), UDim2.fromOffset(230, 18), 9, COLORS.Secondary, Enum.Font.GothamSemibold ) makeLabel( panel, "ClientOnlyLabel", "CLIENT ONLY", UDim2.new(1, -104, 0, 421), UDim2.fromOffset(88, 18), 8, COLORS.Muted, Enum.Font.GothamBold, Enum.TextXAlignment.Right ) ---------------------------------------------------------------- -- MINIMIZED FLOATING BUTTON ---------------------------------------------------------------- local miniButton = create("TextButton", screenGui, { Name = "FloatingOpenButton", AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 18, 0.5, 0), Size = UDim2.fromOffset(54, 54), BackgroundColor3 = COLORS.HeaderTop, BackgroundTransparency = 1, Text = "HR", TextColor3 = COLORS.Text, TextTransparency = 1, TextSize = 15, Font = Enum.Font.GothamBold, AutoButtonColor = false, Visible = false, ZIndex = 20, }) corner(miniButton, 17) stroke(miniButton, COLORS.Accent, 1.5, 0.15) local miniScale = create("UIScale", miniButton, { Scale = 0.75, }) ---------------------------------------------------------------- -- RESPONSIVE GUI SCALE ---------------------------------------------------------------- local baseScale = 1 local expandedPosition = panel.Position local isMinimized = false local isPanelDragging = false local panelDragOrigin local panelDragStartPosition local viewportConnection local function clampExpandedPosition() local camera = Workspace.CurrentCamera local viewport = camera and camera.ViewportSize or Vector2.new(1280, 720) local scaledWidth = PANEL_WIDTH * baseScale local scaledHeight = PANEL_HEIGHT * baseScale local maxX = math.max( 8, viewport.X - scaledWidth - 8 ) local yBound = math.max( 0, (viewport.Y - scaledHeight) / 2 - 8 ) local x = math.clamp( expandedPosition.X.Offset, 8, maxX ) local y = math.clamp( expandedPosition.Y.Offset, -yBound, yBound ) expandedPosition = UDim2.new(0, x, 0.5, y) end local function updateResponsiveScale() local camera = Workspace.CurrentCamera local viewport = camera and camera.ViewportSize or Vector2.new(1280, 720) baseScale = math.clamp( math.min( 1, math.max(1, viewport.X - 24) / PANEL_WIDTH, math.max(1, viewport.Y - 24) / PANEL_HEIGHT ), 0.62, 1 ) panelScale.Scale = baseScale miniScale.Scale = math.clamp(baseScale, 0.72, 1) clampExpandedPosition() if not isMinimized and not isPanelDragging then panel.Position = expandedPosition end miniButton.Position = UDim2.new(0, 18, 0.5, 0) end local function watchCurrentCamera() if viewportConnection then viewportConnection:Disconnect() viewportConnection = nil end local camera = Workspace.CurrentCamera if camera then viewportConnection = camera:GetPropertyChangedSignal("ViewportSize"):Connect( updateResponsiveScale ) end updateResponsiveScale() end keepConnection( Workspace:GetPropertyChangedSignal("CurrentCamera"):Connect( watchCurrentCamera ) ) watchCurrentCamera() ---------------------------------------------------------------- -- SMOOTH PANEL OPEN / MINIMIZE ---------------------------------------------------------------- local function minimizePanel() if isMinimized then return end isMinimized = true expandedPosition = panel.Position local currentX = expandedPosition.X.Offset local currentY = expandedPosition.Y.Offset