I want to make a little 3D display of a drink in a bottle that spins around on the Y axis with a 15 degree X axis tilt.
The script currently looks like this:
local RunService = game:GetService("RunService")
local ServerStorage = game:GetService("ServerStorage")
local bottlesFolder = ServerStorage:WaitForChild("BottlesDrinks")
local isPremium = false
local frames = script.Parent:GetChildren()
local viewportData = {}
local function findFirstBasePart(instance)
for _, child in instance:GetChildren() do
if child:IsA("BasePart") then
return child
else
local found = findFirstBasePart(child)
if found then
return found
end
end
end
return nil
end
for _, frame in frames do
if frame:IsA("Frame") then
local viewport = frame:FindFirstChildOfClass("ViewportFrame")
if viewport then
for _, child in viewport:GetChildren() do
if child:IsA("Model") or child:IsA("BasePart") then
child:Destroy()
end
end
local tool = bottlesFolder:FindFirstChild(frame.Name)
if tool and tool:IsA("Tool") then
local handle = tool:FindFirstChild("Handle")
if handle and handle:IsA("BasePart") then
local partPositions = {}
if isPremium then
partPositions = {
Handle = Vector3.new(0, 0, 0),
Liquid = Vector3.new(0, -0.209, 0),
Bottle22 = Vector3.new(0, 0.869, 0),
Bottle24 = Vector3.new(0.22, -0.348, 0),
Cork = Vector3.new(0, 1.034, 0),
}
else
partPositions = {
Handle = Vector3.new(0, 0, 0),
Liquid = Vector3.new(0, -0.384, 0),
Bottle13 = Vector3.new(0, -0.4, 0),
Cork = Vector3.new(0, 0.875, 0),
}
end
local newModel = Instance.new("Model")
newModel.Name = tool.Name
newModel.Parent = viewport
for partName, position in pairs(partPositions) do
local originalPart = nil
if partName == "Handle" then
originalPart = handle
else
originalPart = handle:FindFirstChild(partName)
if not originalPart then
originalPart = tool:FindFirstChild(partName)
end
end
local partToClone = nil
if originalPart then
if originalPart:IsA("BasePart") then
partToClone = originalPart
elseif originalPart:IsA("Model") or originalPart:IsA("UnionOperation") then
partToClone = findFirstBasePart(originalPart)
end
end
if partToClone and partToClone:IsA("BasePart") then
local clone = partToClone:Clone()
clone.Anchored = true
clone.CFrame = CFrame.new(position)
clone.Parent = newModel
if partName == "Handle" then
for _, child in clone:GetChildren() do
child:Destroy()
end
end
end
end
local centerCFrame, _ = newModel:GetBoundingBox()
local rotatingParts = {}
for _, part in newModel:GetChildren() do
if part:IsA("BasePart") then
local relative = centerCFrame:ToObjectSpace(part.CFrame)
table.insert(rotatingParts, {
Part = part,
RelativeCFrame = relative
})
end
end
viewportData[viewport] = {
Model = newModel,
Center = centerCFrame.Position,
Angle = 0,
RotatingParts = rotatingParts
}
end
end
end
end
end
RunService.Heartbeat:Connect(function(dt)
for _, data in pairs(viewportData) do
data.Angle += math.rad(45) * dt
local tilt = CFrame.Angles(math.rad(15), 0, 0)
local spin = CFrame.Angles(0, data.Angle, 0)
local rotation = spin * tilt
local center = CFrame.new(data.Center)
for _, entry in data.RotatingParts do
entry.Part.CFrame = center * rotation * entry.RelativeCFrame
end
end
end)
It’s meant to clone the required bottle’s handle from the bottlesFolder that is located inside ServerStorage under the name BottlesDrinks, the bottle itself is a tool, that’s why I’m cloning the handle and all the parts inside the handle.
For some reason if IsPremium boolean is true, the parts Bottle22 and Bottle24 don’t get cloned or just aren’t found by the script.
So it just looks like this inside the viewport frame:
When it’s meant to look like this, but inside the viewport frame:
This is the bottle itself inside the folder:
And this is the ScreenGui with the viewport frame and everything:
I’ve tried asking the Roblox Studio assistant, I’ve read quite a bit of documentations and it just doesn’t seem to work…
Any help is appreciated!






