local q=game:GetService("\082\117\110\083\101\114\118\105\099\101")local Q=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local R=Q:WaitForChild("\077\111\100\117\108\101\115")local j=require(R.src.utils.Logger)local E=require(R.Roact)local x=require(R.M)local F=E.createElement local J=math.rad(.7)local S=E.PureComponent:extend("\077\111\100\101\108\086\105\101\119\112\111\114\116")function S.init(q)q.viewportFrameRef=E.createRef()q.xRotation=0 q.yRotation=0 q.rotationDeltaX=0 q.rotationDeltaY=0 q.delta=0 q.keys={}q.lastPosition=Vector3.new(0,0,0)q.viewportCamera=Instance.new("\067\097\109\101\114\097")q.viewportCamera.CameraType=Enum.CameraType.Scriptable q.model=q.props.model q.isRotating=q.props.isRotating==nil and true or q.props.isRotating end function S.didMount(q)if q.model then q.viewportCamera.Parent=q.viewportFrameRef.current q.viewportFrameRef.current.CurrentCamera=q.viewportCamera q:setRotation()q.model.Parent=q.viewportFrameRef.current end q.isMounted=true q:handleSpin()end function S.didUpdate(q)if q.props.visible and q.model then(coroutine.wrap(function()q.model.Parent=q.viewportFrameRef.current end))()end q.viewportCamera.Parent=q.viewportFrameRef.current q.viewportFrameRef.current.CurrentCamera=q.viewportCamera end function S.setRotation(q)local Q=q.model if Q then local R=Q:IsA("\084\111\111\108")local j=R and Q.Box or Q.PrimaryPart local E=math.max(j.Size.X,j.Size.Y,j.Size.Z)local x=q.props.cameraOffset or CFrame.new(0,E,E)local F=(((CFrame.new(j.Position)*CFrame.Angles(0,-q.yRotation,0))*CFrame.Angles(q.xRotation,0,0))*x).p q.viewportCamera.CFrame=CFrame.new(F,j.Position)end end function S.render(q)local Q=q.props return F("\086\105\101\119\112\111\114\116\070\114\097\109\101",x.extend({AnchorPoint=Vector2.new(.5,.5),BackgroundColor3=Color3.fromRGB(255,255,255);BackgroundTransparency=1;BorderSizePixel=0;Active=true,[E.Ref]=q.viewportFrameRef},x.omit(Q,"\109\111\100\101\108","\099\097\109\101\114\097\079\102\102\115\101\116","\105\115\082\111\116\097\116\105\110\103")))end function S.handleSpin(Q)spawn(function()while Q.isMounted and Q.isRotating do local function R(q,Q)q=q%math.rad(360)if q>math.rad(180)then q=q+Q if q>math.rad(360)then return 0 end else q=q-Q if q<0 then return 0 end end return q end Q.xRotation=R(Q.xRotation,math.rad(2))Q.yRotation=Q.yRotation+J Q:setRotation()Q.delta=q.RenderStepped:wait()end end)end function S.willUnmount(q)q.isMounted=false end return S
local RunService = game:GetService('RunService')
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local Modules = ReplicatedStorage:WaitForChild('Modules')
local logger = require(Modules.src.utils.Logger)
local Roact = require(Modules.Roact)
local M = require(Modules.M)
local createElement = Roact.createElement

local AUTO_SPIN_STEP = math.rad(0.70)

local ModelViewport = Roact.PureComponent:extend('ModelViewport')

function ModelViewport:init()
	self.viewportFrameRef = Roact.createRef()
	self.xRotation = 0
	self.yRotation = 0
	self.rotationDeltaX = 0
	self.rotationDeltaY = 0
	self.delta = 0
	self.keys = {}
	self.lastPosition = Vector3.new(0, 0, 0)
	self.viewportCamera = Instance.new('Camera')
	self.viewportCamera.CameraType = Enum.CameraType.Scriptable
	self.model = self.props.model
	self.isRotating = self.props.isRotating == nil and true or self.props.isRotating
end

function ModelViewport:didMount()
	if self.model then
		self.viewportCamera.Parent = self.viewportFrameRef.current
		self.viewportFrameRef.current.CurrentCamera = self.viewportCamera
		self:setRotation()

		self.model.Parent = self.viewportFrameRef.current
	end

	self.isMounted = true
	self:handleSpin()
end

function ModelViewport:didUpdate()
	if self.props.visible and self.model then
		coroutine.wrap(function()
			self.model.Parent = self.viewportFrameRef.current
		end)()
	end

	self.viewportCamera.Parent = self.viewportFrameRef.current
	self.viewportFrameRef.current.CurrentCamera = self.viewportCamera
end

function ModelViewport:setRotation()
	local model = self.model

	if model then
		local isTool = model:IsA('Tool')
		local part = isTool and model.Box or model.PrimaryPart

		local partLenght = math.max(part.Size.X, part.Size.Y, part.Size.Z)
		local offset = self.props.cameraOffset or CFrame.new(0, partLenght, partLenght)

		local cameraPosition =
			(CFrame.new(part.Position) * CFrame.Angles(0, -self.yRotation, 0) * CFrame.Angles(
				self.xRotation,
				0,
				0
			) * offset).p

		self.viewportCamera.CFrame = CFrame.new(cameraPosition, part.Position)
	end
end

function ModelViewport:render()
	local props = self.props

	return createElement(
		'ViewportFrame',

		M.extend(
			{
				AnchorPoint = Vector2.new(0.5, 0.5),
				BackgroundColor3 = Color3.fromRGB(255, 255, 255),
				BackgroundTransparency = 1,
				BorderSizePixel = 0,
				Active = true,
				[Roact.Ref] = self.viewportFrameRef,
			},
			M.omit(props, 'model', 'cameraOffset', 'isRotating')
		)
	)
end

function ModelViewport:handleSpin()
	spawn(function()
		while self.isMounted and self.isRotating do
			local function returnToDefaultPosition(current, maxStep)
				current = current % math.rad(360)
				if current > math.rad(180) then
					current = current + maxStep
					if current > math.rad(360) then
						return 0
					end
				else
					current = current - maxStep
					if current < 0 then
						return 0
					end
				end
				return current
			end

			self.xRotation = returnToDefaultPosition(self.xRotation, math.rad(2))
			self.yRotation = self.yRotation + AUTO_SPIN_STEP

			self:setRotation()
			self.delta = RunService.RenderStepped:wait()
		end
	end)
end

function ModelViewport:willUnmount()
	self.isMounted = false
end

return ModelViewport