How do I pose a character in a ViewportFrame?

Here is my current code.

repeat wait() until game.Players.LocalPlayer.Character
char = game.Players.LocalPlayer.Character
wait(0.1)
local clone = char:Clone()
local torso = clone:WaitForChild("UpperTorso")
clone.Parent = game.ReplicatedStorage
local ViewportFrame = script.Parent
local newCam = Instance.new("Camera")
newCam.CameraType = "Scriptable"
newCam.CFrame = CFrame.new(torso.Position+torso.CFrame.lookVector*6+Vector3.new(0,2,0), torso.Position)
ViewportFrame.CurrentCamera = newCam
clone.Parent = ViewportFrame
local anim = game.ReplicatedStorage.idleAnim:Clone()
anim.Parent = clone
local animTrack = clone.Humanoid:LoadAnimation(anim)
animTrack:Play()

The character appears but it’s just in the default pose. The animation works if I use it outside of a ViewportFrame.

Maybe I’m doing it completely wrong. What should I do?

1 Like

If I recall correctly, animations don’t render inside ViewportFrames. Not entirely sure though.

1 Like

I grabbed this code from a current project I’m working on, feel free to use it/mangle it in the way you need it. Hopefully it does what you’re looking for! :slight_smile:

local RunService = game:GetService('RunService')
local Player = game.Players.LocalPlayer
local ViewPort = script.Parent.ViewportFrame
local Offset = CFrame.new(0,2,-7)
local Camera = Instance.new("Camera")
ViewPort.CurrentCamera = Camera
	
function RenderHumanoid(Model, Parent, MainModel)
	local ModelParts = Model:GetChildren()
	for i=1, #ModelParts do
		local Part = ModelParts[i]
		if not Part:IsA("Script") and Part.Name ~= "Belt" then
				Part.Archivable	= true
			local RenderClone	= Part:Clone()
			if Part:IsA("MeshPart") or Part:IsA("Part") then
				PartUpdater = RunService.Heartbeat:Connect(function()
					if Part then
						RenderClone.CFrame = Part.CFrame
					else
						RenderClone:Destroy()
						PartUpdater:Disconnect()
					end
				end)
			elseif Part:IsA("Accessory") then
				PartUpdater2 = RunService.Heartbeat:Connect(function()
					if Part then
						if RenderClone:FindFirstChild("Handle") and Part:FindFirstChild("Handle") then
						RenderClone.Handle.CFrame = Part.Handle.CFrame
						end
					else
						RenderClone:Destroy()
						PartUpdater2:Disconnect()
					end
				end)
			elseif Part:IsA("Script") then
				Part:Destroy()
			end
			RenderClone.Parent = Parent
		end
	end
end

wait(1)

function Render()
	ViewPort:ClearAllChildren()
	local Char = Instance.new("Model")
		Char.Name = ""
		Char.Parent = ViewPort
	RenderHumanoid(Player.Character,Char)
end

Player.Character.DescendantAdded:Connect(Render)
Player.Character.DescendantRemoving:Connect(Render)

Render()

CameraUpdater = RunService.Heartbeat:Connect(function()
	if Player.Character.HumanoidRootPart then
		Camera.CFrame =  CFrame.new(Player.Character.HumanoidRootPart.CFrame:toWorldSpace(Offset).p, Player.Character.HumanoidRootPart.CFrame.p)
	end
end)

Player.Character.Humanoid.Died:connect(function()
script.Disabled = true
repeat wait() until Player.Character:FindFirstChild("Humanoid") and Player.Character:FindFirstChild("Humanoid").Health == 100
script.Disabled = false
end)

Note: I’m not 100% sure how efficient it is, but it works perfectly for my setup

I ended up fixing it by putting

repeat wait() until game.ContentProvider.RequestQueueSize < 1

at the start of my script, and the animation shows. I’m not sure how they are displayed but it’s a completely still animation so that may be why it works.

That line of code you added does nothing but drop the efficiency of your code. Physics aren’t simulated in ViewportFrames, which is why it’s “still”. You can’t run animations on ViewportFrame models without a hard-coded implementation to do so.

That aside, there is a bone I’d like to pick with a certain part of your code.

repeat wait() until game.Players.LocalPlayer.Character
char = game.Players.LocalPlayer.Character

Don’t do this. This reinvents the wheel for signals and it ends up running loops in places where they don’t belong. You can change this to the following:

local Players = game:GetService("Players") -- Canonical way to fetch services. Don't index them through dot notation.

local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait() -- Returns the character
3 Likes

That ViewportFrame System that he posted, wasn’t it yours?

Did this actually work in the end?
I’m in a similar situation however the only results I’m finding are by simulating an animation elsewhere and copying it that way?