Screen3D - A 3D UI framework that just works

I have this weird bug concering shiftlock (Specifically SmoothShiftlock) Which offsets the humanoid.cameraoffset value.

Here is the visual bug:

When you turn on shiftlock, it basically offsets too far and the 3d UI is no longer visible.

Here is the code for the 3d UI:

--//Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

--//Local Variables
local Camera = workspace.CurrentCamera

--//Modules
local Modules = ReplicatedStorage.Modules

local Screen3D = require(Modules.UI.Components.Screen3D)

local Information = require(ReplicatedStorage.Shared.Information)
local UserData = require(ReplicatedStorage.Shared.UserData)

--//Information
local MovesetInformation = Information.Movesets
local ChihiroInformation = MovesetInformation.Chihiro
local KunishigeInformation = MovesetInformation.Kunishige

local GlobalData = UserData.Global

--//Main 
local Knit = require(ReplicatedStorage.Packages.Knit)

--//UI
local PlayerGui: PlayerGui = Knit.Player.PlayerGui

local HotbarGUI: GuiBase = PlayerGui:WaitForChild("Hotbar")

local HotbarFrame: Frame = HotbarGUI:WaitForChild("Hotbar")
local TipCanvas: CanvasGroup = HotbarFrame:WaitForChild("Tip")

local SkillSlots = HotbarFrame:WaitForChild("SkillSlots")

local SkillSlot1: TextButton = SkillSlots:WaitForChild("1")
local SkillSlot2: TextButton = SkillSlots:WaitForChild("2")
local SkillSlot3: TextButton = SkillSlots:WaitForChild("3")
local SkillSlot4: TextButton = SkillSlots:WaitForChild("4")

local SkillSlotText1: TextLabel = SkillSlot1:WaitForChild("ButtonText")
local SkillSlotText2: TextLabel = SkillSlot2:WaitForChild("ButtonText")
local SkillSlotText3: TextLabel = SkillSlot3:WaitForChild("ButtonText")
local SkillSlotText4: TextLabel = SkillSlot4:WaitForChild("ButtonText")

--//3D UI
local ThreeDHotbarGUI = Screen3D.new(HotbarGUI, 5)

local ThreeDHotbarFrame = ThreeDHotbarGUI:GetComponent3D(HotbarFrame)
local ThreeDTipCanvas = ThreeDHotbarGUI:GetComponent3D(TipCanvas)

local ThreeDSkillSlots = ThreeDHotbarGUI:GetComponent3D(SkillSlots)

local ThreeDSkillSlot1 = ThreeDHotbarGUI:GetComponent3D(SkillSlot1)
local ThreeDSkillSlot2 = ThreeDHotbarGUI:GetComponent3D(SkillSlot2)
local ThreeDSkillSlot3 = ThreeDHotbarGUI:GetComponent3D(SkillSlot3)
local ThreeDSkillSlot4 = ThreeDHotbarGUI:GetComponent3D(SkillSlot4)

local ThreeDSkillSlotText1 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText1)
local ThreeDSkillSlotText2 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText2)
local ThreeDSkillSlotText3 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText3)
local ThreeDSkillSlotText4 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText4)

--//Settings
local LerpSpeed = 2
local Sensitivity = .02

local MaxVelocity : number = 1 --or anything


--//Module
local HotBarController = Knit.CreateController  {
	Name = "HotBarController",
	
	CurrentMoveset = nil,
}

--//Start
function HotBarController:KnitStart()
	
	self:Create3DHotbar()

end

--//Methods
function HotBarController:Create3DHotbar()
	
	task.spawn(function()
		
		--//Enable
		ThreeDHotbarFrame:Enable()
		ThreeDTipCanvas:Enable()

		ThreeDSkillSlots:Enable()

		ThreeDSkillSlot1:Enable()
		ThreeDSkillSlot2:Enable()
		ThreeDSkillSlot3:Enable()
		ThreeDSkillSlot4:Enable()

		ThreeDSkillSlotText1:Enable()
		ThreeDSkillSlotText2:Enable()
		ThreeDSkillSlotText3:Enable()
		ThreeDSkillSlotText4:Enable()

		--//Inital Offset
		ThreeDHotbarFrame.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDTipCanvas.offset = CFrame.Angles(0,math.rad(10),0) 

		ThreeDSkillSlots.offset = CFrame.Angles(0,math.rad(10),0) 

		ThreeDSkillSlot1.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlot2.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlot3.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlot4.offset = CFrame.Angles(0,math.rad(10),0) 

		ThreeDSkillSlotText1.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlotText2.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlotText3.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlotText4.offset = CFrame.Angles(0,math.rad(10),0) 

		local Connection = RunService.RenderStepped:Connect(function(DeltaTime)

			local RootPartAssemblyLinearVelocity = Knit.Player.Character.HumanoidRootPart.AssemblyLinearVelocity

			if RootPartAssemblyLinearVelocity == 0 then
				return
			end

			local RelativeVelocity = Camera.CFrame.Rotation:ToObjectSpace(CFrame.new(RootPartAssemblyLinearVelocity * Sensitivity)).Position
			local LerpAlpha = math.min(DeltaTime * LerpSpeed, 1)

			if RelativeVelocity.Magnitude ~= 0 then
				RelativeVelocity = math.min(MaxVelocity, RelativeVelocity.Magnitude  ) * RelativeVelocity.Unit
			end

			ThreeDHotbarGUI.rootOffset = ThreeDHotbarGUI.rootOffset:Lerp(CFrame.new(RelativeVelocity), LerpAlpha)

		end)
		
	end)
	
end

	
function HotBarController:SetHotbarEnabled(Boolean: boolean)

	for _,SurfaceGui: SurfaceGui in HotbarGUI:GetDescendants() do

		if SurfaceGui:IsA("SurfaceGui") then
			SurfaceGui.Enabled = Boolean
		end

	end

end

function HotBarController:SetSkillTexts(CharacterName: string)
	
	if CharacterName == "Chihiro" then

		self.CurrentMoveset = "Chihiro"

		SkillSlotText1.Text = ChihiroInformation.Skills.One
		SkillSlotText2.Text = ChihiroInformation.Skills.Two
		SkillSlotText3.Text = ChihiroInformation.Skills.Three
		SkillSlotText4.Text = ChihiroInformation.Skills.Four


	elseif CharacterName == "Kunishige" then

		self.CurrentMoveset = "Kunishige"

		SkillSlotText1.Text = KunishigeInformation.Skills.One
		SkillSlotText2.Text = KunishigeInformation.Skills.Two
		SkillSlotText3.Text = KunishigeInformation.Skills.Three
		SkillSlotText4.Text = KunishigeInformation.Skills.Four

	end
	
end



return HotBarController

Any idea how to fix this?

4 Likes

my guess as to what is happening here is that the shiftlock module’s renderstepped is running after the module3d’s renderstepped so module3d doesn’t notice that the camera gets offset to the right every frame

when i get on pc i’ll update module3d to run on BindOnRenderStep so that it always runs last and detects renderstepped camera changes

2 Likes

yea thank you for noticing that. It was really detrimental to me lol

2 Likes

Have you been able to implement BindOnRenderStep? I can do it for you if you want.

2 Likes


doesnt work for me how do i fix, parent is a screen gui

1 Like

you have to enable the frames/textlabels inside the screengui, not the screengui itself

2 Likes

thats silly. add a :EnableDescendants() function :smiley:

Have you been able to update it yet?
Im in desperate need of a fix so ill probably just do it myself atp.

Agreed. Takes alot of extra space just to do something 1 function should do.

Probably will build it tho

2 Likes

Can you upload this to the creator marketplace?

2 Likes

Hi, Great module but i am having trouble with it. It seems to be duplicating the UI the I created when I enable the 3D Components.

1 Like

Is there a way to apply it on guis inside ui list layout?
unsure if i did it right (or theres a specific thing i should do)
Expected :


What I got :

sadly none of the ui modifiers work on it 3d ui yet because idk how to properly implement them :sob:

as usual if someone is smart and/or crazy enough to somehow get all the ui modifiers to work flawlessly with screen3d please feel free to send a pull request

the current workaround is just to set all the positions manually

guess who got ui modifier compatibility working??? expect a new version coming out soon once i iron out all the bugs

6 Likes

Cant wait !! Been using it to replace old 3D UI I did using surfaceguis and positioning the camera manually and it works a lot better

Just released “compatibility mode” to the dev branch:

when 3d objects are enabled with :EnableCompatibility(), they will try to conform to UI modifiers (eg. uilistlayout) at all costs. Setting, reading and updating their offset will work fine, but messing with their parent directly (by doing component.parent3D) might have odd side effects

currently only releasing this to the dev branch because my design choices were… questionable…

3 Likes

drama in MY community resource??? :broken_heart: :broken_heart: :broken_heart: :broken_heart:

does this also fix the problem with smooth shiftlock?

haven’t tested it, it probably should

MAKE :EnableDescendants() or i cant use your resource </3