Creating a basic clock using CFrame

In this tutorial, I’m going to show you how to make a simple clock using CFrame. In the end, you should have something like this:

Creating the hands

Add two parts into workspace.

One hand will be the short hand and the other will be the long hand. (Feel free to rename the hands to avoid confusion).

Resize the long hand. The short hand must also be resized—to about half the long hand’s size.

Now you can duplicate each hand and do the following:

  1. Resize each part and position it to the end of the hand.
  2. Rename them both “Pivot”.
  3. Group each hand along with its pivot.
  4. Set each hand’s primary part to its pivot.
  5. Group both hands into one model.
  6. All parts have to be anchored.
GIF and video demonstrations

clock pivot

Now place the short hand on top of the long hand; in the screenshot below, I gave the short hand a different color to avoid confusion.

Screenshot 2024-02-07 084632

Spinning the hands

Now we want the hands to actually move. (more specifically, spin!) Time to start scripting.

We want something like this:

Add a script inside the model and here’s what you’re gonna do:

  1. a. Get your variables
local hands = script.Parent
  
local longHand = hands:WaitForChild("LongHand")
local shortHand = hands:WaitForChild("ShortHand")
  
local longHand_Pivot = longHand.PrimaryPart
local shortHand_Pivot = shortHand.PrimaryPart
  1. b. And since we’re dealing with time…
local lighting = game:GetService("Lighting")

local minutesInAnHour = 60
  1. c. Get the origin CFrame of each pivot since the clock in general should be stationary.
local longHandOrigin = longHand_Pivot.CFrame
local shortHandOrigin = shortHand_Pivot.CFrame
local function getTwelveHourClock()

end

This is one of our main functions we will use; I’ll talk more about this later.

  1. a. Create a loop
while wait() do

end
  1. b. Rotate the hand model (by its pivot).
longHand:PivotTo()
shortHand:PivotTo()

To rotate a model by it’s origin/pivot, we could do:

model:PivotTo(CFrame.new(model.PrimaryPart.Position) * CFrame.Angles(math.rad(x), math.rad(y), math.rad(z)))

Note: For this to work, the model must have a primary part (the property PrimaryPart must not be nil).

Therefore, we can rotate the hands like this:

longHand:PivotTo(longHandOrigin * CFrame.Angles(0, math.rad(y), 0))
shortHand:PivotTo(shortHandOrigin * CFrame.Angles(0, math.rad(y), 0))
  1. c. Since we are dealing with time here, you’re gonna use the time of day.
local currentTime = lighting.TimeOfDay

The long hand goes by the minute and lighting.TimeOfDay is in the format: hour : minute : seconds (i.e 00:00:00); hence, extract the minutes by getting the substring and convert it to a number.

local currentMinutes = tonumber(string.sub(currentTime, 4, 5))

So now, you can go back to the hands and re-pivot them. But first…

local clock = getTwelveHourClock()

Let me explain what getTwelveHourClock() does:

if lighting.ClockTime > 12 then
	return lighting.ClockTime - 12
else
	return lighting.ClockTime
end

getTwelveHourClock() returns lighting.ClockTime under these conditions:

  • If the current hour (in 24-hour time) is greater than 12, the function will return the difference between lighting.ClockTime and 12.
  • Otherwise, the function will return lighting.ClockTime by itself.

Now we can pivot the hands on its Y-axis. We’ll do this by:

  1. (Long Hand): Dividing the current minutes by the number of minutes in an hour. (Short Hand): Dividing the current hour by 12.

  2. Multiplying the result by 360 (The full circle angle).

  3. Convert it into negative radians. It has to be negative so that it can spin clockwise.

longHand:PivotTo(longHandOrigin * CFrame.Angles(0, -math.rad(360 * currentMinutes/minutesInAnHour), 0))
shortHand:PivotTo(shortHandOrigin * CFrame.Angles(0, -math.rad(360 * clock/12), 0))
Click to see the full script just in case you mess something up
local hands = script.Parent
  
local longHand = hands:WaitForChild("LongHand")
local shortHand = hands:WaitForChild("ShortHand")
  
local longHand_Pivot = longHand.PrimaryPart
local shortHand_Pivot = shortHand.PrimaryPart

local lighting = game:GetService("Lighting")

local minutesInAnHour = 60

local longHandOrigin = longHand_Pivot.CFrame
local shortHandOrigin = shortHand_Pivot.CFrame

local function getTwelveHourClock()
	
	if lighting.ClockTime > 12 then
		return lighting.ClockTime - 12
	else
		return lighting.ClockTime
	end
	
end

while wait() do

    local currentTime = lighting.TimeOfDay
	local currentMinutes = tonumber(string.sub(currentTime, 4, 5)) 
	
	local clock = getTwelveHourClock()
	
	longHand:PivotTo(longHandOrigin * CFrame.Angles(0, -math.rad(360 * currentMinutes/minutesInAnHour), 0))
    shortHand:PivotTo(shortHandOrigin * CFrame.Angles(0, -math.rad(360 * clock/12), 0))

end

Now let’s make a simple day/night cycle.

Add a server script in ServerScriptService and:

local lighting = game:GetService("Lighting")

while wait(.05) do -- You can change the rate at which the clock time changes
	lighting.ClockTime += .01 -- How much you want to increase the clock time by per round
end

The final touches

Just to finish up the clock build:

  1. Add a cylinder in the workspace and name it “Frame”.
  2. Add another cylinder and name it “Pivot”.
  3. Resize the cylinder so that the length of the long hand is at least the radius.
  4. Set the transparency of the pivot of each hand to 1.
  5. Group the hands, the main pivot and the frame into one model.
  6. Make sure that all parts are anchored!
**Final result:**

You did it! :tada:

And that’s all for this tutorial! If you have any questions, suggestions or feedback, feel free to reply below.

8 Likes