local R=game:GetService("\082\117\110\083\101\114\118\105\099\101")local s=require(script.Parent.Roact)local t=require(script.Parent.t)local W=require(script.Dumpster)local V=workspace.CurrentCamera local H=s.Component:extend("\083\107\121\098\111\120")H.validateProps=t.interface({content=t.instanceOf("\077\111\100\101\108");distance=t.optional(t.number),origin=t.optional(t.Vector3),allowMovement=t.optional(t.boolean);movementScale=t.optional(t.number);Ambient=t.optional(t.Color3),LightColor=t.optional(t.Color3),LightDirection=t.optional(t.Vector3)})H.defaultProps={distance=10000;allowMovement=true;movementScale=1000,Ambience=Color3.fromRGB(200,200,200),LightColor=Color3.fromRGB(140,140,140);LightDirection=Vector3.new(-1,-1,-1)}function H.init(R)assert(R.props.content.PrimaryPart,"\116\104\101 \096\099\111\110\116\101\110\116\096 \112\114\111\112 \109\117\115\116 \104\097\118\101 \097 \080\114\105\109\097\114\121\080\097\114\116")R.viewportRef=s.createRef()R.cameraRef=s.createRef()R.adorneeRef=s.createRef()R.dumpster=W.new()R.cameraCFrame,R.updateCameraCFrame=s.createBinding(CFrame.new())R.adorneeCFrame,R.updateAdorneeCFrame=s.createBinding(CFrame.new())R.skyboxSize,R.updateSkyboxSize=s.createBinding(V.ViewportSize)end function H.render(R)return s.createElement("\066\105\108\108\098\111\097\114\100\071\117\105",{Adornee=R.adorneeRef;LightInfluence=0;ResetOnSpawn=false,Size=R.skyboxSize:map(function(R)return UDim2.new(0,R.X,0,R.Y)end)},{Viewport=s.createElement("\086\105\101\119\112\111\114\116\070\114\097\109\101",{Ambient=R.props.Ambient;LightColor=R.props.LightColor;LightDirection=R.props.LightDirection;Size=UDim2.new(1,0,1,0),Position=UDim2.new(.5,0,.5,0);AnchorPoint=Vector2.new(.5,.5),BackgroundTransparency=1;BackgroundColor3=Color3.fromRGB(255,255,255),CurrentCamera=R.cameraRef,[s.Ref]=R.viewportRef});Adornee=s.createElement("\080\097\114\116",{Anchored=true;Transparency=1;CanCollide=false,CFrame=R.adorneeCFrame,[s.Ref]=R.adorneeRef});Camera=s.createElement("\067\097\109\101\114\097",{CFrame=R.cameraCFrame,[s.Ref]=R.cameraRef})})end function H.didMount(s)local t=s.props.content:Clone()t.Parent=s.viewportRef.current s.dumpster:dump(t)local W=s.props.origin or t.PrimaryPart.Position s.dumpster:dump((V:GetPropertyChangedSignal("\086\105\101\119\112\111\114\116\083\105\122\101")):Connect(function()s.updateSkyboxSize(V.ViewportSize)end))s.dumpster:dump(R.RenderStepped:Connect(function()local R=W if s.props.allowMovement then R=W+V.CFrame.Position/s.props.movementScale end s.updateAdorneeCFrame(V.CFrame*CFrame.new(0,0,-s.props.distance))s.updateCameraCFrame(CFrame.fromMatrix(R,V.CFrame.RightVector,V.CFrame.UpVector))end))end function H.willUnmount(R)R.dumpster:burn()end return H
--[[
	Allows you to easily compose a skybox out of instances.

	Modified from:
	https://devforum.roblox.com/t/3dskybox-a-way-to-create-more-immersive-skyboxes-for-your-game/208760
]]

local RunService = game:GetService("RunService")

local Roact = require(script.Parent.Roact)
local t = require(script.Parent.t)
local Dumpster = require(script.Dumpster)

local camera = workspace.CurrentCamera

local Skybox = Roact.Component:extend("Skybox")

Skybox.validateProps = t.interface({
	content = t.instanceOf("Model"),

	-- The distance where the skybox gui plane is. It’s best to have this quite
	-- big so it doesn’t clip with anything in the workspace.
	distance = t.optional(t.number),

	-- The origin for the camera used by the skybox. This defaults to the
	-- position of content's PrimaryPart.
	origin = t.optional(t.Vector3),

	-- This allows the skybox to 'move' relative to the player.
	allowMovement = t.optional(t.boolean),

	-- This value defines how much the skybox will move when the camera does,
	-- the smaller the value, the faster the skybox will move (It’s good to set
	-- a larger value if you want to make the skybox seem further away than it
	-- really is).
	movementScale = t.optional(t.number),

	Ambient = t.optional(t.Color3),
	LightColor = t.optional(t.Color3),
	LightDirection = t.optional(t.Vector3),
})

Skybox.defaultProps = {
	distance = 10000,
	allowMovement = true,
	movementScale = 1000,
	Ambience = Color3.fromRGB(200, 200, 200),
	LightColor = Color3.fromRGB(140, 140, 140),
	LightDirection = Vector3.new(-1, -1, -1),
}

function Skybox:init()
	assert(self.props.content.PrimaryPart, "the `content` prop must have a PrimaryPart")

	self.viewportRef = Roact.createRef()
	self.cameraRef = Roact.createRef()
	self.adorneeRef = Roact.createRef()

	self.dumpster = Dumpster.new()

	self.cameraCFrame, self.updateCameraCFrame = Roact.createBinding(CFrame.new())
	self.adorneeCFrame, self.updateAdorneeCFrame = Roact.createBinding(CFrame.new())
	self.skyboxSize, self.updateSkyboxSize = Roact.createBinding(camera.ViewportSize)
end

function Skybox:render()
	return Roact.createElement("BillboardGui", {
		Adornee = self.adorneeRef,
		LightInfluence = 0,
		ResetOnSpawn = false,
		Size = self.skyboxSize:map(function(viewportSize)
			return UDim2.new(0, viewportSize.X, 0, viewportSize.Y)
		end),
	}, {
		Viewport = Roact.createElement("ViewportFrame", {
			Ambient = self.props.Ambient,
			LightColor = self.props.LightColor,
			LightDirection = self.props.LightDirection,
			Size = UDim2.new(1, 0, 1, 0),
			Position = UDim2.new(0.5, 0, 0.5, 0),
			AnchorPoint = Vector2.new(0.5, 0.5),
			BackgroundTransparency = 1,
			BackgroundColor3 = Color3.fromRGB(255, 255, 255),
			CurrentCamera = self.cameraRef,
			[Roact.Ref] = self.viewportRef,
		}),

		Adornee = Roact.createElement("Part", {
			Anchored = true,
			Transparency = 1,
			CanCollide = false,
			CFrame = self.adorneeCFrame,
			[Roact.Ref] = self.adorneeRef,
		}),

		Camera = Roact.createElement("Camera", {
			CFrame = self.cameraCFrame,
			[Roact.Ref] = self.cameraRef,
		}),
	})
end

function Skybox:didMount()
	local content = self.props.content:Clone()
	content.Parent = self.viewportRef.current
	self.dumpster:dump(content)

	local origin = self.props.origin or content.PrimaryPart.Position

	self.dumpster:dump(camera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
		self.updateSkyboxSize(camera.ViewportSize)
	end))

	self.dumpster:dump(RunService.RenderStepped:Connect(function()
		local camPos = origin

		if self.props.allowMovement then
			camPos = origin + (camera.CFrame.Position / self.props.movementScale)
		end

		self.updateAdorneeCFrame(camera.CFrame * CFrame.new(0, 0, -self.props.distance))
		self.updateCameraCFrame(CFrame.fromMatrix(camPos, camera.CFrame.RightVector, camera.CFrame.UpVector))
	end))
end

function Skybox:willUnmount()
	self.dumpster:burn()
end

return Skybox
