Skip to content
ct

Calendar Time v2.0

Speed Stack and Clock Pacing

This guide is the single source of truth for understanding how time advances in a Calendar Time scene. It exists because "how fast is the clock running?" has four answers, depending on which question

Status
Current
Version
v2.0
Updated
Current with plugin v2.0

This guide is the single source of truth for understanding how time advances in a Calendar Time scene. It exists because "how fast is the clock running?" has four answers, depending on which question you're asking. Getting them confused is the most common source of "the clock is going way too fast / way too slow" bugs.

The four things, in one place

Layer Where it lives Default value What it controls
Engine.time_scale Godot global 1.0 Multiplies every Godot tick: physics, animation, signals, audio, etc. A UI dialog scales by it.
TimeHost.time_scale.delta_multiplier TimeHost Node in your scene 1000.0 (in default_time_scale.tres) Engine→game rate bridge: how many game-seconds one real-second becomes.
GameClock.speed_multiplier GameClock resource (per-clock) 1.0 (slider default 3.0) Per-clock runtime rate. One clock on the host can be 30x while another is 1x.
GameClockSpeedSlider.slider_time_multipliers[i] UI control on the demo ticks: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2, 3, 10, 30, 60] The value the slider writes to clock.speed_multiplier on each tick. Tick 0 is now handled separately.
EngineTimeScaleSlider (demo code) UI control in demo/ui/ ticks: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2, 3] Tick 0 = get_tree().paused = true (engine paused, rendering intact). Ticks 1+ = Engine.time_scale directly. Copy from demo to use.

The composition formula, end-to-end, is:

game_seconds_advanced_per_frame =
    Engine.time_scale
  × TimeHost.time_scale.delta_multiplier
  × GameClock.speed_multiplier
  × engine_delta_seconds_per_frame

That's the same formula documented in TimeScale and DriveModes; this guide is about the slider part specifically.

"1x slider" — what does that actually mean?

The slider's label shows slider_time_multipliers[i] + "x". So:

  • "1x" means clock.speed_multiplier = 1.0
  • "3x" means clock.speed_multiplier = 3.0
  • "60x" means clock.speed_multiplier = 60.0

The "x" is relative to the host's time_scale.delta_multiplier, NOT relative to wall-clock real-time. There is no slider position that equals "1x real-time" unless delta_multiplier = 1.0.

Concretely, with the demo defaults (delta_multiplier = 1000, Engine.time_scale = 1.0, engine_delta = 1/60):

Slider tick clock.speed_multiplier game-seconds / real-second
1x 1.0 1000
3x 3.0 3000
10x 10.0 10,000
30x 30.0 30,000
60x 60.0 60,000

So "1x" in the demo means "1 game-second per millisecond of real time". The slider is for adjusting how far past the base rate you want to be, not for choosing between "real-time" and "fast-forward".

If you want a slider position that is real-time, set the host's time_scale.delta_multiplier = 1.0. Then "1x slider" = 1 game-second per real-second. The slider's numeric values still read the same, but the "x" is now read as "real-time multiplier".

Why is delta_multiplier = 1000 the demo default?

The default is 1000 because Calendar Time is built for idle and simulation games where the world advances faster than the player watches. A typical calendar idle game runs 1000–3000 game-seconds per real-second so a "day" feels like a minute. The slider then amplifies that base rate for "fast forward to next year" type interactions.

If your game is real-time-pacing (1 real-second = 1 game-second), set the host's time_scale.delta_multiplier = 1.0 and the slider's "1x" becomes the natural real-time tick.

When to pin to clock time vs. raw engine time

This is the design question that comes up most often. The rule of thumb: anything in the simulated world uses clock time; anything in the UI/host shell uses raw engine time.

Subsystem Use Why
Date / day / time-of-day progression Clock time Calendar Time is the source of truth for the simulated world.
Day/night lighting transitions Clock time "sunset happens at 7 PM" is a world fact, not a UI animation.
NPC idle animations (blink, breathe, foot-tap) Clock time Pause the game → NPC should freeze. World fact.
Game-owned fixed-step simulation systems Fixed-step tick drives Calendar Time manually Your simulation loop owns system order; Calendar Time records the calendar state for the step.
NPC "look around" (ninja flip every 10 real-sec) Clock time (real-time pacing) Dressing animation that pauses with the world but paces on real-time — interval excludes smult so flip rate is constant regardless of clock speed.
Cursor blink, button hover, menu open/close Raw engine time UI shell — should not freeze when the game pauses.
Tween / animation player for cosmetic effects Raw engine time Cosmetic effects are part of the UI shell, not the world.
Audio (BGM, ambient sounds) Raw engine time Music doesn't pause when you freeze the world.
Save/load determinism replay Raw microseconds (deterministic) The whole point of replay is to be byte-exact. Direct microsecond injection.

The "ninja flip every 10 real-seconds" example is a special case worth calling out: it's a dressing animation, not a game actor, but it IS driven by the clock (listens to game_seconds_advanced). The flipper uses clock time so it freezes when the player pauses the world, but its interval excludes smult so it paces on real-time — exactly one flip every N real-seconds regardless of clock speed. This is the "real-time pacing" sub-pattern of clock-driven animation. See the clock-driven animation pattern guide for the two sub-patterns (flipper vs. emote) and when to use each.

If you want the ninja to keep flipping while the world is paused (different design choice), use raw engine time instead. The pattern is the same; the only thing that changes is which time value the flipper reads.

GameClockSpeedSlider vs. TimeHost.time_scale vs. Engine.time_scale — what each one does

A common source of confusion: three different "speed" knobs. They control different things, and only one of them is per-clock:

Knob What it does to the COMPOSITION
Engine.time_scale = 0.5 Halves physics, animation, audio, and clock speed. EVERYTHING.
Engine.time_scale = 0.0 NEVER DO THIS. Freezes all _process/_physics_process callbacks, breaking tilemap rendering, sprite drawing, and Godot internals. Use host.time_scale.delta_multiplier = 0.0 for clock-time pause, or get_tree().paused = true for engine-time pause (the EngineTimeScale slider's "Paused" tick does this).
host.time_scale.delta_multiplier = 0.0 Stops the host from advancing ANY clock, but Godot still ticks. The intended "pause" mechanism.
host.time_scale.delta_multiplier = 0.5 Halves all clocks under the host, but Godot + UI still tick. Half-speed world.
clock.speed_multiplier = 0.0 (set by slider) Stops JUST this clock. Other clocks on the same host still tick.
clock.speed_multiplier = 0.5 (set by slider) Halves JUST this clock.

The demo's GameClockSpeedSlider is explicitly bound to a single clock's speed_multiplier and does NOT touch Engine.time_scale or host.time_scale. If you want the slider to also control those, you'd extend the slider — but most projects don't.

The EngineTimeScaleSlider is demo code (not part of the addon) because it wraps Godot-global Engine.time_scale, not Calendar Time APIs. To use it in your project, copy demo/ui/engine_time_scale_slider.gd and demo/ui/engine_time_scale_control.tscn into your project. The slider's "Paused" tick uses get_tree().paused = true instead of Engine.time_scale = 0 (which freezes rendering).

The "constant flipping" failure mode

If you set up a clock-driven animation (like the ninja flip or the mood bubble bob in the demo) and observe it firing way more often than expected, the most common cause is: delta_multiplier is very high and interval_real_seconds × delta_multiplier produces a much smaller game-second interval than you expected.

Math check at demo defaults (flipper, excludes smult):

flips_per_real_second = delta_multiplier / interval_real_seconds
                      = 1000 / 10
                      = 100 flips per real-second

That's still fast — the flipper fires 100 times per real-second, which to the eye looks like constant flipping. But it's now independent of speed_multiplier (the flipper paces on real-time, not game-time).

For the mood bubble bob (which divides by dmult × smult):

bobs_per_real_second = (dmult × smult) / bob_period_real_seconds
                     = (1000 × 3) / 1
                     = 3000 bobs per real-second

The fix is either (a) lower delta_multiplier so the math is realistic, (b) increase interval_real_seconds to compensate, or (c) explicitly call out the demo's calibration in docs and let users who want slower flips opt in. The shipped flipper uses (b) and auto-scales via the math in flipper.gd::_recompute_speed().

The "what does 1x mean" user-facing message

If your game exposes a "speed" setting to the player (e.g. an in-game menu), the right labeling depends on what your host's delta_multiplier is:

  • For real-time games (delta_multiplier = 1.0): "1×", "2×", "5×" map cleanly to wall-clock.
  • For idle games (delta_multiplier = 1000): "1×", "10×", "100×" is the calibrated range; the game already advances 1000 game-seconds per real-second at "1×", so "100×" is 100,000 game-seconds per real-second.

The shipped GameClockSpeedSlider is calibrated for the demo's idle-game defaults. If you ship a different host calibration, override the slider_time_multipliers array in your own scene.

Worked example

Setting: real-time-pacing game, delta_multiplier = 1.0, Engine.time_scale = 1.0, slider at "3×".

Per frame at 60 fps:

  • engine_delta = 1/60 sec
  • multiplier chain: 1.0 × 1.0 × 3.0 × 1.0 = 3.0
  • game-seconds per frame: (1/60) × 3.0 = 0.05 game-sec

Per real-second:

  • 60 × 0.05 = 3.0 game-seconds

So at 3× slider, the world advances 3 game-seconds per real-second. A calendar day (24 game-hours × 60 game-minutes × 60 game-seconds) takes 28,800 game-seconds ÷ 3 = 9,600 real-seconds = 2.67 real-hours per calendar day. That's a slow, watchable pace.

Same setup but delta_multiplier = 1000:

  • 60 × (1/60) × 1000 × 3.0 = 3,000 game-seconds per real-second
  • 28,800 ÷ 3,000 = 9.6 real-seconds per calendar day

That's an idle-game pace. "1×" already runs 1000× faster than real-time.

See also

  • clock-driven-animation-pattern.md — the worked code example of converting a Timer-based animation (ninja flip) and a speed-based animation (mood bubble bob) to clock-driven, with real-time-friendly inspector knobs.
  • TimeScale and DriveModes — the formal ownership table for the four TimeScale symbols.
  • What Should Drive What? — beginner guide for choosing Calendar Time, Godot, or a game-owned fixed-step tick.