|
Foundational helpers referenced by most subsequent code. Small, pure,
no dependencies on anything in the project.
utils/result.ts Result<T, E> = Ok<T> | Err<E> for recoverable
failures at system boundaries (save/load, manifest
fetch, content validation). Internal pure logic
still uses throw for programmer errors.
ok / err / isOk / isErr / mapResult / mapErr /
unwrap / unwrapOr.
utils/assert.ts assert (with type-narrowing asserts), assertNever
for exhaustive-switch termination, assertDefined
for narrowing T | null | undefined → T.
utils/equal.ts Structural deepEqual for tests comparing simulation
snapshots. Handles plain objects, arrays, Map, Set,
Date, primitives. Does not handle cyclic graphs
(simulation state is a tree).
utils/types.ts Common type aliases: NonEmptyArray, JsonValue,
ElementOf, DeepReadonly, Brand<T, B> for nominal /
branded types (PersonId vs RelationshipId).
utils/log.ts Structured logging wrapping console. Developer-
facing only; the game ships with no runtime
telemetry.
utils/index.ts Public re-exports.
40 unit tests in tests/unit/utils/ cover Result constructors and
combinators, assert variants, and deepEqual's primitive / array /
object / Map / Set / Date paths plus a realistic simulation-snapshot
comparison.
|
|
The Hollowdark calendar is 12 × 30-day months + a 5-day year-end
festival = 365 days, with 7-day weeks (docs/01-world.md and the
style bible). Months live in canonical order:
spring 1 Thawing 2 Greening 3 Blossomtide
summer 4 Highsun 5 Amberhaze 6 Harvestmark
autumn 7 Firstfall 8 Stormturn 9 Ashfall
winter 10 Rainfall 11 Hollowdark 12 Rimefrost
festival 13 Year's End Festival (5 days)
time/calendar.ts month names, season mapping, days-per-month,
festival helpers
time/gameTime.ts GameTime shape + arithmetic: makeGameTime,
addDays / addWeeks / addMonths / addYears,
daysBetween / weeksBetween, compare / isBefore /
isAfter / isSameDay, dayOfWeek, dayOfYear,
toAbsoluteDays, formatGameTime
time/granularity.ts LifeStage + TickUnit mapping — one tick is a
year in infancy, a season in childhood, a month
in adolescence and old age, a week in adult life
(docs/05-time-system.md, ARCHITECTURE.md §5)
time/speed.ts Speed type: 'paused' | 'play' | 'fast'
time/index.ts public re-exports
Arithmetic is implemented by flattening GameTime to absolute-day
integers (year × 365 + dayOfYear - 1) so addDays, daysBetween, and
ordering are exact integer math. addMonths uses 13-month modular
arithmetic and clamps the day into the festival's 5-day length on
overflow.
59 unit tests in tests/unit/time/ cover constants, validation,
arithmetic edge cases (Rimefrost 30 → Festival 1, Festival 5 →
Thawing 1 of next year, day-clamping when landing in the festival),
negative offsets, tickOfDay preservation, day-of-week stability,
and life-stage boundaries.
|