function ViewportWindow.AddSkybox(S,o)S.skyboxFrame:ClearAllChildren()local T=Instance.new("\077\111\100\101\108")local i=Instance.new("\080\097\114\116")i.Anchored=true i.CanCollide=false i.CanTouch=false i.Transparency=1 i.Size=Vector3.new(1,1,1)local k=Instance.new("\066\108\111\099\107\077\101\115\104")k.Scale=Vector3.new(10000,10000,10000)k.Parent=i local W=i:Clone()local m=i:Clone()for S,T in pairs(SIDES)do local k=Instance.new("\068\101\099\097\108")k.Texture=o[S]k.Face=T k.Parent=i end local D=Instance.new("\068\101\099\097\108")D.Texture=o.SkyboxUp D.Face=Enum.NormalId.Top D.Parent=W local y=Instance.new("\068\101\099\097\108")y.Texture=o.SkyboxDn y.Face=Enum.NormalId.Bottom y.Parent=m i.CFrame=SIDE_CFRAME W.CFrame=TOP_CFRAME m.CFrame=BOTTOM_CFRAME i.Parent=T W.Parent=T m.Parent=T T.Name="\083\107\121\098\111\120\077\111\100\101\108"T.Parent=S.skyboxFrame end function ViewportWindow.GetWorldFrame(o)return o.worldFrame end function ViewportWindow.GetWorldRoot(o)return o.worldRoot end function ViewportWindow.GetPart(o)return o.surfaceGui.Adornee end function ViewportWindow.GetSurface(o)local S=o.surfaceGui.Adornee local T=-Vector3.FromNormalId(o.surfaceGui.Face)local i=Vector3.new(T.y,math.abs(T.x+T.z),0)local k=CFrame.fromMatrix(Vector3.new(),i:Cross(T),i,T)local W=(S.CFrame*CFrame.new((-T*S.Size)/2))*k return W,Vector3.new(math.abs(k.XVector:Dot(S.Size)),math.abs(k.YVector:Dot(S.Size)),math.abs(k.ZVector:Dot(S.Size)))end function ViewportWindow.Render(i,o,S,T)local k=workspace.CurrentCamera o=o or k.CFrame if not(S and T)then S,T=i:GetSurface()end if(S:PointToObjectSpace(o.Position)).Z>0 then return end local W=S.YVector:Cross(o.ZVector)local m=W:Dot(W)>0 and W.Unit or o.XVector local D=CFrame.fromMatrix(o.Position,m,S.YVector)local y=S*Vector3.new(0,T.y/2,0)local G=S*Vector3.new(0,-T.y/2,0)local g=D:PointToObjectSpace(y)local R=D:PointToObjectSpace(G)local X=(g*VEC_YZ).Unit local B=(R*VEC_YZ).Unit local I=math.sign(X.y)*math.acos(-X.z)local Z=math.sign(B.y)*math.acos(-B.z)local J=2*math.tan(math.rad(k.FieldOfView/2))local e=math.tan(I)-math.tan(Z)local u=e/J local n=S:VectorToObjectSpace(S.Position-o.Position)local L=(n*VEC_XZ).Unit local j=n*VEC_YZ local C=-L.z local r=(S:VectorToObjectSpace(o.LookVector)*VEC_XZ).Unit local d=r:Dot(L)/C local q=math.sqrt(1-C*C)/C local a,l=1,1 if i.surfaceGui.SizingMode==Enum.SurfaceGuiSizingMode.FixedSize then l=T.x/T.y end local U=math.sign(n.x*n.z)*q local M=(j.y/j.z)*l local b=math.abs((d*u)*l)local N=((S-S.Position)*Y_SPIN)*CFrame.new(0,0,0,a,0,0,0,l,0,U,M,b)local K=0 local p={N:GetComponents()}for o=1,#p,1 do K=math.max(K,math.abs(p[o]))end for o=1,#p,1 do p[o]=p[o]/K end local c=CFrame.new(unpack(p))+o.Position i.camera.FieldOfView=k.FieldOfView i.camera.CFrame=c end


function ViewportWindow:AddSkybox(skybox)
	self.skyboxFrame:ClearAllChildren()
	
	local model = Instance.new("Model")

	local side = Instance.new("Part")
	side.Anchored = true
	side.CanCollide = false
	side.CanTouch = false
	side.Transparency = 1
	side.Size = Vector3.new(1, 1, 1)

	local mesh = Instance.new("BlockMesh")
	mesh.Scale = Vector3.new(10000, 10000, 10000)
	mesh.Parent = side

	local top = side:Clone()
	local bottom = side:Clone()

	for property, enum in pairs(SIDES) do
		local decal = Instance.new("Decal")
		decal.Texture = skybox[property]
		decal.Face = enum
		decal.Parent = side
	end

	local decalTop = Instance.new("Decal")
	decalTop.Texture = skybox.SkyboxUp
	decalTop.Face = Enum.NormalId.Top
	decalTop.Parent = top

	local decalBottom = Instance.new("Decal")
	decalBottom.Texture = skybox.SkyboxDn
	decalBottom.Face = Enum.NormalId.Bottom
	decalBottom.Parent = bottom

	side.CFrame = SIDE_CFRAME
	top.CFrame = TOP_CFRAME
	bottom.CFrame = BOTTOM_CFRAME

	side.Parent = model
	top.Parent = model
	bottom.Parent = model
	
	model.Name = "SkyboxModel"
	model.Parent = self.skyboxFrame
end

function ViewportWindow:GetWorldFrame()
	return self.worldFrame
end

function ViewportWindow:GetWorldRoot()
	return self.worldRoot
end

function ViewportWindow:GetPart()
	return self.surfaceGui.Adornee
end

function ViewportWindow:GetSurface()
	local part = self.surfaceGui.Adornee

	local v = -Vector3.FromNormalId(self.surfaceGui.Face)
	local u = Vector3.new(v.y, math.abs(v.x + v.z), 0)
	local lcf = CFrame.fromMatrix(Vector3.new(), u:Cross(v), u, v)
	local cf = part.CFrame * CFrame.new(-v * part.Size/2) * lcf

	return cf, Vector3.new(
		math.abs(lcf.XVector:Dot(part.Size)),
		math.abs(lcf.YVector:Dot(part.Size)),
		math.abs(lcf.ZVector:Dot(part.Size))
	)
end

function ViewportWindow:Render(cameraCFrame, surfaceCFrame, surfaceSize)
	local camera = workspace.CurrentCamera

	cameraCFrame = cameraCFrame or camera.CFrame
	if not (surfaceCFrame and surfaceSize) then
		surfaceCFrame, surfaceSize = self:GetSurface()
	end
	
	if surfaceCFrame:PointToObjectSpace(cameraCFrame.Position).Z > 0 then
		return
	end 

	local xCross = surfaceCFrame.YVector:Cross(cameraCFrame.ZVector)
	local xVector = xCross:Dot(xCross) > 0 and xCross.Unit or cameraCFrame.XVector
	local levelCameraCFrame = CFrame.fromMatrix(cameraCFrame.Position, xVector, surfaceCFrame.YVector)

	local tc = surfaceCFrame * Vector3.new(0, surfaceSize.y/2, 0)
	local bc = surfaceCFrame * Vector3.new(0, -surfaceSize.y/2, 0)
	local cstc = levelCameraCFrame:PointToObjectSpace(tc)
	local csbc = levelCameraCFrame:PointToObjectSpace(bc)

	local tv = (cstc * VEC_YZ).Unit
	local bv = (csbc * VEC_YZ).Unit
	local alpha = math.sign(tv.y) * math.acos(-tv.z)
	local beta = math.sign(bv.y) * math.acos(-bv.z)

	local fovH = 2 * math.tan(math.rad(camera.FieldOfView / 2))
	local surfaceFovH = math.tan(alpha) - math.tan(beta)
	local fovRatio = surfaceFovH / fovH

	local dv = surfaceCFrame:VectorToObjectSpace(surfaceCFrame.Position - cameraCFrame.Position)
	local dvXZ = (dv * VEC_XZ).Unit
	local dvXY = dv * VEC_YZ

	local dvx = -dvXZ.z
	local camXZ = (surfaceCFrame:VectorToObjectSpace(cameraCFrame.LookVector) * VEC_XZ).Unit
	local scale = camXZ:Dot(dvXZ) / dvx
	local tanArcCos = math.sqrt(1 - dvx*dvx) / dvx

	local w, h = 1, 1
	if self.surfaceGui.SizingMode == Enum.SurfaceGuiSizingMode.FixedSize then
		h = surfaceSize.x / surfaceSize.y
	end

	local dx = math.sign(dv.x*dv.z) * tanArcCos
	local dy = dvXY.y / dvXY.z * h
	local d = math.abs(scale * fovRatio * h)

	local newCFrame = (surfaceCFrame - surfaceCFrame.Position) * Y_SPIN
		* CFrame.new(0, 0, 0, w, 0, 0, 0, h, 0, dx, dy, d)

	local max = 0
	local components = {newCFrame:GetComponents()}
	for i = 1, #components do
		max = math.max(max, math.abs(components[i]))
	end

	for i = 1, #components do
		components[i] = components[i] / max
	end

	local scaledCFrame = CFrame.new(unpack(components)) + cameraCFrame.Position

	self.camera.FieldOfView = camera.FieldOfView
	self.camera.CFrame = scaledCFrame
	
	-- this eats performance!
	-- self:_refreshVisibility(cameraCFrame, surfaceCFrame, surfaceSize, 0.001)
end
