Загрузка данных
-- RbxMotion Studio v0.1
-- Полностью заменяет предыдущий LocalScript
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local gui = script.Parent
local Main = gui:WaitForChild("Main")
local TopBar = gui:WaitForChild("TopBar")
local ViewportPanel = gui:WaitForChild("Viewport")
local Explorer = gui:WaitForChild("Explorer")
local Inspector = gui:WaitForChild("Inspector")
local Timeline = gui:WaitForChild("Timeline")
--==================================================
-- НАСТРОЙКИ
--==================================================
local COLORS = {
bg = Color3.fromRGB(14, 15, 18),
panel = Color3.fromRGB(21, 23, 28),
panel2 = Color3.fromRGB(27, 30, 36),
panel3 = Color3.fromRGB(34, 37, 44),
line = Color3.fromRGB(52, 56, 65),
text = Color3.fromRGB(230, 233, 240),
muted = Color3.fromRGB(145, 150, 162),
accent = Color3.fromRGB(78, 132, 255),
accentDark = Color3.fromRGB(48, 87, 170),
selected = Color3.fromRGB(48, 73, 120),
red = Color3.fromRGB(220, 80, 80),
}
local FPS = 30
local currentFrame = 0
local totalFrames = 180
local playing = false
local selectedPart = nil
local keyframes = {}
--==================================================
-- БАЗОВЫЕ НАСТРОЙКИ GUI
--==================================================
Main.Size = UDim2.fromScale(1, 1)
Main.Position = UDim2.fromScale(0, 0)
Main.BackgroundColor3 = COLORS.bg
Main.BorderSizePixel = 0
TopBar.Size = UDim2.new(1, 0, 0, 48)
TopBar.Position = UDim2.new(0, 0, 0, 0)
TopBar.BackgroundColor3 = COLORS.panel
TopBar.BorderSizePixel = 0
ViewportPanel.Position = UDim2.new(0, 230, 0, 48)
ViewportPanel.Size = UDim2.new(1, -510, 1, -185)
ViewportPanel.BackgroundColor3 = Color3.fromRGB(9, 10, 13)
ViewportPanel.BorderSizePixel = 0
Explorer.Position = UDim2.new(0, 0, 0, 48)
Explorer.Size = UDim2.new(0, 230, 1, -185)
Explorer.BackgroundColor3 = COLORS.panel
Explorer.BorderSizePixel = 0
Inspector.Position = UDim2.new(1, -280, 0, 48)
Inspector.Size = UDim2.new(0, 280, 1, -185)
Inspector.BackgroundColor3 = COLORS.panel
Inspector.BorderSizePixel = 0
Timeline.Position = UDim2.new(0, 0, 1, -137)
Timeline.Size = UDim2.new(1, 0, 0, 137)
Timeline.BackgroundColor3 = COLORS.panel
Timeline.BorderSizePixel = 0
--==================================================
-- УТИЛИТЫ GUI
--==================================================
local function clear(container)
for _, child in ipairs(container:GetChildren()) do
if not child:IsA("UIListLayout") then
child:Destroy()
end
end
end
local function corner(object, radius)
local c = Instance.new("UICorner")
c.CornerRadius = UDim.new(0, radius or 5)
c.Parent = object
return c
end
local function stroke(object, color, thickness)
local s = Instance.new("UIStroke")
s.Color = color or COLORS.line
s.Thickness = thickness or 1
s.Parent = object
return s
end
local function text(parent, value, position, size, fontSize, color)
local label = Instance.new("TextLabel")
label.Parent = parent
label.Text = value
label.Position = position
label.Size = size
label.BackgroundTransparency = 1
label.TextColor3 = color or COLORS.text
label.Font = Enum.Font.Gotham
label.TextSize = fontSize or 13
label.TextXAlignment = Enum.TextXAlignment.Left
label.TextYAlignment = Enum.TextYAlignment.Center
return label
end
local function button(parent, value, position, size)
local b = Instance.new("TextButton")
b.Parent = parent
b.Text = value
b.Position = position
b.Size = size
b.BackgroundColor3 = COLORS.panel2
b.TextColor3 = COLORS.text
b.Font = Enum.Font.Gotham
b.TextSize = 12
b.AutoButtonColor = false
b.BorderSizePixel = 0
corner(b, 5)
b.MouseEnter:Connect(function()
b.BackgroundColor3 = COLORS.panel3
end)
b.MouseLeave:Connect(function()
b.BackgroundColor3 = COLORS.panel2
end)
return b
end
local function divider(parent, position, size)
local d = Instance.new("Frame")
d.Parent = parent
d.Position = position
d.Size = size
d.BackgroundColor3 = COLORS.line
d.BorderSizePixel = 0
return d
end
--==================================================
-- TOP BAR
--==================================================
clear(TopBar)
text(
TopBar,
"RBXMOTION",
UDim2.new(0, 18, 0, 0),
UDim2.new(0, 130, 1, 0),
17
)
local menuX = 155
for _, item in ipairs({
"FILE",
"EDIT",
"VIEW",
"ANIMATION",
"LIGHTING",
"CAMERA"
}) do
local b = button(
TopBar,
item,
UDim2.new(0, menuX, 0, 8),
UDim2.new(0, 82, 0, 32)
)
menuX += 84
if item == "LIGHTING" then
b.MouseButton1Click:Connect(function()
print("Lighting panel")
end)
end
end
local settings = button(
TopBar,
"⚙",
UDim2.new(1, -48, 0, 8),
UDim2.new(0, 34, 0, 32)
)
--==================================================
-- VIEWPORT
--==================================================
clear(ViewportPanel)
local Preview = Instance.new("ViewportFrame")
Preview.Name = "Preview"
Preview.Parent = ViewportPanel
Preview.Size = UDim2.fromScale(1, 1)
Preview.BackgroundColor3 = Color3.fromRGB(8, 9, 12)
Preview.BorderSizePixel = 0
Preview.Ambient = Color3.fromRGB(150, 150, 150)
Preview.LightColor = Color3.fromRGB(255, 255, 255)
Preview.LightDirection = Vector3.new(-1, -1, -1)
local world = Instance.new("WorldModel")
world.Parent = Preview
local camera = Instance.new("Camera")
camera.Parent = Preview
Preview.CurrentCamera = camera
local cameraDistance = 13
local cameraYaw = 0
local cameraPitch = 8
local function updateCamera()
local target = Vector3.new(0, 3.2, 0)
local radiansYaw = math.rad(cameraYaw)
local radiansPitch = math.rad(cameraPitch)
local offset = Vector3.new(
math.sin(radiansYaw) * math.cos(radiansPitch),
math.sin(radiansPitch),
math.cos(radiansYaw) * math.cos(radiansPitch)
) * cameraDistance
camera.CFrame = CFrame.lookAt(target + offset, target)
end
updateCamera()
--==================================================
-- ТЕСТОВЫЙ ПЕРСОНАЖ
--==================================================
local character = Instance.new("Model")
character.Name = "Character"
character.Parent = world
local parts = {}
local function createPart(name, size, position)
local p = Instance.new("Part")
p.Name = name
p.Size = size
p.Position = position
p.Anchored = true
p.Material = Enum.Material.SmoothPlastic
p.Color = Color3.fromRGB(150, 155, 165)
p.Parent = character
parts[name] = p
return p
end
createPart("Torso", Vector3.new(2.2, 3, 1.2), Vector3.new(0, 3.2, 0))
createPart("Head", Vector3.new(2, 2, 2), Vector3.new(0, 5.7, 0))
createPart("Arm.L", Vector3.new(0.9, 3, 0.9), Vector3.new(-1.55, 3.2, 0))
createPart("Arm.R", Vector3.new(0.9, 3, 0.9), Vector3.new(1.55, 3.2, 0))
createPart("Leg.L", Vector3.new(1, 3, 1), Vector3.new(-0.55, 0.25, 0))
createPart("Leg.R", Vector3.new(1, 3, 1), Vector3.new(0.55, 0.25, 0))
for _, p in pairs(parts) do
local selection = Instance.new("SelectionBox")
selection.Adornee = p
selection.LineThickness = 0.035
selection.Color3 = COLORS.accent
selection.Transparency = 1
selection.Parent = p
p:SetAttribute("OriginalColor", p.Color)
p.MouseEnter:Connect(function()
if selectedPart ~= p then
p.Color = Color3.fromRGB(180, 185, 200)
end
end)
p.MouseLeave:Connect(function()
if selectedPart ~= p then
p.Color = p:GetAttribute("OriginalColor")
end
end)
end
--==================================================
-- EXPLORER
--==================================================
clear(Explorer)
text(
Explorer,
"SCENE",
UDim2.new(0, 15, 0, 10),
UDim2.new(1, -30, 0, 28),
12,
COLORS.muted
)
local explorerItems = {
{"▾ Scene", 42, nil},
{" ◇ Camera", 70, nil},
{" ◇ Lighting", 98, nil},
{" ▾ Character", 126, nil},
{" Head", 154, "Head"},
{" Torso", 182, "Torso"},
{" Arm.L", 210, "Arm.L"},
{" Arm.R", 238, "Arm.R"},
{" Leg.L", 266, "Leg.L"},
{" Leg.R", 294, "Leg.R"},
}
for _, item in ipairs(explorerItems) do
local name = item[1]
local y = item[2]
local partName = item[3]
local b = button(
Explorer,
name,
UDim2.new(0, 8, 0, y),
UDim2.new(1, -16, 0, 25)
)
b.TextXAlignment = Enum.TextXAlignment.Left
if partName then
b.MouseButton1Click:Connect(function()
local p = parts[partName]
if p then
if selectedPart then
selectedPart.Color =
selectedPart:GetAttribute("OriginalColor")
local oldSelection = selectedPart:FindFirstChildOfClass("SelectionBox")
if oldSelection then
oldSelection.Transparency = 1
end
end
selectedPart = p
selectedPart.Color = COLORS.accent
local selection = p:FindFirstChildOfClass("SelectionBox")
if selection then
selection.Transparency = 0
end
print("Selected:", partName)
end
end)
end
end
--==================================================
-- INSPECTOR
--==================================================
clear(Inspector)
text(
Inspector,
"INSPECTOR",
UDim2.new(0, 15, 0, 10),
UDim2.new(1, -30, 0, 28),
12,
COLORS.muted
)
text(
Inspector,
"Transform",
UDim2.new(0, 15, 0, 48),
UDim2.new(1, -30, 0, 28),
15
)
local selectedName = text(
Inspector,
"Nothing selected",
UDim2.new(0, 15, 0, 80),
UDim2.new(1, -30, 0, 25),
12,
COLORS.muted
)
local function propertyRow(name, y)
local label = text(
Inspector,
name,
UDim2.new(0, 15, 0, y),
UDim2.new(0, 90, 0, 26),
12,
COLORS.muted
)
local value = Instance.new("TextBox")
value.Parent = Inspector
value.Position = UDim2.new(0, 105, 0, y)
value.Size = UDim2.new(1, -120, 0, 26)
value.BackgroundColor3 = COLORS.panel2
value.TextColor3 = COLORS.text
value.Font = Enum.Font.Gotham
value.TextSize = 11
value.Text = "0"
value.ClearTextOnFocus = false
value.BorderSizePixel = 0
corner(value, 4)
return value
end
local posX = propertyRow("Position X", 120)
local posY = propertyRow("Position Y", 153)
local posZ = propertyRow("Position Z", 186)
local rotX = propertyRow("Rotation X", 230)
local rotY = propertyRow("Rotation Y", 263)
local rotZ = propertyRow("Rotation Z", 296)
local keyButton = button(
Inspector,
"◆ CREATE KEYFRAME",
UDim2.new(0, 15, 0, 340),
UDim2.new(1, -30, 0, 35)
)
keyButton.BackgroundColor3 = COLORS.accent
local function updateInspector()
if not selectedPart then
selectedName.Text = "Nothing selected"
return
end
selectedName.Text = selectedPart.Name
local p = selectedPart.Position
local r = selectedPart.Orientation
posX.Text = string.format("%.2f", p.X)
posY.Text = string.format("%.2f", p.Y)
posZ.Text = string.format("%.2f", p.Z)
rotX.Text = string.format("%.1f", r.X)
rotY.Text = string.format("%.1f", r.Y)
rotZ.Text = string.format("%.1f", r.Z)
end
local function applyInspector()
if not selectedPart then
return
end
local x = tonumber(posX.Text) or selectedPart.Position.X
local y = tonumber(posY.Text) or selectedPart.Position.Y
local z = tonumber(posZ.Text) or selectedPart.Position.Z
local rx = tonumber(rotX.Text) or selectedPart.Orientation.X
local ry = tonumber(rotY.Text) or selectedPart.Orientation.Y
local rz = tonumber(rotZ.Text) or selectedPart.Orientation.Z
selectedPart.CFrame =
CFrame.new(x, y, z) *
CFrame.Angles(
math.rad(rx),
math.rad(ry),
math.rad(rz)
)
end
for _, box in ipairs({
posX, posY, posZ,
rotX, rotY, rotZ
}) do
box.FocusLost:Connect(applyInspector)
end
--==================================================
-- TIMELINE
--==================================================
clear(Timeline)
text(
Timeline,
"TIMELINE",
UDim2.new(0, 15, 0, 8),
UDim2.new(0, 100, 0, 24),
12,
COLORS.muted
)
local playButton = button(
Timeline,
"▶",
UDim2.new(0, 120, 0, 5),
UDim2.new(0, 34, 0, 30)
)
local stopButton = button(
Timeline,
"■",
UDim2.new(0, 158, 0, 5),
UDim2.new(0, 34, 0, 30)
)
local frameText = text(
Timeline,
"FRAME 0",
UDim2.new(0, 205, 0, 5),
UDim2.new(0, 100, 0, 30),
12
)
local fpsText = text(
Timeline,
"30 FPS",
UDim2.new(1, -80, 0, 5),
UDim2.new(0, 65, 0, 30),
12,
COLORS.muted
)
local timelineArea = Instance.new("Frame")
timelineArea.Parent = Timeline
timelineArea.Position = UDim2.new(0, 90, 0, 40)
timelineArea.Size = UDim2.new(1, -105, 1, -45)
timelineArea.BackgroundColor3 = COLORS.bg
timelineArea.BorderSizePixel = 0
-- TRACK NAMES
local trackNames = {
"HEAD",
"BODY",
"ARM.L",
"ARM.R",
"LEG.L",
"LEG.R"
}
for i, name in ipairs(trackNames) do
local y = (i - 1) * 18
text(
Timeline,
name,
UDim2.new(0, 15, 0, 43 + y),
UDim2.new(0, 70, 0, 18),
10,
COLORS.muted
)
divider(
Timeline,
UDim2.new(0, 90, 0, 51 + y),
UDim2.new(1, -105, 0, 1)
)
end
-- FRAME MARKERS
local function createKeyVisual(frame, track)
local x = frame / totalFrames
local diamond = Instance.new("TextButton")
diamond.Parent = Timeline
diamond.Text = "◆"
diamond.TextSize = 11
diamond.TextColor3 = COLORS.accent
diamond.BackgroundTransparency = 1
diamond.Position = UDim2.new(
0.06 + x * 0.91,
0,
0,
43 + track * 18
)
diamond.Size = UDim2.new(0, 18, 0, 18)
return diamond
end
local playhead = Instance.new("Frame")
playhead.Parent = Timeline
playhead.Size = UDim2.new(0, 2, 1, -40)
playhead.Position = UDim2.new(0.06, 0, 0, 40)
playhead.BackgroundColor3 = COLORS.accent
playhead.BorderSizePixel = 0
playhead.ZIndex = 10
local function updatePlayhead()
local alpha = currentFrame / totalFrames
playhead.Position = UDim2.new(
0.06 + alpha * 0.91,
0,
0,
40
)
frameText.Text = "FRAME " .. currentFrame
end
--==================================================
-- KEYFRAME SYSTEM
--==================================================
local function saveKeyframe()
if not selectedPart then
return
end
keyframes[selectedPart.Name] = keyframes[selectedPart.Name] or {}
keyframes[selectedPart.Name][currentFrame] = {
cframe = selectedPart.CFrame
}
local track = 0
for i, name in ipairs(trackNames) do
if name == selectedPart.Name then
track = i - 1
break
end
end
createKeyVisual(currentFrame, track)
print(
"Keyframe:",
selectedPart.Name,
"Frame:",
currentFrame
)
end
keyButton.MouseButton1Click:Connect(saveKeyframe)
--==================================================
-- PLAYBACK
--==================================================
playButton.MouseButton1Click:Connect(function()
playing = not playing
if playing then
playButton.Text = "Ⅱ"
else
playButton.Text = "▶"
end
end)
stopButton.MouseButton1Click:Connect(function()
playing = false
currentFrame = 0
playButton.Text = "▶"
updatePlayhead()
end)
RunService.RenderStepped:Connect(function(dt)
if playing then
currentFrame += math.floor(dt * FPS)
if currentFrame >= totalFrames then
currentFrame = 0
end
updatePlayhead()
end
end)
--==================================================
-- DRAGGING TIMELINE
--==================================================
timelineArea.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
local x = input.Position.X - timelineArea.AbsolutePosition.X
local width = timelineArea.AbsoluteSize.X
local alpha = math.clamp(x / width, 0, 1)
currentFrame = math.floor(alpha * totalFrames)
updatePlayhead()
end
end)
--==================================================
-- CAMERA CONTROL
--==================================================
local draggingCamera = false
local lastMouse
Preview.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
draggingCamera = true
lastMouse = input.Position
end
end)
Preview.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton2 then
draggingCamera = false
end
end)
UserInputService.InputChanged:Connect(function(input)
if not draggingCamera then
return
end
if input.UserInputType == Enum.UserInputType.MouseMovement then
local delta = input.Position - lastMouse
cameraYaw -= delta.X * 0.35
cameraPitch = math.clamp(
cameraPitch + delta.Y * 0.25,
-70,
70
)
lastMouse = input.Position
updateCamera()
end
end)
Preview.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseWheel then
cameraDistance = math.clamp(
cameraDistance - input.Position.Z,
5,
30
)
updateCamera()
end
end)
--==================================================
-- ВЫБОР ЧАСТЕЙ В VIEWPORT
--==================================================
for name, part in pairs(parts) do
local click = Instance.new("ClickDetector")
click.MaxActivationDistance = 100
click.Parent = part
click.MouseClick:Connect(function()
if selectedPart then
selectedPart.Color =
selectedPart:GetAttribute("OriginalColor")
local old = selectedPart:FindFirstChildOfClass("SelectionBox")
if old then
old.Transparency = 1
end
end
selectedPart = part
selectedPart.Color = COLORS.accent
local selection = part:FindFirstChildOfClass("SelectionBox")
if selection then
selection.Transparency = 0
end
updateInspector()
end)
end
--==================================================
-- INITIALIZE
--==================================================
updateInspector()
updatePlayhead()
print("RbxMotion Studio v0.1 loaded.")