FolioTier 3

time

Discrete-period clock + day counter — the time-passes machinery for sandbox VNs. Ships paired with Locations.

What Time does

Time is two coupled state machines — a discrete-period clock (morning / noon / evening / night) and a day counter — that the runtime advances on author-controlled boundaries. Games gate content on "what time of day" and "what day of the week" without manual scalar bookkeeping.

Like Stats, Time exists because Ren'Py has no time primitive — every sandbox game builds its own scaffolding in init python: blocks. Shipping it as an engine subsystem replaces that scaffolding with declarative verbs and a typed slot in the canonical project that saves carry.

Verbs

| Verb | Page | |---|---| | set time period=<id> day=<id> | /docs/folio/set-time | | advance-time periods=<expr> | /docs/folio/advance-time |

Expression accessors

| Accessor | Returns | |---|---| | time.period | The current period identifier (or null when no clock state). | | time.day | The current day identifier (or null when no clock state). |

Both round-trip through the bounded expression grammar — use them inside any if, gate when:, hotspot when:, etc.

if time.period == "evening" -> events-evening else -> events-day

Default period / day enums

| Periods (default) | Days (default) | |---|---| | morning, noon, evening, night | monday, tuesday, wednesday, thursday, friday, saturday, sunday |

Imported projects can override either set via the time config schema; the runtime gates set time writes against the declared lists (silently drops unknown identifiers). Your project's actual enum lives in canonicalProject.subsystems.time.periods / .days — the Studio's Locations + Time rail shows them.

Trenchcoat split — linear-time vs. calendar-with-schedules

v1 ships the linear-time half completely:

  • Linear-time (Eternum) — period + day count, no per-character schedules. Authors use at period <X> art variants and if time.period == "<X>" gates directly. Eternum has zero calendar machinery — period strings are textual narration in the dialogue prose, not runtime state. The runtime no-ops cleanly on advance-time when initialPeriod / initialDay are null.
  • Calendar-with-schedules (AWAM, Lab Rats 2) — characters have declared schedules; the runtime resolves "who is at this location right now" from the clock + schedule table. Out of v1. The schema reserves time.schedules: null for the post-v1 expansion; authors who need character schedules in v1 fall through to manual lane via the migration report.

"No clock state" projects (Eternum case)

When initialPeriod / initialDay are null:

  • set time / advance-time are silently no-ops at runtime.
  • time.period / time.day return null from expression accessors.
  • if time.period == "evening" resolves false (null is never equal to a string).

Authors of Eternum-shaped projects use period strings narratively ("It's getting late") rather than as state. The Time runtime exists to support Locations art time-of-day variants and to hold the slot for post-v1 calendar expansion.

Importer translation

Ren'Py's time machinery is pure scaffolding — bare variables with helper functions in init python::

default current_period = "morning"
default current_day = "monday"
default day_index = 0

init python:
    def advance_period():
        global period_index, day_index
        period_index = (period_index + 1) % 4
        if period_index == 0:
            day_index += 1

The pattern pass (Track B § B.3) detects this scaffolding shape (variable triplet + modulo arithmetic on period index) and lowers it to advance-time periods=1 calls. Conditions on current_period == "<period>" lower to if time.period == "<period>".

Custom period names, non-standard rollover, hour-granularity counters land in the migration report's manual lane. AWAM-style per-character schedules flow there too in v1.

See also

  • set time — initialize the clock
  • advance-time — move the clock forward
  • locations — paired subsystem
  • iftime.period / time.day in conditional routing
  • stats — sister subsystem