Run it
Copy the script and paste it into your executor.
Players = :()
UserInputService = :()
TweenService = :()
RunService = :()
LocalPlayer = Players.LocalPlayer
PlayerGui = LocalPlayer:()
DEFAULT_BINDINGS = {
{ dir = , key = , id = },
{ dir = , key = , id = },
{ dir = , key = , id = },
{ dir = , key = , id = },
}
CurrentBindings = {}
_, v (DEFAULT_BINDINGS)
.(CurrentBindings, { dir = v.dir, key = v.key, id = v.id, speedMult = , holdLoop = , alts = {} })
PRESETS = {
{ name = , ids = { LEFT=, DOWN=, UP=, RIGHT= } },
{ name = ,ids = { LEFT=, DOWN=, UP=, RIGHT= } },
{ name = ,ids = { LEFT=, DOWN=, UP=, RIGHT= } },
}
animTracks = {}
idleTrack =
connections = {}
animator =
character =
rebindingRow =
guiVisible =
idleLooping =
rpModeEnabled =
currentTarget =
rpMoveStep =
rpMinDistance =
rpPushbackStep =
targetAnimConn =
legsLocked =
savedWalkSpeed =
savedJumpPower =
faceDecal =
defaultFaceId =
faceIds = { LEFT = , DOWN = , UP = , RIGHT = }
sequence = {}
seqPlaying =
seqTrack =
seqRowFrames = {}
arrowHudFrames = {}
idleBPM =
BASE_BPM =
StatusState = {
currentAnimName = ,
currentAnimId = ,
speedMult = ,
bpm = idleBPM,
playing = ,
}
favorites = {
{ name = , id = },
{ name = , id = },
{ name = , id = },
{ name = , id = },
{ name = , id = },
{ name = , id = },
{ name = , id = },
}
recents = {}
RECENTS_CAP =
playlist = {}
playlistIndex =
playlistPlaying =
previewClone =
previewAnimator =
previewCam =
previewAngle =
THEMES = {
Pink = { accent = .(, , ), accent2 = .(, , ) },
Cyan = { accent = .(, , ), accent2 = .(, , ) },
Purple = { accent = .(, , ), accent2 = .(, , ) },
RGB = { accent = .(, , ), accent2 = .(, , ) },
}
currentThemeName =
themedStrokes = {}
themedBgs = {}
themedTexts = {}
rgbCycleOn =
vinylImage =
VINYL_DECAL_ID =
vinylRotation =
vinylBaseRPM =
crtEnabled =
crtOverlay =
crtFlickerConn =
micDeviceInput =
micAnalyzer =
micWire =
micAvailable =
specBars = {}
SPEC_BAR_COUNT =
bpmDetectTaps = {}
BPM_TAP_WINDOW =
detectedBPM =
beatsPerIdleLoop =
ReplicatedStorage = :()
SoundService = :()
musicRemote =
MUSIC_SOUND_NAME =
musicStatusLbl =
musicRequestTick =
PRIORITY = .AnimationPriority.Action
FRAME_TARGET =
BLEND_IN =
BLEND_OUT =
ARROW_COLORS = {
LEFT = { idle = .(, , ), hit = .(, , ) },
DOWN = { idle = .(, , ), hit = .(, , ) },
UP = { idle = .(, , ), hit = .(, , ) },
RIGHT = { idle = .(, , ), hit = .(, , ) },
}
ARROW_SYMBOLS = { LEFT = , DOWN = , UP = , RIGHT = }
ARROW_SIZE =
ARROW_HIT_SIZE =
ARROW_GAP =
ARROW_ORDER = { , , , }
(m) (..(m))
(char)
hum = char:()
hum
a = hum:()
a a = .(); a.Parent = hum
a
(key)
t = animTracks[key]
t (() t:() ) (() t:() ) animTracks[key] =
()
idleTrack (() idleTrack:() ) (() idleTrack:() ) idleTrack =
idleLooping =
()
seqTrack (() seqTrack:() ) (() seqTrack:() ) seqTrack =
()
idleLooping = ; seqPlaying =
(); ()
k (animTracks) (k)
_, c (connections) (() c:() )
connections = {}; animator = ; character =
faceDecal = ; defaultFaceId =
notifyContainer =
(text, kind)
notifyContainer (..text);
kind = kind
colors = {
info = .(, , ),
success = .(, , ),
= .(, , ),
= .(, , ),
}
toast = .()
toast.Size = .(, , , )
toast.BackgroundColor3 = .(, , )
toast.BackgroundTransparency =
toast.BorderSizePixel =
toast.ClipsDescendants =
toast.Parent = notifyContainer
corner = .(); corner.CornerRadius = .(,); corner.Parent = toast
stroke = .(); stroke.Color = colors[kind] colors.info; stroke.Thickness = ; stroke.Parent = toast
bar = .()
bar.Size = .(, , , )
bar.BackgroundColor3 = colors[kind] colors.info
bar.BorderSizePixel =
bar.Parent = toast
lbl = .()
lbl.Size = .(, -, , ); lbl.Position = .(, , , )
lbl.BackgroundTransparency = ; lbl.Text = text
lbl.TextColor3 = .(,,); lbl.Font = .Font.GothamBold
lbl.TextSize = ; lbl.TextXAlignment = .TextXAlignment.Left
lbl.TextWrapped = ; lbl.Parent = toast
toast.Position = .(, , , )
TweenService:(toast, TweenInfo.(, .EasingStyle.Quint, .EasingDirection.Out), { Position = .(,,,) }):()
.(, ()
toast toast.Parent
t = TweenService:(toast, TweenInfo.(, .EasingStyle.Quint, .EasingDirection.In), { BackgroundTransparency = })
TweenService:(lbl, TweenInfo.(), { TextTransparency = }):()
TweenService:(stroke, TweenInfo.(), { Transparency = }):()
t:()
t.Completed:(() toast toast:() )
)
(obj) .(themedStrokes, obj); obj.Color = THEMES[currentThemeName].accent
(obj) .(themedBgs, obj); obj.BackgroundColor3 = THEMES[currentThemeName].accent
(obj) .(themedTexts, obj); obj.TextColor3 = THEMES[currentThemeName].accent
(accent)
_, o (themedStrokes) (() o.Color = accent )
_, o (themedBgs) (() o.BackgroundColor3 = accent )
_, o (themedTexts) (() o.TextColor3 = accent )
(name)
THEMES[name]
currentThemeName = name
rgbCycleOn = (name == )
rgbCycleOn
(THEMES[name].accent)
(..name, )
.(()
hue =
.()
rgbCycleOn
hue = (hue + ) %
(.(hue, , ))
)
(char)
head = char:()
head
d = head:()
d d.ClassName ~=
faceDecal = d
defaultFaceId = d.Texture
(..defaultFaceId)
(dir)
faceDecal
id = faceIds[dir]
id id ~=
faceDecal.Texture = ..id
()
faceDecal defaultFaceId
faceDecal.Texture = defaultFaceId
(locked)
character
hum = character:()
hum
locked
savedWalkSpeed = hum.WalkSpeed
savedJumpPower = hum.JumpPower
hum.WalkSpeed =
hum.JumpPower =
hum.WalkSpeed = savedWalkSpeed
hum.JumpPower = savedJumpPower
(id, label)
id id ==
i = #recents, , -
recents[i].id == id .(recents, i)
.(recents, , { id = id, label = label id })
#recents > RECENTS_CAP .(recents)
refreshRecentsUI ()
(assetId, label)
StatusState.currentAnimName = label assetId
StatusState.currentAnimId = assetId
refreshStatusUI ()
previewAnimator assetId assetId ==
ok, result = (()
anim = .()
anim.AnimationId = ..assetId
t = previewAnimator:(anim)
t.Priority = .AnimationPriority.Action
t
)
ok result
_, t (previewAnimator:()) t:()
result:()
rpModeEnabled =
currentTarget =
rpMoveStep =
rpMinDistance =
rpRetreatStep =
rpMaxDistance =
targetAnimConn =
targetCharAddedConn =
()
targetAnimConn
targetAnimConn:()
targetAnimConn =
targetCharAddedConn
targetCharAddedConn:()
targetCharAddedConn =
()
rpModeEnabled currentTarget
character currentTarget.Character
myRoot = character:()
targetRoot = currentTarget.Character:()
myRoot targetRoot
awayVector = (myRoot.Position - targetRoot.Position)
distance = awayVector.Magnitude
distance <=
distance < rpMaxDistance
actualStep = .(rpRetreatStep, rpMaxDistance - distance)
myRoot.CFrame = myRoot.CFrame + (awayVector.Unit * actualStep)
()
()
currentTarget
(targetChar)
targetChar
hum = targetChar:(, )
hum
anr = hum:(, ) hum:()
anr
targetAnimConn = anr.AnimationPlayed:((track)
rpModeEnabled
()
)
currentTarget.Character
(currentTarget.Character)
targetCharAddedConn = currentTarget.CharacterAdded:((newChar)
()
(newChar)
)
(partialName)
partialName partialName ==
currentTarget =
()
notify (, )
lowerName = partialName:()
_, player (Players:())
player ~= LocalPlayer player.Name:():(, #lowerName) == lowerName
currentTarget = player
()
notify ( .. player.Name, )
player
notify (, )
()
rpModeEnabled currentTarget
character currentTarget.Character
myRoot = character:()
targetRoot = currentTarget.Character:()
myRoot targetRoot
direction = (targetRoot.Position - myRoot.Position)
distance = direction.Magnitude
distance > rpMinDistance
actualStep = .(rpMoveStep, distance - rpMinDistance)
myRoot.CFrame = myRoot.CFrame + (direction.Unit * actualStep)
(key, assetId, speedMult, holdLoop)
animator
speedMult = speedMult
speedMult <= speedMult =
wantLooped = holdLoop
track = animTracks[key]
track track.Animation
track.Animation.AnimationId ~= ..assetId
track.Looped ~= wantLooped
(key)
ok, result = (()
anim = .()
anim.AnimationId = ..assetId
t = animator:(anim)
t.Priority = PRIORITY; t.Looped = wantLooped
t
)
ok (..assetId);
track = result; animTracks[key] = track
wantLooped
track:(BLEND_IN)
track:(speedMult)
baseReach = FRAME_TARGET /
reach = baseReach / speedMult
track:(BLEND_IN)
track:(track.Length > (track.Length / reach) )
.(reach, ()
track track.IsPlaying
track:()
track.TimePosition = .(, track.Length - )
)
StatusState.currentAnimName = key
StatusState.currentAnimId = assetId
StatusState.speedMult = speedMult
StatusState.playing =
refreshStatusUI ()
(assetId, key)
(assetId, key)
(key)
t = animTracks[key]
t t.IsPlaying t:(BLEND_OUT)
StatusState.playing =
refreshStatusUI ()
(row)
row.alts #row.alts >
roll = .() *
acc =
_, alt (row.alts)
acc += alt.chance
roll <= acc alt.id ~=
alt.id
row.id
(dir)
f = arrowHudFrames[dir]
f
TweenService:(f.bg, TweenInfo.(, .EasingStyle.Linear), {
BackgroundColor3 = ARROW_COLORS[dir].hit,
Size = .(, ARROW_HIT_SIZE, , ARROW_HIT_SIZE),
}):()
f.stroke
TweenService:(f.stroke, TweenInfo.(, .EasingStyle.Linear), { Thickness = }):()
f.glow
f.glow.Visible =
TweenService:(f.glow, TweenInfo.(), { BackgroundTransparency = }):()
(dir)
f = arrowHudFrames[dir]
f
TweenService:(f.bg, TweenInfo.(, .EasingStyle.Linear), {
BackgroundColor3 = ARROW_COLORS[dir].idle,
Size = .(, ARROW_SIZE, , ARROW_SIZE),
}):()
f.stroke
TweenService:(f.stroke, TweenInfo.(, .EasingStyle.Linear), { Thickness = }):()
f.glow
tw = TweenService:(f.glow, TweenInfo.(), { BackgroundTransparency = })
tw:()
tw.Completed:(() f.glow f.glow.Visible = )
(char)
char
oldArch = char.Archivable
char.Archivable =
ok, clone = (() char:() )
char.Archivable = oldArch
ok clone
_, v (clone:())
v:() v:()
v:()
v:()
v.CanCollide =
v.Anchored =
v.Massless =
v.Material = .Material.ForceField
TweenService:(v, TweenInfo.(, .EasingStyle.Quad, .EasingDirection.Out), {Transparency = }):()
v:() v:() v:()
TweenService:(v, TweenInfo.(, .EasingStyle.Quad, .EasingDirection.Out), {Transparency = }):()
root = clone:() clone.PrimaryPart
root
root.Anchored =
clone.Parent =
.(, ()
clone clone:()
)
()
BASE_BPM BASE_BPM <=
idleBPM / BASE_BPM
(assetId, shouldLoop)
()
animator
ok, result = (()
anim = .()
anim.AnimationId = ..assetId
t = animator:(anim)
t.Priority = .AnimationPriority.Idle; t.Looped = shouldLoop
t
)
ok
result
(assetId, cb)
t = (assetId, )
t
idleTrack = t; t:()
t:(())
(assetId, )
t.Stopped:(() cb () )
(assetId)
t = (assetId, )
t
idleTrack = t; idleLooping = ; t:()
t:(())
(assetId, )
StatusState.playing =
refreshStatusUI ()
()
idleLooping =
idleTrack idleTrack.IsPlaying idleTrack:()
StatusState.playing =
refreshStatusUI ()
(bpm)
bpm bpm > idleBPM = bpm
StatusState.bpm = idleBPM
idleTrack idleTrack.IsPlaying
idleTrack:(())
refreshStatusUI ()
(bpm)
bpm bpm > BASE_BPM = bpm
idleTrack idleTrack.IsPlaying
idleTrack:(())
()
now = .()
.(bpmDetectTaps, now)
#bpmDetectTaps > BPM_TAP_WINDOW .(bpmDetectTaps, )
#bpmDetectTaps <
gaps = {}
i = , #bpmDetectTaps
gap = bpmDetectTaps[i] - bpmDetectTaps[i-]
gap > gap < .(gaps, gap)
#gaps ==
.(gaps)
median = gaps[.(#gaps/)]
sum, count = ,
_, g (gaps)
g < median * g > median * sum = sum + g; count = count +
count ==
avgGap = sum / count
detectedBPM = .(( / avgGap) + )
detectedBPM
(beatsPerLoop)
beatsPerLoop = beatsPerLoop beatsPerIdleLoop
idleTrack idleTrack.Length idleTrack.Length <=
bpm = (beatsPerLoop * ) / idleTrack.Length
detectedBPM = .(bpm + )
detectedBPM
()
ok, remote = (()
ReplicatedStorage:(, )
)
ok remote
musicRemote = remote
musicRemote ~=
(text, color)
musicStatusLbl
musicStatusLbl.Text = text
color musicStatusLbl.TextColor3 = color
(expectedId)
.(()
myTick = musicRequestTick
deadline = .() +
snd =
.() < deadline myTick == musicRequestTick
snd = SoundService:(MUSIC_SOUND_NAME)
snd snd.SoundId:(expectedId, , )
.()
myTick ~= musicRequestTick
snd snd.SoundId:(expectedId, , )
(, .(,,))
loadDeadline = .() +
.() < loadDeadline myTick == musicRequestTick
snd.IsLoaded
.()
myTick ~= musicRequestTick
snd.IsLoaded snd.IsPlaying
(, .(,,))
snd.IsLoaded
(, .(,,))
(, .(,,))
)
(id)
musicRemote
(, .(,,))
musicRequestTick = musicRequestTick +
(, .(,,))
musicRemote:(, id)
(id)
()
musicRemote
musicRequestTick = musicRequestTick +
musicRemote:()
(, .(,,))
()
seqPlaying #sequence == animator
seqPlaying =
.(()
_, step (sequence)
seqPlaying
step.id step.id ~=
()
ok, result = (()
anim = .()
anim.AnimationId = ..step.id
t = animator:(anim)
t.Priority = PRIORITY; t.Looped =
t
)
ok
seqTrack = result; seqTrack:()
(step.id, )
.(.(, step.delay ))
()
seqPlaying =
)
()
seqPlaying =
()
()
playlistPlaying #playlist == animator
playlistPlaying =
.(()
playlistPlaying
step = playlist[playlistIndex]
step step.id step.id ~=
()
ok, result = (()
anim = .()
anim.AnimationId = ..step.id
t = animator:(anim)
t.Priority = PRIORITY; t.Looped =
t
)
ok
seqTrack = result; seqTrack:()
(step.id, step.name (..playlistIndex))
.(.(, (step step.delay) ))
playlistPlaying
playlistIndex = playlistIndex +
playlistIndex > #playlist playlistIndex =
refreshPlaylistUI ()
()
)
()
playlistPlaying =
()
()
#playlist ==
playlistIndex = playlistIndex +
playlistIndex > #playlist playlistIndex =
refreshPlaylistUI ()
()
#playlist ==
playlistIndex = playlistIndex -
playlistIndex < playlistIndex = #playlist
refreshPlaylistUI ()
lastNoteTime =
DOUBLE_NOTE_WINDOW =
(input, _gp)
rebindingRow
kn = input.KeyCode input.KeyCode.Name
input.UserInputState == .UserInputState.Begin
kn ~= kn:()
rebindingRow.key = kn
rebindingRow.keyBtn.Text = kn
rebindingRow.keyBtn.BackgroundColor3 = .(, , )
rebindingRow =
_, row (CurrentBindings)
input.KeyCode input.KeyCode.Name == row.key
input.UserInputState == .UserInputState.Begin
now = .()
isDouble = (now - lastNoteTime) <= DOUBLE_NOTE_WINDOW
lastNoteTime = now
k, track (animTracks)
track.IsPlaying
track:()
isDouble
(character)
chosenId = (row)
(row.key, chosenId, row.speedMult, row.holdLoop)
(row.dir)
(row.dir)
()
()
refreshBpmDetectorUI ()
input.UserInputState == .UserInputState.End
(row.key)
(row.dir)
()
(char)
previewCloneContainer
previewClone previewClone:(); previewClone =
wasArchivable = char.Archivable
wasArchivable char.Archivable =
ok, clone = (() char:() )
wasArchivable char.Archivable = wasArchivable
ok clone
(, )
_, d (clone:())
d:() d:() d:()
clone.Name =
clone.Parent = previewCloneContainer
hum = clone:()
hum
hum.DisplayDistanceType = .HumanoidDisplayDistanceType.None
previewAnimator = hum:() .(, hum)
(, )
root = clone:() clone.PrimaryPart
root root.Anchored =
okPivot = (()
clone:(.(, , ))
)
okPivot
hrp = clone:() clone.PrimaryPart
hrp clone:(.(, , ))
previewClone = clone
(char)
(); character = char
(() character:(, ) )
animator = (char)
animator
(char)
legsLocked ()
.(connections, UserInputService.InputBegan:(onInput))
.(connections, UserInputService.InputEnded:(onInput))
hum = char:()
hum .(connections, hum.Died:(cleanupAll))
.(buildPreviewClone, char)
()
(, )
LocalPlayer.Character .(setupCharacter, LocalPlayer.Character)
LocalPlayer.CharacterAdded:((c) .(setupCharacter, c) )
()
found = {}
_, plr (Players:())
plr ~= LocalPlayer plr.Character
hum = plr.Character:()
anr = hum hum:()
anr
_, track (anr:())
animObj = track.Animation
animObj animObj.AnimationId ~=
id = animObj.AnimationId:()
id ~=
.(found, { player = plr.Name, id = id })
found
(p, r)
c = .(); c.CornerRadius = r .(,); c.Parent = p
(p, col, th)
s = .(); s.Color = col; s.Thickness = th ; s.Parent = p; s
(parent, text, pos, size, color, xAlign, ts)
l = .()
l.Size = size; l.Position = pos; l.BackgroundTransparency =
l.Text = text; l.TextColor3 = color .(,,)
l.TextSize = ts ; l.Font = .Font.GothamBold
l.TextXAlignment = xAlign .TextXAlignment.Center
l.Parent = parent; l
(parent, text, pos, size, bg, tc, ts)
b = .()
b.Size = size; b.Position = pos; b.BackgroundColor3 = bg
b.Text = text; b.TextColor3 = tc .(,,)
b.Font = .Font.GothamBold; b.TextSize = ts
b.BorderSizePixel = ; b.Parent = parent; b.AutoButtonColor =
(b)
baseSize = size
hoverGlow = (b, .(,,), )
hoverGlow.Transparency =
b.MouseEnter:(()
TweenService:(b, TweenInfo.(, .EasingStyle.Quad), {
Size = .(baseSize.X.Scale, baseSize.X.Offset + , baseSize.Y.Scale, baseSize.Y.Offset + )
}):()
TweenService:(hoverGlow, TweenInfo.(), { Thickness = , Transparency = }):()
)
b.MouseLeave:(()
TweenService:(b, TweenInfo.(, .EasingStyle.Quad), { Size = baseSize }):()
TweenService:(hoverGlow, TweenInfo.(), { Thickness = , Transparency = }):()
)
b.MouseButton1Down:(()
TweenService:(b, TweenInfo.(), { Size = .(baseSize.X.Scale, baseSize.X.Offset - , baseSize.Y.Scale, baseSize.Y.Offset - ) }):()
)
b.MouseButton1Up:(()
TweenService:(b, TweenInfo.(), { Size = baseSize }):()
)
b
(parent, yPos, color)
d = .(); d.Size = .(,-,,)
d.Position = .(,,,yPos)
d.BackgroundColor3 = color .(,,)
d.BorderSizePixel = ; d.Parent = parent
d
(parent, pos, size, placeholder, default)
b = .()
b.Size = size; b.Position = pos
b.BackgroundColor3 = .(,,)
b.PlaceholderText = placeholder ; b.PlaceholderColor3 = .(,,)
b.Text = default ; b.TextColor3 = .(,,)
b.ClearTextOnFocus = ; b.Font = .Font.Code; b.TextSize =
b.Parent = parent; (b); b
(parent, pos, size, minVal, maxVal, default, onChange)
track = .()
track.Size = size; track.Position = pos
track.BackgroundColor3 = .(,,)
track.BorderSizePixel = ; track.Active =
track.Parent = parent; (track, .(,))
fill = .()
fill.BackgroundColor3 = .(,,)
fill.BorderSizePixel = ; fill.Size = .(,,,)
fill.Parent = track; (fill, .(,))
(fill)
handle = .()
handle.Size = .(,,,)
handle.AnchorPoint = .(,)
handle.Position = .(,,,)
handle.BackgroundColor3 = .(,,)
handle.BorderSizePixel = ; handle.ZIndex =
handle.Parent = track; (handle, .(,))
hStroke = (handle, .(,,), )
(hStroke)
value = default
dragging =
(v, fire)
v = .(v, minVal, maxVal)
value = v
pct = (maxVal > minVal) (v - minVal) / (maxVal - minVal)
fill.Size = .(pct, , , )
handle.Position = .(pct, , , )
fire onChange (v)
(x)
abs = track.AbsolutePosition.X
w = track.AbsoluteSize.X
w <=
pct = .((x - abs) / w, , )
(minVal + pct * (maxVal - minVal), )
(input)
input.UserInputType == .UserInputType.MouseButton1
input.UserInputType == .UserInputType.Touch
dragging =
(input.Position.X)
track.InputBegan:(tryBegin)
handle.InputBegan:((input)
input.UserInputType == .UserInputType.MouseButton1
input.UserInputType == .UserInputType.Touch
dragging =
)
UserInputService.InputChanged:((input)
dragging (input.UserInputType == .UserInputType.MouseMovement
input.UserInputType == .UserInputType.Touch)
(input.Position.X)
)
UserInputService.InputEnded:((input)
input.UserInputType == .UserInputType.MouseButton1
input.UserInputType == .UserInputType.Touch
dragging =
)
(default, )
{ track = track, fill = fill, handle = handle, setValue = setValue, getValue = () value }
(row, listFrame)
_, c (listFrame:())
c:() c:() c:()
j, alt (row.alts)
entry = .()
entry.Size = .(,-,,)
entry.BackgroundColor3 = .(,,)
entry.BorderSizePixel =
entry.LayoutOrder = j
entry.Parent = listFrame
(entry, .(,))
(entry, .(, alt.id, alt.chance),
.(,,,), .(,-,,), .(,,), .TextXAlignment.Left, )
rem = (entry, , .(,-,,), .(,,,), .(,,), , )
rem.MouseButton1Click:(()
.(row.alts, j)
(row, listFrame)
)
total =
_, a (row.alts) total += a.chance
footer = (listFrame, .(, total),
.(,-,,), .(,-,,),
(total > ) .(,,) .(,,),
.TextXAlignment.Right, )
footer.LayoutOrder =
()
old = PlayerGui:()
old old:()
sg = .()
sg.Name = ; sg.ResetOnSpawn =
sg.ZIndexBehavior = .ZIndexBehavior.Sibling; sg.Parent = PlayerGui
totalW = #ARROW_ORDER * ARROW_SIZE + (#ARROW_ORDER - ) * ARROW_GAP
bottomY =
i, dir (ARROW_ORDER)
colors = ARROW_COLORS[dir]
cx = -totalW/ + (i-)*(ARROW_SIZE + ARROW_GAP) + ARROW_SIZE/
cy = -(ARROW_SIZE/ + bottomY)
bg = .()
bg.AnchorPoint = .(, )
bg.Size = .(, ARROW_SIZE, , ARROW_SIZE)
bg.Position = .(, cx, , cy)
bg.BackgroundColor3 = colors.idle
bg.BorderSizePixel = ; bg.Parent = sg
(bg, .(, ))
stroke = (bg, .(,,), )
glow = .()
glow.Size = .(,,,); glow.BackgroundTransparency =
glow.BackgroundColor3 = colors.hit; glow.BorderSizePixel = ; glow.Parent = bg
(glow, .(,))
glow.Visible =
lbl = .()
lbl.Size = .(,,,); lbl.BackgroundTransparency =
lbl.Text = ARROW_SYMBOLS[dir]
lbl.TextColor3 = .(,,)
lbl.TextSize = ; lbl.Font = .Font.GothamBold; lbl.Parent = bg
arrowHudFrames[dir] = { bg = bg, lbl = lbl, stroke = stroke, glow = glow }
()
micAvailable =
ok = (()
micDeviceInput = .()
micDeviceInput.Parent = LocalPlayer
micAnalyzer = .()
micAnalyzer.WindowSize =
micAnalyzer.Parent = LocalPlayer
micWire = .()
micWire.SourceInstance = micDeviceInput
micWire.TargetInstance = micAnalyzer
micWire.Parent = micAnalyzer
micDeviceInput.Active =
)
micAvailable = ok micDeviceInput ~= micAnalyzer ~=
micAvailable
()
micAvailable
eqBars, waveBars, beatDot, notesLayer, particleLayer = , , , ,
()
.(()
speed = StatusState.playing
.(speed)
eqBars
_, bar (eqBars)
h = StatusState.playing ( + .() * ) ( + .() * )
TweenService:(bar, TweenInfo.(speed, .EasingStyle.Sine), {
Size = .(, , h, )
}):()
)
.(()
t =
RunService.Heartbeat:()
t = t + (StatusState.bpm / ) *
waveBars
i, bar (waveBars)
h = + * ( + * .(t + i * ))
bar.Size = .(, , h, )
)
.(()
interval = / .(, StatusState.bpm)
.(interval)
beatDot
beatDot.Size = .(, , , )
TweenService:(beatDot, TweenInfo.(interval * , .EasingStyle.Quad), {
Size = .(, , , )
}):()
)
.(()
symbols = { , , , }
.( + .() * )
notesLayer
n = .()
n.Size = .(, , , )
n.Position = .(.(), , , )
n.BackgroundTransparency =
n.Text = symbols[.(, #symbols)]
n.TextColor3 = THEMES[currentThemeName].accent
n.TextTransparency =
n.Font = .Font.GothamBold
n.TextSize = + .(, )
n.Parent = notesLayer
(n)
tw = TweenService:(n, TweenInfo.( + .()*, .EasingStyle.Linear), {
Position = .(n.Position.X.Scale, , -, ),
TextTransparency =
})
tw:()
tw.Completed:(() n:() )
)
.(()
.( + .() * )
particleLayer
p = .()
sz = .(, )
p.Size = .(, sz, , sz)
p.Position = .(.(), , , )
p.BackgroundColor3 = THEMES[currentThemeName].accent2
p.BackgroundTransparency =
p.BorderSizePixel =
p.Parent = particleLayer
uiCorner(p, UDim.new(1,0))
local tw = TweenService:Create(p, TweenInfo.new(1.5 + math.random(), Enum.EasingStyle.Sine), {
Position = UDim2.new(p.Position.X.Scale + (math.random()-0.5)*0.1, 0, -0.05, 0),
BackgroundTransparency = 1
})
tw:Play()
tw.Completed:Connect(function() p:Destroy() end)
end
end
end)
-- Vinyl record spin: RPM scales with whatever's currently playing —
-- directional anim speedMult if one is active, otherwise idle BPM ratio.
task.spawn(function()
while true do
RunService.Heartbeat:Wait()
if vinylImage then
local rpm
if StatusState.playing and StatusState.speedMult then
rpm = vinylBaseRPM * StatusState.speedMult
else
rpm = vinylBaseRPM * idleSpeedFromBPM()
end
vinylRotation = (vinylRotation + (rpm / 60) * 360 * (1/60)) % 360
vinylImage.Rotation = vinylRotation
end
end
end)
-- Spectrogram: real mic spectrum if available, otherwise an
-- animation/BPM-synced fallback so the bars are never just dead.
task.spawn(function()
while true do
task.wait(0.05)
if #specBars > 0 then
if micAvailable and micAnalyzer then
local ok, spectrum = pcall(function() return micAnalyzer:GetSpectrum() end)
if ok and spectrum then
local n = #spectrum
for i, bar in ipairs(specBars) do
local idx = math.max(1, math.floor((i / #specBars) * n))
local mag = spectrum[idx] or 0
local h = math.clamp(mag * 2, 0.05, 1)
TweenService:Create(bar, TweenInfo.new(0.05), { Size = UDim2.new(1,0,h,0) }):Play()
end
else
micAvailable = false -- analyzer stopped working mid-session, fall back
end
else
for i, bar in ipairs(specBars) do
local base = StatusState.playing and 0.3 or 0.08
local h = base + math.random() * (StatusState.playing and 0.6 or 0.15)
TweenService:Create(bar, TweenInfo.new(0.05), { Size = UDim2.new(1,0,h,0) }):Play()
end
end
end
end
end)
-- CRT flicker: tiny random transparency jitter on the scanline overlay
task.spawn(function()
while true do
task.wait(0.08 + math.random() * 0.15)
if crtEnabled and crtOverlay then
crtOverlay.BackgroundTransparency = 0.82 + math.random() * 0.08
end
end
end)
-- (preview camera orbit loop lives in buildGUI, started once previewCam exists)
end
-- ============================================================
-- MAIN GUI BUILD
-- ============================================================
local function buildGUI()
local old = PlayerGui:FindFirstChild("FNFInjectorGui")
if old then old:Destroy() end
local sg = Instance.new("ScreenGui")
sg.Name = "FNFInjectorGui"
sg.ResetOnSpawn = false
sg.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
sg.Parent = PlayerGui
-- Notification stack (top-right of screen, independent of main panel)
notifyContainer = Instance.new("Frame")
notifyContainer.Size = UDim2.new(0, 260, 1, -20)
notifyContainer.Position = UDim2.new(1, -270, 0, 10)
notifyContainer.BackgroundTransparency = 1
notifyContainer.Parent = sg
local notifyLayout = Instance.new("UIListLayout")
notifyLayout.SortOrder = Enum.SortOrder.LayoutOrder
notifyLayout.Padding = UDim.new(0, 6)
notifyLayout.Parent = notifyContainer
local MAIN_W, MAIN_H = 430, 600
local main = Instance.new("Frame")
main.Name = "Main"; main.Size = UDim2.new(0,MAIN_W,0,MAIN_H)
main.Position = UDim2.new(0,60,0,60)
main.BackgroundColor3 = Color3.fromRGB(13,13,18)
main.BorderSizePixel = 0; main.Active = true; main.Draggable = true
main.Parent = sg; uiCorner(main, UDim.new(0,10))
local mainStroke = uiStroke(main, Color3.fromRGB(255,80,180), 2)
regStroke(mainStroke)
-- decorative background particle / notes layers, clipped to main panel
particleLayer = Instance.new("Frame")
particleLayer.Size = UDim2.new(1,0,1,0); particleLayer.BackgroundTransparency = 1
particleLayer.ClipsDescendants = true; particleLayer.ZIndex = 0; particleLayer.Parent = main
notesLayer = Instance.new("Frame")
notesLayer.Size = UDim2.new(1,0,1,0); notesLayer.BackgroundTransparency = 1
notesLayer.ClipsDescendants = true; notesLayer.ZIndex = 0; notesLayer.Parent = main
-- CRT overlay: green tint + scanlines, sits above everything else in
-- the panel but ignores input so it never blocks clicks. Hidden by
-- default; toggled from the FX tab.
crtOverlay = Instance.new("Frame")
crtOverlay.Size = UDim2.new(1,0,1,0); crtOverlay.BackgroundColor3 = Color3.fromRGB(20,255,120)
crtOverlay.BackgroundTransparency = 0.88
crtOverlay.BorderSizePixel = 0; crtOverlay.ZIndex = 50
crtOverlay.Visible = false
crtOverlay.Parent = main
local crtOverlayCorner = Instance.new("UICorner"); crtOverlayCorner.CornerRadius = UDim.new(0,10); crtOverlayCorner.Parent = crtOverlay
local scanlineHolder = Instance.new("Frame")
scanlineHolder.Size = UDim2.new(1,0,1,0); scanlineHolder.BackgroundTransparency = 1
scanlineHolder.ClipsDescendants = true; scanlineHolder.ZIndex = 51
scanlineHolder.Parent = crtOverlay
local SCANLINE_GAP = 4
for y = 0, 700, SCANLINE_GAP do
local line = Instance.new("Frame")
line.Size = UDim2.new(1,0,0,1)
line.Position = UDim2.new(0,0,0,y)
line.BackgroundColor3 = Color3.fromRGB(0,0,0)
line.BackgroundTransparency = 0.55
line.BorderSizePixel = 0
line.ZIndex = 51
line.Parent = scanlineHolder
end
-- Title bar
local titleBar = Instance.new("Frame")
titleBar.Size = UDim2.new(1,0,0,36); titleBar.BackgroundColor3 = Color3.fromRGB(22,8,32)
titleBar.BorderSizePixel = 0; titleBar.Parent = main; uiCorner(titleBar, UDim.new(0,10))
local titleLbl = makeLabel(titleBar, "🎵 FNF ANIM INJECTOR v6.1",
UDim2.new(0,12,0,0), UDim2.new(1,-80,1,0),
Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 13)
regText(titleLbl)
local toggleBtn = makeBtn(titleBar, "HIDE",
UDim2.new(1,-68,0,5), UDim2.new(0,60,0,26), Color3.fromRGB(255,80,180))
regBg(toggleBtn)
-- Tab bar
local TAB_H = 32
local tabBar = Instance.new("Frame")
tabBar.Size = UDim2.new(1,0,0,TAB_H); tabBar.Position = UDim2.new(0,0,0,36)
tabBar.BackgroundColor3 = Color3.fromRGB(18,8,28)
tabBar.BorderSizePixel = 0; tabBar.Parent = main
-- Content area
local contentArea = Instance.new("Frame")
contentArea.Size = UDim2.new(1,0,1,-(36+TAB_H))
contentArea.Position = UDim2.new(0,0,0,36+TAB_H)
contentArea.BackgroundTransparency = 1; contentArea.Parent = main
-- ── Tabs ──
local tabNames = { "📋 BINDS", "🎬 MAKER", "👁 PREVIEW", "❤ FAVES", "🎶 LIST", "🎛 FX", "⚙ SETTINGS" }
local pages = {}
local tabButtons = {}
local tabW = math.floor(MAIN_W / #tabNames)
for i, name in ipairs(tabNames) do
local page = Instance.new("ScrollingFrame")
page.Size = UDim2.new(1,0,1,0); page.BackgroundTransparency = 1
page.ScrollBarThickness = 4
page.CanvasSize = UDim2.new(0,0,0,0)
page.AutomaticCanvasSize = Enum.AutomaticSize.Y
page.Visible = (i == 1); page.Parent = contentArea
pages[name] = page
local tb = makeBtn(tabBar, name,
UDim2.new(0,(i-1)*tabW,0,0), UDim2.new(0,tabW,1,0),
i == 1 and Color3.fromRGB(255,80,180) or Color3.fromRGB(28,12,42), nil, 9)
tabButtons[name] = tb
if i == 1 then regBg(tb) end
tb.MouseButton1Click:Connect(function()
for n, p in pairs(pages) do
p.Visible = (n == name)
end
for n, btn in pairs(tabButtons) do
local isActive = (n == name)
btn.BackgroundColor3 = isActive and THEMES[currentThemeName].accent or Color3.fromRGB(28,12,42)
-- swap registration so theme/RGB cycling keeps following the active tab
for j = #themedBgs, 1, -1 do if themedBgs[j] == btn then table.remove(themedBgs, j) end end
if isActive then regBg(btn) end
end
end)
end
-- ============================================================
-- TAB 1 : BINDS + IDLE + BPM
-- ============================================================
local pg1 = pages["📋 BINDS"]
makeLabel(pg1, "DIR", UDim2.new(0,8,0,6), UDim2.new(0,36,0,20), Color3.fromRGB(255,80,180))
makeLabel(pg1, "KEY", UDim2.new(0,48,0,6), UDim2.new(0,62,0,20), Color3.fromRGB(255,80,180))
makeLabel(pg1, "ANIM ID", UDim2.new(0,116,0,6), UDim2.new(0,180,0,20),Color3.fromRGB(255,80,180))
makeLabel(pg1, "TEST", UDim2.new(0,308,0,6), UDim2.new(0,90,0,20), Color3.fromRGB(255,80,180))
makeDivider(pg1, 28, Color3.fromRGB(0,200,255))
-- ROW_H covers: dir/key/id/test line, speed slider line, hold-loop +
-- alt-input line, and a small scrollable alt list — per binding row.
local ROW_H = 150
local startY = 36
for i, row in ipairs(CurrentBindings) do
local y = startY + (i-1)*ROW_H
local dirColor = ARROW_COLORS[row.dir] and ARROW_COLORS[row.dir].hit or Color3.fromRGB(255,255,255)
makeLabel(pg1, row.dir, UDim2.new(0,8,0,y), UDim2.new(0,36,0,28), dirColor)
local keyBtn = makeBtn(pg1, row.key, UDim2.new(0,48,0,y), UDim2.new(0,60,0,28), Color3.fromRGB(25,35,48))
row.keyBtn = keyBtn
keyBtn.MouseButton1Click:Connect(function()
rebindingRow = row; keyBtn.Text = "..."
keyBtn.BackgroundColor3 = Color3.fromRGB(0,200,255)
end)
local idBox = makeBox(pg1, UDim2.new(0,116,0,y), UDim2.new(0,180,0,28), "anim id", row.id)
idBox.FocusLost:Connect(function()
local n = idBox.Text:gsub("%D","")
if n ~= "" then row.id = n; destroyTrack(row.key) else idBox.Text = row.id end
end)
local testBtn = makeBtn(pg1, "▶ TEST", UDim2.new(0,306,0,y), UDim2.new(0,90,0,28), Color3.fromRGB(0,180,230), nil, 11)
testBtn.MouseButton1Down:Connect(function()
local chosenId = rollBindingAnimId(row)
playAnim(row.key, chosenId, row.speedMult, row.holdLoop); hitArrow(row.dir); swapFace(row.dir)
end)
testBtn.MouseButton1Up:Connect(function() stopAnim(row.key); releaseArrow(row.dir); restoreFace() end)
local sy = y + 30
makeLabel(pg1, "SPD", UDim2.new(0,8,0,sy), UDim2.new(0,32,0,22), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local spdValLbl = makeLabel(pg1, string.format("x%.2f", row.speedMult),
UDim2.new(0,280,0,sy), UDim2.new(0,112,0,22), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Right, 10)
regText(spdValLbl)
makeSlider(pg1, UDim2.new(0,42,0,sy+2), UDim2.new(0,232,0,14), 0.25, 3, row.speedMult, function(v)
row.speedMult = v
spdValLbl.Text = string.format("x%.2f", v)
if StatusState.currentAnimName == row.key then
StatusState.speedMult = v
if refreshStatusUI then refreshStatusUI() end
end
end)
-- ── HOLD-LOOP toggle + alt-animation entry inputs ──
local sy2 = y + 58
local holdBtn = makeBtn(pg1, "🔁 HOLD-LOOP: OFF", UDim2.new(0,8,0,sy2), UDim2.new(0,140,0,24), Color3.fromRGB(35,35,55), nil, 9)
holdBtn.MouseButton1Click:Connect(function()
row.holdLoop = not row.holdLoop
holdBtn.Text = row.holdLoop and "🔁 HOLD-LOOP: ON" or "🔁 HOLD-LOOP: OFF"
holdBtn.BackgroundColor3 = row.holdLoop and Color3.fromRGB(0,180,230) or Color3.fromRGB(35,35,55)
end)
local altIdBox = makeBox(pg1, UDim2.new(0,154,0,sy2), UDim2.new(0,142,0,24), "alt anim id")
local altPctBox = makeBox(pg1, UDim2.new(0,300,0,sy2), UDim2.new(0,52,0,24), "%")
local addAltBtn = makeBtn(pg1, "+", UDim2.new(0,356,0,sy2), UDim2.new(0,40,0,24), Color3.fromRGB(60,190,120), nil, 12)
-- ── mini scrolling list of this row's configured alts ──
local sy3 = y + 86
local altListFrame = Instance.new("ScrollingFrame")
altListFrame.Size = UDim2.new(1,-16,0,56)
altListFrame.Position = UDim2.new(0,8,0,sy3)
altListFrame.BackgroundColor3 = Color3.fromRGB(18,18,26)
altListFrame.BorderSizePixel = 0
altListFrame.ScrollBarThickness = 3
altListFrame.CanvasSize = UDim2.new(0,0,0,0)
altListFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y
altListFrame.Parent = pg1
uiCorner(altListFrame, UDim.new(0,6))
local altListLayout = Instance.new("UIListLayout")
altListLayout.Padding = UDim.new(0,2)
altListLayout.Parent = altListFrame
local altListPad = Instance.new("UIPadding")
altListPad.PaddingTop = UDim.new(0,2); altListPad.PaddingLeft = UDim.new(0,2); altListPad.PaddingRight = UDim.new(0,2)
altListPad.Parent = altListFrame
addAltBtn.MouseButton1Click:Connect(function()
local id = altIdBox.Text:gsub("%D","")
local chance = tonumber(altPctBox.Text)
if id == "" or not chance then notify("Enter an alt anim ID + % chance", "warn"); return end
table.insert(row.alts, { id = id, chance = math.clamp(chance, 0, 100) })
altIdBox.Text = ""; altPctBox.Text = ""
refreshRowAltList(row, altListFrame)
end)
refreshRowAltList(row, altListFrame)
end
-- Idle section
local idleY = startY + #CurrentBindings * ROW_H + 6
makeDivider(pg1, idleY, Color3.fromRGB(255,80,180))
local idleTitleLbl = makeLabel(pg1, "🎵 IDLE ANIMATION",
UDim2.new(0,8,0,idleY+6), UDim2.new(0,200,0,20),
Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left)
regText(idleTitleLbl)
local statusLbl = makeLabel(pg1, "● OFF",
UDim2.new(0,200,0,idleY+6), UDim2.new(0,196,0,20),
Color3.fromRGB(160,80,80), Enum.TextXAlignment.Right)
local idleIdBox = makeBox(pg1, UDim2.new(0,8,0,idleY+30), UDim2.new(1,-16,0,28), "Paste idle anim ID...")
local loopBtn = makeBtn(pg1, "⟳ LOOP", UDim2.new(0,8,0,idleY+64), UDim2.new(0,120,0,28), Color3.fromRGB(70,120,255))
local onceBtn = makeBtn(pg1, "▶ ONCE", UDim2.new(0,136,0,idleY+64), UDim2.new(0,120,0,28), Color3.fromRGB(60,190,120))
local idleStop = makeBtn(pg1, "■ STOP", UDim2.new(0,264,0,idleY+64), UDim2.new(0,130,0,28), Color3.fromRGB(190,50,50))
local function getIdleId() return idleIdBox.Text:gsub("%D","") end
loopBtn.MouseButton1Click:Connect(function()
local id = getIdleId(); if id == "" then notify("Enter an idle anim ID first", "warn"); return end
playIdleLoop(id); statusLbl.Text = "● LOOPING"; statusLbl.TextColor3 = Color3.fromRGB(80,220,120)
notify("Idle looping started", "success")
end)
onceBtn.MouseButton1Click:Connect(function()
local id = getIdleId(); if id == "" then notify("Enter an idle anim ID first", "warn"); return end
playIdleOnce(id, function()
if not idleLooping then statusLbl.Text = "● OFF"; statusLbl.TextColor3 = Color3.fromRGB(160,80,80) end
end)
statusLbl.Text = "▶ PLAYING"; statusLbl.TextColor3 = Color3.fromRGB(0,200,255)
end)
idleStop.MouseButton1Click:Connect(function()
stopIdle(); statusLbl.Text = "● OFF"; statusLbl.TextColor3 = Color3.fromRGB(160,80,80)
end)
-- BPM controls
local bpmY = idleY + 98
makeLabel(pg1, "BPM", UDim2.new(0,8,0,bpmY), UDim2.new(0,38,0,28),
Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 11)
local bpmBox = makeBox(pg1, UDim2.new(0,44,0,bpmY), UDim2.new(0,68,0,28), "100", tostring(idleBPM))
makeLabel(pg1, "BASE", UDim2.new(0,120,0,bpmY), UDim2.new(0,44,0,28),
Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local baseBox = makeBox(pg1, UDim2.new(0,164,0,bpmY), UDim2.new(0,68,0,28), "100", tostring(BASE_BPM))
local applyBpmBtn = makeBtn(pg1, "✓ APPLY", UDim2.new(0,240,0,bpmY), UDim2.new(0,154,0,28), Color3.fromRGB(70,120,255), nil, 11)
local bpmSliderY = bpmY + 36
makeLabel(pg1, "DRAG", UDim2.new(0,8,0,bpmSliderY), UDim2.new(0,50,0,22), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local bpmValLbl = makeLabel(pg1, string.format("%d BPM", idleBPM),
UDim2.new(0,300,0,bpmSliderY), UDim2.new(0,94,0,22), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Right, 11)
regText(bpmValLbl)
local bpmSlider = makeSlider(pg1, UDim2.new(0,62,0,bpmSliderY+2), UDim2.new(0,232,0,14), 40, 300, idleBPM, function(v)
v = math.floor(v + 0.5)
setIdleBPM(v)
bpmBox.Text = tostring(v)
bpmValLbl.Text = string.format("%d BPM", v)
end)
bpmBox.FocusLost:Connect(function()
local n = tonumber(bpmBox.Text)
if n and n > 0 then
idleBPM = n
bpmSlider.setValue(n, false)
bpmValLbl.Text = string.format("%d BPM", n)
setIdleBPM(n)
else
bpmBox.Text = tostring(idleBPM)
end
end)
baseBox.FocusLost:Connect(function()
local n = tonumber(baseBox.Text)
if n and n > 0 then BASE_BPM = n else baseBox.Text = tostring(BASE_BPM) end
setIdleBPM(idleBPM)
end)
applyBpmBtn.MouseButton1Click:Connect(function()
local n = tonumber(bpmBox.Text)
local b = tonumber(baseBox.Text)
if n and n > 0 then idleBPM = n; bpmSlider.setValue(n, false); bpmValLbl.Text = string.format("%d BPM", n) end
if b and b > 0 then BASE_BPM = b end
setIdleBPM(idleBPM)
notify("BPM settings applied", "info")
end)
-- Beat-sync indicator + mini equalizer, docked at bottom of binds tab
local vizY = bpmSliderY + 34
makeDivider(pg1, vizY, Color3.fromRGB(0,200,255))
makeLabel(pg1, "BEAT SYNC", UDim2.new(0,8,0,vizY+6), UDim2.new(0,90,0,18), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
beatDot = Instance.new("Frame")
beatDot.AnchorPoint = Vector2.new(0.5,0.5)
beatDot.Size = UDim2.new(0,10,0,10)
beatDot.Position = UDim2.new(0,100,0,vizY+15)
beatDot.BackgroundColor3 = Color3.fromRGB(255,80,180)
beatDot.BorderSizePixel = 0; beatDot.Parent = pg1
uiCorner(beatDot, UDim.new(1,0))
regBg(beatDot)
makeLabel(pg1, "EQUALIZER", UDim2.new(0,140,0,vizY+6), UDim2.new(0,100,0,18), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local eqHolder = Instance.new("Frame")
eqHolder.Size = UDim2.new(0,120,0,26); eqHolder.Position = UDim2.new(0,140,0,vizY+22)
eqHolder.BackgroundTransparency = 1; eqHolder.Parent = pg1
local eqLayout = Instance.new("UIListLayout")
eqLayout.FillDirection = Enum.FillDirection.Horizontal
eqLayout.Padding = UDim.new(0,3)
eqLayout.VerticalAlignment = Enum.VerticalAlignment.Bottom
eqLayout.Parent = eqHolder
eqBars = {}
for i = 1, 8 do
local bar = Instance.new("Frame")
bar.Size = UDim2.new(0, 10, 0.2, 0)
bar.BackgroundColor3 = THEMES[currentThemeName].accent
bar.BorderSizePixel = 0
bar.Parent = eqHolder
uiCorner(bar, UDim.new(0,2))
regBg(bar)
table.insert(eqBars, bar)
end
makeLabel(pg1, "WAVEFORM", UDim2.new(0,270,0,vizY+6), UDim2.new(0,120,0,18), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local waveHolder = Instance.new("Frame")
waveHolder.Size = UDim2.new(0,130,0,26); waveHolder.Position = UDim2.new(0,270,0,vizY+22)
waveHolder.BackgroundTransparency = 1; waveHolder.Parent = pg1
local waveLayout = Instance.new("UIListLayout")
waveLayout.FillDirection = Enum.FillDirection.Horizontal
waveLayout.Padding = UDim.new(0,2)
waveLayout.VerticalAlignment = Enum.VerticalAlignment.Center
waveLayout.Parent = waveHolder
waveBars = {}
for i = 1, 16 do
local bar = Instance.new("Frame")
bar.Size = UDim2.new(0, 5, 0.3, 0)
bar.BackgroundColor3 = THEMES[currentThemeName].accent2
bar.BorderSizePixel = 0
bar.Parent = waveHolder
uiCorner(bar, UDim.new(0,2))
table.insert(waveBars, bar)
end
-- ============================================================
-- STATUS PANEL (bottom-fixed strip inside binds tab; also mirrored on preview tab)
-- ============================================================
local statusY = vizY + 60
makeDivider(pg1, statusY, Color3.fromRGB(255,80,180))
local statusTitle = makeLabel(pg1, "📊 STATUS", UDim2.new(0,8,0,statusY+6), UDim2.new(0,120,0,18), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 11)
regText(statusTitle)
local statLbl1 = makeLabel(pg1, "Anim: —", UDim2.new(0,8,0,statusY+26), UDim2.new(1,-16,0,16), Color3.fromRGB(210,210,220), Enum.TextXAlignment.Left, 10)
local statLbl2 = makeLabel(pg1, "Speed: x1.00 BPM: 100 State: STOPPED", UDim2.new(0,8,0,statusY+44), UDim2.new(1,-16,0,16), Color3.fromRGB(160,160,180), Enum.TextXAlignment.Left, 10)
function refreshStatusUI()
statLbl1.Text = string.format("Anim: %s (%s)", StatusState.currentAnimName, StatusState.currentAnimId ~= "" and StatusState.currentAnimId or "—")
statLbl2.Text = string.format("Speed: x%.2f BPM: %d State: %s",
StatusState.speedMult, StatusState.bpm, StatusState.playing and "PLAYING" or "STOPPED")
end
refreshStatusUI()
-- ============================================================
-- TAB 2 : ANIMATION SEQUENCE MAKER
-- ============================================================
local pg2 = pages["🎬 MAKER"]
local makerTitle = makeLabel(pg2, "🎬 ANIMATION SEQUENCE MAKER",
UDim2.new(0,8,0,6), UDim2.new(1,-16,0,20),
Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(makerTitle)
makeDivider(pg2, 28, Color3.fromRGB(0,200,255))
makeLabel(pg2, "ANIM ID", UDim2.new(0,8,0,34), UDim2.new(0,220,0,16), Color3.fromRGB(160,160,160))
makeLabel(pg2, "DELAY (s)", UDim2.new(0,232,0,34), UDim2.new(0,80,0,16), Color3.fromRGB(160,160,160))
local seqScroll = Instance.new("ScrollingFrame")
seqScroll.Size = UDim2.new(1,-16,0,182); seqScroll.Position = UDim2.new(0,8,0,52)
seqScroll.BackgroundColor3 = Color3.fromRGB(18,18,26); seqScroll.BorderSizePixel = 0
seqScroll.ScrollBarThickness = 4; seqScroll.CanvasSize = UDim2.new(0,0,0,0)
seqScroll.Parent = pg2; uiCorner(seqScroll)
local seqLayout = Instance.new("UIListLayout")
seqLayout.SortOrder = Enum.SortOrder.LayoutOrder; seqLayout.Padding = UDim.new(0,4)
seqLayout.Parent = seqScroll
local seqPad = Instance.new("UIPadding")
seqPad.PaddingTop = UDim.new(0,4); seqPad.PaddingLeft = UDim.new(0,4); seqPad.PaddingRight = UDim.new(0,4)
seqPad.Parent = seqScroll
local function updateCanvas()
seqScroll.CanvasSize = UDim2.new(0,0,0, seqLayout.AbsoluteContentSize.Y + 10)
end
seqLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(updateCanvas)
local seqStatusLbl = makeLabel(pg2, "● IDLE",
UDim2.new(0,8,0,310), UDim2.new(1,-16,0,18), Color3.fromRGB(160,80,80), Enum.TextXAlignment.Left)
local function addSeqRow(id, delay)
local step = { id = id or "", delay = delay or 0.5 }
table.insert(sequence, step)
local row = Instance.new("Frame")
row.Size = UDim2.new(1,-8,0,30); row.BackgroundColor3 = Color3.fromRGB(24,24,36)
row.BorderSizePixel = 0; row.LayoutOrder = #sequence; row.Parent = seqScroll
uiCorner(row, UDim.new(0,6))
local idIn = makeBox(row, UDim2.new(0,4,0,3), UDim2.new(0,206,0,24), "Animation ID", step.id)
idIn.FocusLost:Connect(function() step.id = idIn.Text:gsub("%D","") end)
local dlIn = makeBox(row, UDim2.new(0,216,0,3), UDim2.new(0,64,0,24), "0.5", tostring(step.delay))
dlIn.FocusLost:Connect(function() step.delay = tonumber(dlIn.Text) or 0.5 end)
local rem = makeBtn(row, "✕", UDim2.new(0,286,0,3), UDim2.new(0,28,0,24), Color3.fromRGB(170,35,35), nil, 12)
rem.MouseButton1Click:Connect(function()
for j, s in ipairs(sequence) do if s == step then table.remove(sequence, j); break end end
for j, r in ipairs(seqRowFrames) do if r == row then table.remove(seqRowFrames, j); break end end
row:Destroy(); updateCanvas()
end)
table.insert(seqRowFrames, row); updateCanvas()
end
makeBtn(pg2, "+ ADD STEP", UDim2.new(0,8,0,240), UDim2.new(1,-16,0,26), Color3.fromRGB(35,35,55))
.MouseButton1Click:Connect(function() addSeqRow("", 0.5) end)
local seqPlay = makeBtn(pg2, "▶ PLAY SEQUENCE", UDim2.new(0,8,0,272), UDim2.new(0,176,0,30), Color3.fromRGB(60,190,120))
local seqStop = makeBtn(pg2, "■ STOP", UDim2.new(0,192,0,272), UDim2.new(0,90,0,30), Color3.fromRGB(190,50,50))
local seqClear = makeBtn(pg2, "🗑 CLEAR", UDim2.new(0,290,0,272), UDim2.new(0,106,0,30), Color3.fromRGB(70,25,70))
seqPlay.MouseButton1Click:Connect(function()
if #sequence == 0 then seqStatusLbl.Text = "⚠ Add steps first"; notify("Add a step first", "warn"); return end
playSequence()
seqStatusLbl.Text = "▶ RUNNING"; seqStatusLbl.TextColor3 = Color3.fromRGB(80,220,120)
notify("Sequence started", "info")
task.spawn(function()
while seqPlaying do task.wait(0.1) end
seqStatusLbl.Text = "● IDLE"; seqStatusLbl.TextColor3 = Color3.fromRGB(160,80,80)
end)
end)
seqStop.MouseButton1Click:Connect(function()
stopSequence(); seqStatusLbl.Text = "● IDLE"; seqStatusLbl.TextColor3 = Color3.fromRGB(160,80,80)
end)
seqClear.MouseButton1Click:Connect(function()
stopSequence(); sequence = {}
for _, r in ipairs(seqRowFrames) do pcall(function() r:Destroy() end) end
seqRowFrames = {}; updateCanvas()
seqStatusLbl.Text = "● IDLE"; seqStatusLbl.TextColor3 = Color3.fromRGB(160,80,80)
end)
-- Quick preset loader
makeDivider(pg2, 330, Color3.fromRGB(0,200,255))
local presetTitle = makeLabel(pg2, "⚡ QUICK PRESETS", UDim2.new(0,8,0,336), UDim2.new(1,-16,0,18), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 11)
regText(presetTitle)
for i, preset in ipairs(PRESETS) do
local py = 356 + (i-1)*32
local pbtn = makeBtn(pg2, "📥 "..preset.name, UDim2.new(0,8,0,py), UDim2.new(1,-16,0,26), Color3.fromRGB(28,12,42), nil, 11)
pbtn.MouseButton1Click:Connect(function()
for _, row in ipairs(CurrentBindings) do
local newId = preset.ids[row.dir]
if newId then
row.id = newId
if row.keyBtn then destroyTrack(row.key) end
end
end
notify("Loaded preset: "..preset.name, "success")
end)
end
-- ============================================================
-- TAB 3 : LIVE PREVIEW
-- ============================================================
local pg3v = pages["👁 PREVIEW"]
local pvTitle = makeLabel(pg3v, "👁 LIVE CHARACTER PREVIEW", UDim2.new(0,8,0,6), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(pvTitle)
makeDivider(pg3v, 28, Color3.fromRGB(0,200,255))
local viewport = Instance.new("ViewportFrame")
viewport.Size = UDim2.new(1,-16,0,260); viewport.Position = UDim2.new(0,8,0,36)
viewport.BackgroundColor3 = Color3.fromRGB(10,10,16)
-- ViewportFrames render pure black without an explicit light source —
-- these three properties act as a simple fill light for the clone.
viewport.Ambient = Color3.fromRGB(140,140,150)
viewport.LightColor = Color3.fromRGB(255,255,255)
viewport.LightDirection = Vector3.new(-0.6, -1, -0.4)
viewport.Parent = pg3v
uiCorner(viewport)
local vpStroke = uiStroke(viewport, Color3.fromRGB(255,80,180), 2)
regStroke(vpStroke)
previewCloneContainer = Instance.new("WorldModel")
previewCloneContainer.Parent = viewport
previewCam = Instance.new("Camera")
previewCam.FieldOfView = 60
previewCam.CFrame = CFrame.new(Vector3.new(0, 3, 6), Vector3.new(0, 3, 0))
viewport.CurrentCamera = previewCam
previewCam.Parent = viewport
-- fix the earlier placeholder orbit loop now that previewCam/container exist
task.spawn(function()
while true do
RunService.Heartbeat:Wait()
if previewCam then
previewAngle = previewAngle + 0.3
local rad = math.rad(previewAngle)
local dist = 6
local pos = Vector3.new(math.sin(rad) * dist, 4, math.cos(rad) * dist)
previewCam.CFrame = CFrame.new(pos, Vector3.new(0, 3, 0))
end
end
end)
local pvHint = makeLabel(pg3v, "Rotates automatically. Plays whatever anim you last triggered.",
UDim2.new(0,8,0,300), UDim2.new(1,-16,0,18), Color3.fromRGB(140,140,160), Enum.TextXAlignment.Left, 10)
local pvRefreshBtn = makeBtn(pg3v, "🔄 REFRESH CLONE", UDim2.new(0,8,0,324), UDim2.new(1,-16,0,28), Color3.fromRGB(70,120,255))
pvRefreshBtn.MouseButton1Click:Connect(function()
if character then buildPreviewClone(character); notify("Preview clone refreshed", "info") end
end)
-- Status mirror on preview tab
makeDivider(pg3v, 362, Color3.fromRGB(255,80,180))
local pvStat1 = makeLabel(pg3v, "Anim: —", UDim2.new(0,8,0,370), UDim2.new(1,-16,0,16), Color3.fromRGB(210,210,220), Enum.TextXAlignment.Left, 10)
local pvStat2 = makeLabel(pg3v, "Speed: x1.00 BPM: 100 State: STOPPED", UDim2.new(0,8,0,388), UDim2.new(1,-16,0,16), Color3.fromRGB(160,160,180), Enum.TextXAlignment.Left, 10)
local oldRefresh = refreshStatusUI
refreshStatusUI = function()
oldRefresh()
pvStat1.Text = string.format("Anim: %s (%s)", StatusState.currentAnimName, StatusState.currentAnimId ~= "" and StatusState.currentAnimId or "—")
pvStat2.Text = string.format("Speed: x%.2f BPM: %d State: %s",
StatusState.speedMult, StatusState.bpm, StatusState.playing and "PLAYING" or "STOPPED")
end
-- Recents list
makeDivider(pg3v, 414, Color3.fromRGB(0,200,255))
local recentsTitle = makeLabel(pg3v, "🕐 RECENT ANIMATIONS", UDim2.new(0,8,0,420), UDim2.new(1,-16,0,18), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 11)
regText(recentsTitle)
local recentsScroll = Instance.new("ScrollingFrame")
recentsScroll.Size = UDim2.new(1,-16,0,120); recentsScroll.Position = UDim2.new(0,8,0,442)
recentsScroll.BackgroundColor3 = Color3.fromRGB(18,18,26); recentsScroll.BorderSizePixel = 0
recentsScroll.ScrollBarThickness = 4; recentsScroll.CanvasSize = UDim2.new(0,0,0,0)
recentsScroll.Parent = pg3v; uiCorner(recentsScroll)
local recentsLayout = Instance.new("UIListLayout")
recentsLayout.Padding = UDim.new(0,4); recentsLayout.Parent = recentsScroll
function refreshRecentsUI()
for _, c in ipairs(recentsScroll:GetChildren()) do
if c:IsA("Frame") then c:Destroy() end
end
for i, r in ipairs(recents) do
local row = Instance.new("Frame")
row.Size = UDim2.new(1,-8,0,26); row.BackgroundColor3 = Color3.fromRGB(24,24,36)
row.BorderSizePixel = 0; row.LayoutOrder = i; row.Parent = recentsScroll
uiCorner(row, UDim.new(0,6))
makeLabel(row, r.label.." — "..r.id, UDim2.new(0,8,0,0), UDim2.new(1,-90,1,0), Color3.fromRGB(200,200,215), Enum.TextXAlignment.Left, 10)
local playBtn = makeBtn(row, "▶", UDim2.new(1,-40,0,2), UDim2.new(0,32,0,22), Color3.fromRGB(60,190,120), nil, 11)
playBtn.MouseButton1Click:Connect(function()
updatePreviewAnimation(r.id, r.label)
notify("Previewing "..r.label, "info")
end)
end
end
refreshRecentsUI()
-- ============================================================
-- TAB 4 : FAVORITES
-- ============================================================
local pg4 = pages["❤ FAVES"]
local favTitle = makeLabel(pg4, "❤ FAVORITE ANIMATIONS", UDim2.new(0,8,0,6), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(favTitle)
makeDivider(pg4, 28, Color3.fromRGB(0,200,255))
local favNameBox = makeBox(pg4, UDim2.new(0,8,0,36), UDim2.new(0,180,0,28), "Name")
local favIdBox = makeBox(pg4, UDim2.new(0,196,0,36), UDim2.new(0,138,0,28), "Anim ID")
local favAddBtn = makeBtn(pg4, "+ SAVE", UDim2.new(0,340,0,36), UDim2.new(0,74,0,28), Color3.fromRGB(60,190,120), nil, 11)
local favScroll = Instance.new("ScrollingFrame")
favScroll.Size = UDim2.new(1,-16,0,300); favScroll.Position = UDim2.new(0,8,0,72)
favScroll.BackgroundColor3 = Color3.fromRGB(18,18,26); favScroll.BorderSizePixel = 0
favScroll.ScrollBarThickness = 4; favScroll.CanvasSize = UDim2.new(0,0,0,0)
favScroll.Parent = pg4; uiCorner(favScroll)
local favLayout = Instance.new("UIListLayout")
favLayout.Padding = UDim.new(0,4); favLayout.Parent = favScroll
local favPad = Instance.new("UIPadding")
favPad.PaddingTop = UDim.new(0,4); favPad.PaddingLeft = UDim.new(0,4); favPad.PaddingRight = UDim.new(0,4)
favPad.Parent = favScroll
local function refreshFavUI()
for _, c in ipairs(favScroll:GetChildren()) do
if c:IsA("Frame") then c:Destroy() end
end
for i, f in ipairs(favorites) do
local row = Instance.new("Frame")
row.Size = UDim2.new(1,-8,0,32); row.BackgroundColor3 = Color3.fromRGB(24,24,36)
row.BorderSizePixel = 0; row.LayoutOrder = i; row.Parent = favScroll
uiCorner(row, UDim.new(0,6))
makeLabel(row, f.name.." — "..f.id, UDim2.new(0,8,0,0), UDim2.new(1,-116,1,0), Color3.fromRGB(200,200,215), Enum.TextXAlignment.Left, 10)
local playBtn = makeBtn(row, "▶", UDim2.new(1,-146,0,3), UDim2.new(0,34,0,26), Color3.fromRGB(0,180,230), nil, 11)
local addPlBtn = makeBtn(row, "➕LIST", UDim2.new(1,-108,0,3), UDim2.new(0,58,0,26), Color3.fromRGB(70,120,255), nil, 9)
local delBtn = makeBtn(row, "✕", UDim2.new(1,-42,0,3), UDim2.new(0,34,0,26), Color3.fromRGB(170,35,35), nil, 11)
playBtn.MouseButton1Click:Connect(function()
updatePreviewAnimation(f.id, f.name)
pushRecent(f.id, f.name)
notify("Previewing favorite: "..f.name, "info")
end)
addPlBtn.MouseButton1Click:Connect(function()
table.insert(playlist, { name = f.name, id = f.id, delay = 1 })
if refreshPlaylistUI then refreshPlaylistUI() end
notify(f.name.." added to playlist", "success")
end)
delBtn.MouseButton1Click:Connect(function()
table.remove(favorites, i)
refreshFavUI()
end)
end
end
favAddBtn.MouseButton1Click:Connect(function()
local id = favIdBox.Text:gsub("%D","")
local nm = favNameBox.Text ~= "" and favNameBox.Text or ("Fav "..(#favorites+1))
if id == "" then notify("Enter an anim ID to save", "warn"); return end
table.insert(favorites, { name = nm, id = id })
favNameBox.Text = ""; favIdBox.Text = ""
refreshFavUI()
notify("Saved to favorites: "..nm, "success")
end)
refreshFavUI()
-- ============================================================
-- TAB 5 : PLAYLIST MANAGER
-- ============================================================
local pg5 = pages["🎶 LIST"]
local plTitle = makeLabel(pg5, "🎶 PLAYLIST MANAGER", UDim2.new(0,8,0,6), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(plTitle)
makeDivider(pg5, 28, Color3.fromRGB(0,200,255))
local plScroll = Instance.new("ScrollingFrame")
plScroll.Size = UDim2.new(1,-16,0,260); plScroll.Position = UDim2.new(0,8,0,36)
plScroll.BackgroundColor3 = Color3.fromRGB(18,18,26); plScroll.BorderSizePixel = 0
plScroll.ScrollBarThickness = 4; plScroll.CanvasSize = UDim2.new(0,0,0,0)
plScroll.Parent = pg5; uiCorner(plScroll)
local plLayout = Instance.new("UIListLayout")
plLayout.Padding = UDim.new(0,4); plLayout.Parent = plScroll
local plPad = Instance.new("UIPadding")
plPad.PaddingTop = UDim.new(0,4); plPad.PaddingLeft = UDim.new(0,4); plPad.PaddingRight = UDim.new(0,4)
plPad.Parent = plScroll
function refreshPlaylistUI()
for _, c in ipairs(plScroll:GetChildren()) do
if c:IsA("Frame") then c:Destroy() end
end
for i, item in ipairs(playlist) do
local row = Instance.new("Frame")
row.Size = UDim2.new(1,-8,0,30)
row.BackgroundColor3 = (i == playlistIndex and playlistPlaying) and Color3.fromRGB(50,30,60) or Color3.fromRGB(24,24,36)
row.BorderSizePixel = 0; row.LayoutOrder = i; row.Parent = plScroll
uiCorner(row, UDim.new(0,6))
makeLabel(row, string.format("%d. %s — %s", i, item.name or item.id, item.id),
UDim2.new(0,8,0,0), UDim2.new(1,-40,1,0), Color3.fromRGB(200,200,215), Enum.TextXAlignment.Left, 10)
local rem = makeBtn(row, "✕", UDim2.new(1,-34,0,3), UDim2.new(0,26,0,24), Color3.fromRGB(170,35,35), nil, 11)
rem.MouseButton1Click:Connect(function()
table.remove(playlist, i)
refreshPlaylistUI()
end)
end
end
refreshPlaylistUI()
local plAddBox = makeBox(pg5, UDim2.new(0,8,0,300), UDim2.new(0,220,0,26), "Animation ID to add")
local plAddBtn = makeBtn(pg5, "+ ADD", UDim2.new(0,236,0,300), UDim2.new(0,80,0,26), Color3.fromRGB(35,35,55))
plAddBtn.MouseButton1Click:Connect(function()
local id = plAddBox.Text:gsub("%D","")
if id == "" then notify("Enter an anim ID", "warn"); return end
table.insert(playlist, { name = "Track "..(#playlist+1), id = id, delay = 1 })
plAddBox.Text = ""
refreshPlaylistUI()
end)
local plPlay = makeBtn(pg5, "▶ PLAY", UDim2.new(0,8,0,332), UDim2.new(0,96,0,28), Color3.fromRGB(60,190,120), nil, 11)
local plPrev = makeBtn(pg5, "⏮ PREV", UDim2.new(0,110,0,332), UDim2.new(0,86,0,28), Color3.fromRGB(70,120,255), nil, 11)
local plNext = makeBtn(pg5, "NEXT ⏭", UDim2.new(0,202,0,332), UDim2.new(0,86,0,28), Color3.fromRGB(70,120,255), nil, 11)
local plStop = makeBtn(pg5, "■ STOP", UDim2.new(0,294,0,332), UDim2.new(0,100,0,28), Color3.fromRGB(190,50,50), nil, 11)
plPlay.MouseButton1Click:Connect(function()
if #playlist == 0 then notify("Playlist is empty", "warn"); return end
playPlaylist(); notify("Playlist started", "info")
end)
plPrev.MouseButton1Click:Connect(prevPlaylistTrack)
plNext.MouseButton1Click:Connect(nextPlaylistTrack)
plStop.MouseButton1Click:Connect(function() stopPlaylist(); refreshPlaylistUI() end)
-- ============================================================
-- TAB : FX (vinyl record / CRT mode / spectrogram / BPM detector)
-- ============================================================
local pgFx = pages["🎛 FX"]
-- ── Vinyl record widget ──
local vinylTitle = makeLabel(pgFx, "💿 VINYL RECORD", UDim2.new(0,8,0,6), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(vinylTitle)
makeDivider(pgFx, 28, Color3.fromRGB(0,200,255))
makeLabel(pgFx, "Spins faster the higher the current speed / BPM is.",
UDim2.new(0,8,0,34), UDim2.new(1,-16,0,18), Color3.fromRGB(140,140,160), Enum.TextXAlignment.Left, 10)
local vinylHolder = Instance.new("Frame")
vinylHolder.Size = UDim2.new(0,120,0,120); vinylHolder.Position = UDim2.new(0,8,0,56)
vinylHolder.BackgroundColor3 = Color3.fromRGB(8,8,10); vinylHolder.BorderSizePixel = 0
vinylHolder.Parent = pgFx; uiCorner(vinylHolder, UDim.new(1,0))
local vinylHolderStroke = uiStroke(vinylHolder, Color3.fromRGB(255,80,180), 2)
regStroke(vinylHolderStroke)
vinylImage = Instance.new("ImageLabel")
vinylImage.Size = UDim2.new(1,-8,1,-8); vinylImage.Position = UDim2.new(0,4,0,4)
vinylImage.BackgroundTransparency = 1
vinylImage.Image = VINYL_DECAL_ID ~= "" and ("rbxassetid://"..VINYL_DECAL_ID) or ""
vinylImage.ScaleType = Enum.ScaleType.Fit
vinylImage.Parent = vinylHolder
-- fallback ring so it still reads as a record before a decal is set
local vinylRing = Instance.new("Frame")
vinylRing.Size = UDim2.new(1,0,1,0); vinylRing.BackgroundTransparency = 1
vinylRing.Parent = vinylHolder
uiCorner(vinylRing, UDim.new(1,0))
uiStroke(vinylRing, Color3.fromRGB(60,60,65), 1)
local vinylCenter = Instance.new("Frame")
vinylCenter.Size = UDim2.new(0,14,0,14); vinylCenter.AnchorPoint = Vector2.new(0.5,0.5)
vinylCenter.Position = UDim2.new(0.5,0,0.5,0); vinylCenter.BackgroundColor3 = Color3.fromRGB(255,80,180)
vinylCenter.BorderSizePixel = 0; vinylCenter.Parent = vinylHolder
uiCorner(vinylCenter, UDim.new(1,0)); regBg(vinylCenter)
local vinylIdBox = makeBox(pgFx, UDim2.new(0,140,0,56), UDim2.new(1,-148,0,28), "Vinyl decal asset ID")
vinylIdBox.FocusLost:Connect(function()
local id = vinylIdBox.Text:gsub("%D","")
VINYL_DECAL_ID = id
vinylImage.Image = id ~= "" and ("rbxassetid://"..id) or ""
end)
makeLabel(pgFx, "Paste your record-label decal ID above — art rotates with the disc.",
UDim2.new(0,140,0,88), UDim2.new(1,-148,0,32), Color3.fromRGB(130,130,150), Enum.TextXAlignment.Left, 10)
makeLabel(pgFx, "BASE RPM", UDim2.new(0,140,0,124), UDim2.new(0,70,0,24), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local vinylRpmBox = makeBox(pgFx, UDim2.new(0,214,0,124), UDim2.new(0,70,0,24), "33.3", tostring(vinylBaseRPM))
vinylRpmBox.FocusLost:Connect(function()
local n = tonumber(vinylRpmBox.Text)
if n and n > 0 then vinylBaseRPM = n else vinylRpmBox.Text = tostring(vinylBaseRPM) end
end)
-- ── CRT monitor mode ──
makeDivider(pgFx, 190, Color3.fromRGB(255,80,180))
local crtTitle = makeLabel(pgFx, "📺 CRT MONITOR MODE", UDim2.new(0,8,0,196), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(crtTitle)
makeLabel(pgFx, "Adds scanlines + a green-tinted flicker over the whole panel.",
UDim2.new(0,8,0,218), UDim2.new(1,-16,0,18), Color3.fromRGB(140,140,160), Enum.TextXAlignment.Left, 10)
local crtBtn = makeBtn(pgFx, "📴 CRT MODE OFF", UDim2.new(0,8,0,240), UDim2.new(1,-16,0,32), Color3.fromRGB(35,35,55), nil, 11)
crtBtn.MouseButton1Click:Connect(function()
crtEnabled = not crtEnabled
if crtOverlay then crtOverlay.Visible = crtEnabled end
if crtEnabled then
crtBtn.Text = "📺 CRT MODE ON"
crtBtn.BackgroundColor3 = THEMES[currentThemeName].accent
else
crtBtn.Text = "📴 CRT MODE OFF"
crtBtn.BackgroundColor3 = Color3.fromRGB(35,35,55)
end
notify(crtEnabled and "CRT mode enabled" or "CRT mode disabled", "info")
end)
-- ── Mic spectrogram ──
makeDivider(pgFx, 284, Color3.fromRGB(0,200,255))
local specTitle = makeLabel(pgFx, "🎙 SPECTROGRAM (MIC)", UDim2.new(0,8,0,290), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(specTitle)
local specStatusLbl = makeLabel(pgFx, "● not connected", UDim2.new(0,200,0,290), UDim2.new(1,-208,0,20), Color3.fromRGB(160,80,80), Enum.TextXAlignment.Right, 10)
makeLabel(pgFx, "Uses Roblox's mic Audio API if this client/game supports it; otherwise the bars react to animation state instead.",
UDim2.new(0,8,0,312), UDim2.new(1,-16,0,28), Color3.fromRGB(130,130,150), Enum.TextXAlignment.Left, 10)
local specHolder = Instance.new("Frame")
specHolder.Size = UDim2.new(1,-16,0,60); specHolder.Position = UDim2.new(0,8,0,346)
specHolder.BackgroundColor3 = Color3.fromRGB(18,18,26); specHolder.BorderSizePixel = 0
specHolder.Parent = pgFx; uiCorner(specHolder)
local specLayout = Instance.new("UIListLayout")
specLayout.FillDirection = Enum.FillDirection.Horizontal
specLayout.Padding = UDim.new(0,3)
specLayout.VerticalAlignment = Enum.VerticalAlignment.Bottom
specLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
specLayout.Parent = specHolder
specBars = {}
for i = 1, SPEC_BAR_COUNT do
local bar = Instance.new("Frame")
bar.Size = UDim2.new(0, 6, 0.15, 0)
bar.BackgroundColor3 = THEMES[currentThemeName].accent2
bar.BorderSizePixel = 0
bar.Parent = specHolder
uiCorner(bar, UDim.new(0,2))
table.insert(specBars, bar)
end
local micBtn = makeBtn(pgFx, "🎙 REQUEST MIC ACCESS", UDim2.new(0,8,0,414), UDim2.new(1,-16,0,30), Color3.fromRGB(70,120,255), nil, 11)
micBtn.MouseButton1Click:Connect(function()
local success = setupMicSpectrogram()
if success then
specStatusLbl.Text = "● mic connected"; specStatusLbl.TextColor3 = Color3.fromRGB(80,220,120)
notify("Mic spectrogram connected", "success")
else
specStatusLbl.Text = "● using fallback"; specStatusLbl.TextColor3 = Color3.fromRGB(255,180,60)
notify("Mic unavailable here — using animation-synced fallback", "warn")
end
end)
-- ── Animation BPM detector ──
makeDivider(pgFx, 456, Color3.fromRGB(255,80,180))
local bpmDetectTitle = makeLabel(pgFx, "🎯 BPM DETECTOR", UDim2.new(0,8,0,462), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(bpmDetectTitle)
makeLabel(pgFx, "Tap mode reads the rhythm of your Z/X/C/V presses. Idle mode reads the loaded idle clip's length.",
UDim2.new(0,8,0,484), UDim2.new(1,-16,0,28), Color3.fromRGB(130,130,150), Enum.TextXAlignment.Left, 10)
local detectedLbl = makeLabel(pgFx, "Detected: — BPM", UDim2.new(0,8,0,516), UDim2.new(1,-16,0,22), Color3.fromRGB(0,200,255), Enum.TextXAlignment.Left, 13)
function refreshBpmDetectorUI()
if detectedBPM then
detectedLbl.Text = string.format("Detected: %d BPM (from %d taps)", detectedBPM, #bpmDetectTaps)
end
end
makeLabel(pgFx, "BEATS/LOOP", UDim2.new(0,8,0,542), UDim2.new(0,80,0,26), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local beatsBox = makeBox(pgFx, UDim2.new(0,90,0,542), UDim2.new(0,50,0,26), "4", tostring(beatsPerIdleLoop))
beatsBox.FocusLost:Connect(function()
local n = tonumber(beatsBox.Text)
if n and n > 0 then beatsPerIdleLoop = n else beatsBox.Text = tostring(beatsPerIdleLoop) end
end)
local idleDetectBtn = makeBtn(pgFx, "📐 FROM IDLE LENGTH", UDim2.new(0,148,0,542), UDim2.new(0,150,0,26), Color3.fromRGB(70,120,255), nil, 10)
idleDetectBtn.MouseButton1Click:Connect(function()
local bpm = detectBpmFromIdleLength(beatsPerIdleLoop)
if bpm then
refreshBpmDetectorUI()
notify("Detected "..bpm.." BPM from idle length", "success")
else
notify("Load an idle animation first", "warn")
end
end)
local resetTapBtn = makeBtn(pgFx, "↺ RESET TAPS", UDim2.new(0,306,0,542), UDim2.new(0,116,0,26), Color3.fromRGB(170,35,35), nil, 10)
resetTapBtn.MouseButton1Click:Connect(function()
bpmDetectTaps = {}; detectedBPM = nil
detectedLbl.Text = "Detected: — BPM"
notify("Tap history cleared", "info")
end)
local applyDetectedBtn = makeBtn(pgFx, "✓ APPLY DETECTED BPM TO IDLE", UDim2.new(0,8,0,574), UDim2.new(1,-16,0,28), Color3.fromRGB(60,190,120), nil, 11)
applyDetectedBtn.MouseButton1Click:Connect(function()
if detectedBPM then
setIdleBPM(detectedBPM)
notify("Idle BPM set to "..detectedBPM, "success")
else
notify("No BPM detected yet — tap some keys or use idle length", "warn")
end
end)
-- ── Shared music player (no VC) ──
makeDivider(pgFx, 616, Color3.fromRGB(0,200,255))
local musicTitle = makeLabel(pgFx, "🎵 MUSIC PLAYER (NO VC)", UDim2.new(0,8,0,622), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(musicTitle)
makeLabel(pgFx, "Plays an uploaded audio asset for the whole server directly — no voice chat involved, so no mic compression/suppression.",
UDim2.new(0,8,0,644), UDim2.new(1,-16,0,30), Color3.fromRGB(140,140,160), Enum.TextXAlignment.Left, 10)
makeLabel(pgFx, "Needs the companion server script installed once in ServerScriptService (see notes).",
UDim2.new(0,8,0,676), UDim2.new(1,-16,0,18), Color3.fromRGB(130,130,150), Enum.TextXAlignment.Left, 9)
local musicIdBox = makeBox(pgFx, UDim2.new(0,8,0,698), UDim2.new(1,-16,0,28), "Audio asset ID (e.g. 1234567890)")
local musicPlayBtn = makeBtn(pgFx, "▶ PLAY FOR EVERYONE", UDim2.new(0,8,0,730), UDim2.new(0,220,0,30), Color3.fromRGB(60,190,120), nil, 11)
local musicStopBtn = makeBtn(pgFx, "■ STOP", UDim2.new(0,236,0,730), UDim2.new(0,160,0,30), Color3.fromRGB(190,50,50), nil, 11)
musicStatusLbl = makeLabel(pgFx, "● idle", UDim2.new(0,8,0,766), UDim2.new(1,-16,0,20), Color3.fromRGB(160,80,80), Enum.TextXAlignment.Left, 11)
musicPlayBtn.MouseButton1Click:Connect(function()
local id = musicIdBox.Text:gsub("%D","")
if id == "" then notify("Enter an audio asset ID first", "warn"); return end
playMusicTrack(id)
notify("Requested track "..id.." for the whole server", "info")
end)
musicStopBtn.MouseButton1Click:Connect(function()
stopMusicTrack()
notify("Stopped shared music", "info")
end)
-- ============================================================
-- TAB 6 : SETTINGS (legs / face / theme)
-- ============================================================
local pg6 = pages["⚙ SETTINGS"]
local legsTitle = makeLabel(pg6, "🦵 LEGS ON GROUND (Optional)",
UDim2.new(0,8,0,8), UDim2.new(1,-16,0,20),
Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(legsTitle)
makeDivider(pg6, 30, Color3.fromRGB(0,200,255))
makeLabel(pg6, "Prevents walking and jumping — character stays planted.",
UDim2.new(0,8,0,36), UDim2.new(1,-16,0,28),
Color3.fromRGB(140,140,160), Enum.TextXAlignment.Left, 10)
local legsBtn = makeBtn(pg6, "🔓 LEGS UNLOCKED (OFF)",
UDim2.new(0,8,0,68), UDim2.new(1,-16,0,32), Color3.fromRGB(35,35,55), nil, 11)
legsBtn.MouseButton1Click:Connect(function()
legsLocked = not legsLocked
applyLegsLock(legsLocked)
if legsLocked then
legsBtn.Text = "🔒 LEGS LOCKED (ON)"
legsBtn.BackgroundColor3 = THEMES[currentThemeName].accent
else
legsBtn.Text = "🔓 LEGS UNLOCKED (OFF)"
legsBtn.BackgroundColor3 = Color3.fromRGB(35,35,55)
end
notify(legsLocked and "Legs locked" or "Legs unlocked", "info")
end)
-- Dynamic face
makeDivider(pg6, 114, Color3.fromRGB(255,80,180))
local faceTitle = makeLabel(pg6, "😊 DYNAMIC FACE IDs (per arrow direction)",
UDim2.new(0,8,0,120), UDim2.new(1,-16,0,20),
Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(faceTitle)
makeLabel(pg6, "Only works if your character has a face decal on its head.",
UDim2.new(0,8,0,142), UDim2.new(1,-16,0,18),
Color3.fromRGB(130,130,150), Enum.TextXAlignment.Left, 10)
local faceOrder = { "LEFT", "DOWN", "UP", "RIGHT" }
for i, dir in ipairs(faceOrder) do
local y = 164 + (i-1)*38
local col = ARROW_COLORS[dir] and ARROW_COLORS[dir].hit or Color3.fromRGB(255,255,255)
makeLabel(pg6, dir, UDim2.new(0,8,0,y), UDim2.new(0,52,0,28), col, Enum.TextXAlignment.Left)
local fb = makeBox(pg6, UDim2.new(0,66,0,y), UDim2.new(1,-74,0,28), "Face decal ID for "..dir, faceIds[dir])
local capturedDir = dir
fb.FocusLost:Connect(function()
faceIds[capturedDir] = fb.Text:gsub("%D","")
end)
end
-- Theme selector
makeDivider(pg6, 320, Color3.fromRGB(0,200,255))
local themeTitle = makeLabel(pg6, "🎨 THEME", UDim2.new(0,8,0,326), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(themeTitle)
local themeNames = { "Pink", "Cyan", "Purple", "RGB" }
local themeSwatch = { Pink = Color3.fromRGB(255,80,180), Cyan = Color3.fromRGB(0,200,255),
Purple = Color3.fromRGB(165,85,255), RGB = Color3.fromRGB(255,255,255) }
for i, tn in ipairs(themeNames) do
local tx = 8 + (i-1) * 104
local tbtn = makeBtn(pg6, tn, UDim2.new(0, tx, 0, 356), UDim2.new(0, 96, 0, 32), themeSwatch[tn], Color3.fromRGB(20,20,20), 11)
tbtn.MouseButton1Click:Connect(function() setTheme(tn) end)
end
-- ============================================================
-- RP TUG-OF-WAR UI
-- ============================================================
makeDivider(pg6, 400, Color3.fromRGB(0,200,255))
local rpTitle = makeLabel(pg6, "⚔ RP TUG-OF-WAR (PROXIMITY)", UDim2.new(0,8,0,406), UDim2.new(1,-16,0,20), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Left, 12)
regText(rpTitle)
makeLabel(pg6, "Moves you toward the target on every note press.", UDim2.new(0,8,0,428), UDim2.new(1,-16,0,18), Color3.fromRGB(130,130,150), Enum.TextXAlignment.Left, 10)
-- Toggle Button
local rpBtn = makeBtn(pg6, "📴 RP MODE OFF", UDim2.new(0,8,0,450), UDim2.new(0,160,0,32), Color3.fromRGB(35,35,55), nil, 11)
rpBtn.MouseButton1Click:Connect(function()
rpModeEnabled = not rpModeEnabled
if rpModeEnabled then
rpBtn.Text = "⚔ RP MODE ON"
rpBtn.BackgroundColor3 = THEMES[currentThemeName].accent
else
rpBtn.Text = "📴 RP MODE OFF"
rpBtn.BackgroundColor3 = Color3.fromRGB(35,35,55)
end
end)
-- Player Search Box
local targetBox = makeBox(pg6, UDim2.new(0,176,0,450), UDim2.new(1,-184,0,32), "Target Player Name...")
targetBox.FocusLost:Connect(function()
setTargetPlayer(targetBox.Text)
end)
-- Speed Slider
makeLabel(pg6, "SPEED", UDim2.new(0,8,0,490), UDim2.new(0,40,0,22), Color3.fromRGB(160,160,160), Enum.TextXAlignment.Left, 10)
local rpValLbl = makeLabel(pg6, string.format("%.1f studs", rpMoveStep), UDim2.new(0,300,0,490), UDim2.new(0,94,0,22), Color3.fromRGB(255,80,180), Enum.TextXAlignment.Right, 11)
regText(rpValLbl)
makeSlider(pg6, UDim2.new(0,50,0,494), UDim2.new(0,250,0,14), 0.5, 5, rpMoveStep, function(v)
rpMoveStep = v
rpValLbl.Text = string.format("%.1f studs", v)
end)
-- Hide / show toggle
toggleBtn.MouseButton1Click:Connect(function()
guiVisible = not guiVisible
contentArea.Visible = guiVisible
tabBar.Visible = guiVisible
toggleBtn.Text = guiVisible and "HIDE" or "SHOW"
end)
startVisualizerLoops()
notify("FNF Injector v6.1 loaded", "success")
return sg
end
-- ============================================================
-- LAUNCH
-- ============================================================
task.spawn(setupMusicRemote)
buildArrowHud()
buildGUI()
--[[
╔══════════════════════════════════════════════════════╗
║ FNF CINEMATIC STANDOFF INTRO — v1.0 ║
║ Back-to-back walk-off → turn → local VS split-cam ║
╚══════════════════════════════════════════════════════╝
HOW IT WORKS:
• Run this SAME script on both accounts (yours + your alt).
• Give each one a "role": "A" or "B", and the other account's
username. Role decides which spot / which walk direction.
• Movement (walking to spots, turning to face each other) is
done by tweening YOUR OWN HumanoidRootPart CFrame. Since you
have network ownership of your own character, this actually
replicates to everyone else in the server — they see two
players walk to their marks and square up, nothing more.
• The VS split-screen face-cam overlay is a local ScreenGui —
built from cloned heads in a ViewportFrame, never touches
the real character, so only the client running this sees it.
• True frame-perfect sync between two separate accounts needs
a server RemoteEvent (one is auto-detected if present, see
SYNC section). Without one, it falls back to a 3-2-1 on-screen
countdown so you just start both scripts and count together.
]]
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
local camera = workspace.CurrentCamera
-- ============================================================
-- CONFIG — tweak freely
-- ============================================================
local Config = {
TriggerKey = Enum.KeyCode.B, -- press this to arm/start
AltUsername = "mentransmigrasilo",-- who the other rig is
-- world anchor: standoff happens relative to wherever LocalPlayer
-- is standing the moment you press the trigger key
SpotDistance = 14, -- how far apart the final marks are
CenterGap = 3, -- how close together they start, back to back
WalkDuration = 2.4,
TurnDuration = 0.55,
HoldBeforeSplit = 0.35,
SplitCamDuration = 2.6, -- how long the VS face-cam stays up
CountdownEnabled = true, -- 3-2-1 fallback sync
WalkAnimId = "180426354", -- placeholder walk-forward loop
IdleStanceAnimId = "507766388", -- placeholder FNF-ready idle stance
-- role placement — "A" ends up on the right (Boyfriend side),
-- "B" ends up on the left (Opponent side), classic FNF stage layout
Role = "A", -- "A" or "B", set per-account
}
-- ============================================================
-- OPTIONAL SERVER SYNC (auto-detected, not required)
-- ============================================================
-- If a companion server script drops a "StandoffSyncRemote" RemoteEvent
-- into ReplicatedStorage, we use it to get a synced go-time. If it's not
-- there, we just fall back to the local 3-2-1 countdown.
local syncRemote = nil
task.spawn(function()
pcall(function()
syncRemote = ReplicatedStorage:WaitForChild("StandoffSyncRemote", 3)
end)
end)
-- ============================================================
-- STATE
-- ============================================================
local standoffActive = false
local rigConns = {}
local function cleanupConns()
for _, c in ipairs(rigConns) do pcall(function() c:Disconnect() end) end
rigConns = {}
end
-- ============================================================
-- CHARACTER / ANIMATOR HELPERS
-- ============================================================
local function getHumanoidBits(char)
if not char then return nil end
local hum = char:FindFirstChildOfClass("Humanoid")
local root = char:FindFirstChild("HumanoidRootPart")
if not hum or not root then return nil end
local animator = hum:FindFirstChildOfClass("Animator") or Instance.new("Animator", hum)
return { hum = hum, root = root, animator = animator }
end
local function loadAnim(animator, id, looped, priority)
local ok, track = pcall(function()
local anim = Instance.new("Animation")
anim.AnimationId = "rbxassetid://"..id
local t = animator:LoadAnimation(anim)
t.Looped = looped
t.Priority = priority or Enum.AnimationPriority.Action
return t
end)
if ok then return track end
return nil
end
-- Smoothly tween a HumanoidRootPart's CFrame. Root gets anchored for the
-- duration so physics doesn't fight the tween, then restored after.
local function tweenRoot(root, targetCFrame, duration, style, direction)
local wasAnchored = root.Anchored
root.Anchored = true
local tw = TweenService:Create(root, TweenInfo.new(duration, style or Enum.EasingStyle.Sine, direction or Enum.EasingDirection.InOut), {
CFrame = targetCFrame
})
tw:Play()
tw.Completed:Wait()
root.Anchored = wasAnchored
return true
end
-- ============================================================
-- ON-SCREEN 3-2-1 SYNC COUNTDOWN (local only, helps line up two clients)
-- ============================================================
local function showCountdown(cb)
local sg = Instance.new("ScreenGui")
sg.Name = "StandoffCountdown"; sg.ResetOnSpawn = false; sg.Parent = PlayerGui
local lbl = Instance.new("TextLabel")
lbl.Size = UDim2.new(0,300,0,150)
lbl.AnchorPoint = Vector2.new(0.5,0.5)
lbl.Position = UDim2.new(0.5,0,0.5,0)
lbl.BackgroundTransparency = 1
lbl.Font = Enum.Font.GothamBlack
lbl.TextSize = 90
lbl.TextColor3 = Color3.fromRGB(255,80,180)
lbl.TextStrokeTransparency = 0
lbl.TextStrokeColor3 = Color3.new(0,0,0)
lbl.Parent = sg
task.spawn(function()
for _, n in ipairs({"3","2","1","GO"}) do
lbl.Text = n
lbl.Size = UDim2.new(0,420,0,210)
TweenService:Create(lbl, TweenInfo.new(0.5, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {
Size = UDim2.new(0,300,0,150)
}):Play()
task.wait(0.7)
end
sg:Destroy()
if cb then cb() end
end)
end
-- ============================================================
-- CINEMATIC CAMERA (local only)
-- ============================================================
local savedCamType, savedCamCFrame
local function lockCinematicCamera(startCFrame)
savedCamType = camera.CameraType
savedCamCFrame = camera.CFrame
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = startCFrame
end
local function restoreCamera()
camera.CameraType = savedCamType or Enum.CameraType.Custom
end
-- Wide establishing dolly: pulls back slowly as both walk to their marks
local function dollyCamera(fromCFrame, toCFrame, duration)
local tw = TweenService:Create(camera, TweenInfo.new(duration, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {
CFrame = toCFrame
})
camera.CFrame = fromCFrame
tw:Play()
return tw
end
-- Subtle handheld shake, used during the VS face-cam hold
local shakeConn = nil
local function startCameraShake(intensity)
if shakeConn then shakeConn:Disconnect() end
shakeConn = RunService.RenderStepped:Connect(function()
if camera.CameraType == Enum.CameraType.Scriptable then
local ox = (math.random() - 0.5) * intensity
local oy = (math.random() - 0.5) * intensity
camera.CFrame = camera.CFrame * CFrame.new(ox, oy, 0)
end
end)
end
local function stopCameraShake()
if shakeConn then shakeConn:Disconnect(); shakeConn = nil end
end
-- ============================================================
-- VS FACE-CAM SPLIT SCREEN (local only — WorldModel clone trick,
-- same pattern as a standard viewport character preview)
-- ============================================================
local function buildFaceViewport(char, parent, position, size)
local vp = Instance.new("ViewportFrame")
vp.Size = size; vp.Position = position
vp.BackgroundColor3 = Color3.fromRGB(6,6,10)
vp.Ambient = Color3.fromRGB(160,160,170)
vp.LightColor = Color3.fromRGB(255,255,255)
vp.LightDirection = Vector3.new(-0.4,-0.6,-0.6)
vp.Parent = parent
local world = Instance.new("WorldModel")
world.Parent = vp
local wasArchivable = char.Archivable
if not wasArchivable then char.Archivable = true end
local ok, clone = pcall(function() return char:Clone() end)
if not wasArchivable then char.Archivable = wasArchivable end
if not ok or not clone then return vp end
for _, d in ipairs(clone:GetDescendants()) do
if d:IsA("Script") or d:IsA("LocalScript") then d:Destroy() end
end
clone.Parent = world
local head = clone:FindFirstChild("Head")
local hrp = clone:FindFirstChild("HumanoidRootPart") or clone.PrimaryPart
if hrp then hrp.Anchored = true end
local cam = Instance.new("Camera")
if head then
cam.CFrame = CFrame.new(head.Position + Vector3.new(0,0,2.2), head.Position)
else
cam.CFrame = CFrame.new(Vector3.new(0,3,4), Vector3.new(0,3,0))
end
cam.FieldOfView = 45
cam.Parent = vp
vp.CurrentCamera = cam
return vp
end
local function playVSFaceCam(myChar, altChar, holdTime)
local sg = Instance.new("ScreenGui")
sg.Name = "StandoffVS"; sg.ResetOnSpawn = false; sg.IgnoreGuiInset = true
sg.Parent = PlayerGui
local root = Instance.new("Frame")
root.Size = UDim2.new(1,0,1,0); root.BackgroundColor3 = Color3.new(0,0,0)
root.BackgroundTransparency = 1; root.ClipsDescendants = true; root.Parent = sg
-- LEFT half (opponent / role B viewport by convention)
local leftHalf = Instance.new("Frame")
leftHalf.Size = UDim2.new(0.5,0,1,0); leftHalf.Position = UDim2.new(-0.5,0,0,0)
leftHalf.BackgroundTransparency = 1; leftHalf.ClipsDescendants = true; leftHalf.Parent = root
-- RIGHT half (player / role A viewport by convention)
local rightHalf = Instance.new("Frame")
rightHalf.Size = UDim2.new(0.5,0,1,0); rightHalf.Position = UDim2.new(1,0,0,0)
rightHalf.BackgroundTransparency = 1; rightHalf.ClipsDescendants = true; rightHalf.Parent = root
local isRoleA = (Config.Role == "A")
local myHalf, altHalf = (isRoleA and rightHalf or leftHalf), (isRoleA and leftHalf or rightHalf)
buildFaceViewport(altChar, altHalf, UDim2.new(0,0,0,0), UDim2.new(1,0,1,0))
buildFaceViewport(myChar, myHalf, UDim2.new(0,0,0,0), UDim2.new(1,0,1,0))
-- diagonal seam divider
local seam = Instance.new("Frame")
seam.Size = UDim2.new(0,10,2.4,0)
seam.AnchorPoint = Vector2.new(0.5,0.5)
seam.Position = UDim2.new(0.5,0,0.5,0)
seam.Rotation = 18
seam.BackgroundColor3 = Color3.fromRGB(255,80,180)
seam.BorderSizePixel = 0; seam.ZIndex = 5; seam.Parent = root
-- VS badge, pops in with a punchy scale tween
local vsLbl = Instance.new("TextLabel")
vsLbl.Size = UDim2.new(0,140,0,70)
vsLbl.AnchorPoint = Vector2.new(0.5,0.5)
vsLbl.Position = UDim2.new(0.5,0,0.5,0)
vsLbl.BackgroundTransparency = 1
vsLbl.Text = "VS"; vsLbl.Font = Enum.Font.GothamBlack; vsLbl.TextSize = 0
vsLbl.TextColor3 = Color3.fromRGB(255,255,255)
vsLbl.TextStrokeTransparency = 0; vsLbl.TextStrokeColor3 = Color3.fromRGB(255,80,180)
vsLbl.ZIndex = 6; vsLbl.Parent = root
-- slide both halves in
TweenService:Create(leftHalf, TweenInfo.new(0.45, Enum.EasingStyle.Back, Enum.EasingDirection.Out), { Position = UDim2.new(0,0,0,0) }):Play()
local rightTw = TweenService:Create(rightHalf, TweenInfo.new(0.45, Enum.EasingStyle.Back, Enum.EasingDirection.Out), { Position = UDim2.new(0.5,0,0,0) })
rightTw:Play()
task.wait(0.25)
TweenService:Create(vsLbl, TweenInfo.new(0.35, Enum.EasingStyle.Back, Enum.EasingDirection.Out), { TextSize = 64 }):Play()
startCameraShake(0.02)
task.wait(holdTime)
stopCameraShake()
-- fade out
local fadeTime = 0.4
TweenService:Create(leftHalf, TweenInfo.new(fadeTime, Enum.EasingStyle.Quad), { Position = UDim2.new(-0.5,0,0,0) }):Play()
TweenService:Create(rightHalf, TweenInfo.new(fadeTime, Enum.EasingStyle.Quad), { Position = UDim2.new(1,0,0,0) }):Play()
TweenService:Create(vsLbl, TweenInfo.new(fadeTime, Enum.EasingStyle.Quad), { TextSize = 0 }):Play()
task.wait(fadeTime + 0.1)
sg:Destroy()
end
-- ============================================================
-- MAIN SEQUENCE
-- ============================================================
local function runStandoff()
if standoffActive then return end
standoffActive = true
local altPlayer = Players:FindFirstChild(Config.AltUsername)
if not altPlayer or not altPlayer.Character then
warn("[Standoff] Alt player not found or has no character.")
standoffActive = false
return
end
local myChar = LocalPlayer.Character
local altChar = altPlayer.Character
local myBits = getHumanoidBits(myChar)
local altBits = getHumanoidBits(altChar)
if not myBits or not altBits then
warn("[Standoff] Missing Humanoid/HumanoidRootPart on one of the rigs.")
standoffActive = false
return
end
local function begin()
-- anchor point = my current position, facing my current LookVector
local originCFrame = CFrame.new(myBits.root.Position, myBits.root.Position + myBits.root.CFrame.LookVector)
local isRoleA = (Config.Role == "A")
-- back-to-back start: both on the same line, facing opposite ways,
-- separated only by CenterGap
local halfGap = Config.CenterGap / 2
local myStart = originCFrame * CFrame.new(isRoleA and halfGap or -halfGap, 0, 0)
* (isRoleA and CFrame.Angles(0, math.rad(90), 0) or CFrame.Angles(0, math.rad(-90), 0))
tweenRoot(myBits.root, myStart, 0.01, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
-- cinematic camera: wide shot centered on both, looking down the line
local camStart = originCFrame * CFrame.new(0, 5, 10)
local camEnd = originCFrame * CFrame.new(0, 4, Config.SpotDistance * 0.9)
lockCinematicCamera(camStart)
local camTw = dollyCamera(camStart, camEnd, Config.WalkDuration + Config.TurnDuration)
-- walk animation while marching to spot
local walkTrack = loadAnim(myBits.animator, Config.WalkAnimId, true, Enum.AnimationPriority.Movement)
if walkTrack then walkTrack:Play(0.15) end
-- walk out to final mark, still facing away from each other
local mySpot = originCFrame * CFrame.new(isRoleA and Config.SpotDistance/2 or -Config.SpotDistance/2, 0, 0)
* (isRoleA and CFrame.Angles(0, math.rad(90), 0) or CFrame.Angles(0, math.rad(-90), 0))
tweenRoot(myBits.root, mySpot, Config.WalkDuration, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
if walkTrack then walkTrack:Stop(0.15) end
-- turn to face each other — role A faces -X (toward B), role B faces +X (toward A)
local turnCFrame = mySpot * (isRoleA and CFrame.Angles(0, math.rad(-90), 0) or CFrame.Angles(0, math.rad(90), 0))
-- correct: rebuild from position only, then rotate to actually look at the other spot
local lookTarget = originCFrame.Position + Vector3.new(isRoleA and -1 or 1, 0, 0)
turnCFrame = CFrame.new(mySpot.Position, Vector3.new(lookTarget.X, mySpot.Position.Y, mySpot.Position.Z))
tweenRoot(myBits.root, turnCFrame, Config.TurnDuration, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
-- FNF-ready idle stance
local idleTrack = loadAnim(myBits.animator, Config.IdleStanceAnimId, true, Enum.AnimationPriority.Idle)
if idleTrack then idleTrack:Play(0.2) end
task.wait(Config.HoldBeforeSplit)
-- local-only face-cam VS split
playVSFaceCam(myChar, altChar, Config.SplitCamDuration)
restoreCamera()
standoffActive = false
end
if Config.CountdownEnabled and not syncRemote then
showCountdown(begin)
elseif syncRemote then
-- server-synced start: fire our readiness, wait for GO from server
syncRemote:FireServer("ready")
local conn
conn = syncRemote.OnClientEvent:Connect(function(cmd)
if cmd == "go" then
conn:Disconnect()
task.spawn(begin)
end
end)
table.insert(rigConns, conn)
else
task.spawn(begin)
end
end
-- ============================================================
-- TRIGGER
-- ============================================================
table.insert(rigConns, UserInputService.InputBegan:Connect(function(input, gp)
if gp then return end
if input.KeyCode == Config.TriggerKey then
runStandoff()
end
end))
print("[Standoff] Loaded. Role: "..Config.Role.." — press "..Config.TriggerKey.Name.." to start, boss man.")
you can rap battle with your friends

Universal