fuzzyworld

when-am-i / files / .claude / skills / new-calendar / SKILL.md

SKILL.md

6.9 KB · history · blame


name: new-calendar description: Author a new calendar region dataset file for "When am I?" end-to-end — research a place/people's calendar system(s) with sourced citations, draft the GeoJSON region polygon and eras with proleptic-Gregorian dates, choose the right converter (or descriptive-only), then validate, screenshot, and prepare a PR-ready contribution. Use when adding a calendar/region, contributing calendar data, or extending coverage to a new place or people.


Authoring a new calendar dataset

This skill walks you through creating one src/data/calendars/<slug>.json region file for the "When am I?" app, the way a careful contributor would. The app's framing is plural: "When am I?" is asked of a person, so a region's eras collect every valid answer a local could give — overlapping calendars at the same place and time are expected, not an error.

Read these first — they are the source of truth, defer to them over this skill: - src/data/calendars/SCHEMA.md — the human-readable field docs. - scripts/validate-data.mts — the authoritative machine-checkable schema. - src/utils/calendars.ts — which calendar strings are convertible (have a converter). - An existing file as a template, e.g. src/data/calendars/iran.json (two eras, two converters) or src/data/calendars/massachusett.json (descriptive-only + an anchorEvents "winters since" reckoning).

The one rule that overrides everything: never invent

This dataset is only as trustworthy as its sources. Do not invent events, moon names, era boundaries, dates, or polygons. Every era and every anchor event must trace to a real, citable source (Wikipedia is acceptable as the project's acceptance gate). If you cannot source a claim, leave it out and say so. When a fact is uncertain or contested, prefer the conservative version and note it in the description. If you find yourself guessing a date or a boundary, stop.

Workflow

1. Gather inputs

Ask the user (or confirm) the place and the people/polity — e.g. "the Mughal Empire", "Coast Salish around Puget Sound", "Joseon Korea". The answer is about whose reckoning it is, so be specific: "Algonquian" is a language family, not one calendar; pick the actual nation.

2. Research the calendar system(s) — with sources

For that place + people, determine: - Which calendar system(s) were used, and over which date ranges (era boundaries). Multiple eras are normal (e.g. a switch from a lunar to a solar civil calendar, or a Julian→Gregorian cutover). - Whose answer each is (usedBy), e.g. "court and civil administration", "Orthodox church", a specific people. - Real, dateable sources for each. Collect the URLs as you go.

Use WebSearch/WebFetch to research; cite what you actually read.

3. Choose the calendar string (convertible vs descriptive-only)

This is two independent gates (see plan.md, Q3): - Acceptance — a sourced wiki page is enough to include the calendar at all. - Convertibility — whether a deterministic epoch+rule yields a numeric local year. This is decided by src/utils/calendars.ts: - Convertible strings hit a converter there: Gregorian, Julian, and the Temporal-backed Islamic, Hebrew, Persian, Indian/Saka, Buddhist, Japanese, Ethiopic, plus the hand-rolled Chinese sexagenary cycle, Maya Long Count, French Republican calendar (year only, via a sourced lookup table — its year began at the Paris equinox, an observation, not a fixed rule), and the simple year-offset counts Dangi/Juche, ab urbe condita (AUC), and Seleucid era. Match an existing string exactly (the lookup is case/space-insensitive). - Descriptive-only — a calendar with no continuous numbered year (e.g. an observational lunar calendar). Use a clear calendar name; the engine shows the era's name/description/sources + the Gregorian reference year and a "no numbered year" note. Never mislabel a descriptive calendar as convertible. - If a genuinely new convertible system is needed, that's converter work in src/utils/calendars.ts (a Temporal calendarId if Intl supports it, else hand-rolled). Caveat: the Temporal chinese calendar is broken in @js-temporal/polyfill@0.5.1 (throws on every date) — that's why China uses a hand-rolled Chinese sexagenary cycle converter instead. Verify any new Temporal calendar actually converts before relying on it.

4. Draft the region polygon

GeoJSON Polygon (or MultiPolygon), coordinates as [lng, lat] (longitude first — easy to get backwards), outer ring closed (first position repeated as last), ≥4 positions. Keep it a reasonable approximation of the territory; the validator checks ranges (lng −180..180, lat −90..90) and closure, not accuracy — that's the reviewer's job against the screenshot. geojson.io is handy for drafting.

5. Add anchorEvents for descriptive-only calendars (optional)

For a calendar with no numbered year, an anchorEvents entry lets a local place you in time as "about N winters since <event>". Each event needs a name, a proleptic-Gregorian date, and at least one source — these must be real, documented events (e.g. the 1616–1619 New England epidemic), never invented.

6. Write the file

Match the shape of an existing file exactly. Dates (start/end, event date) are proleptic Gregorian YYYY-MM-DD; null start/end means open-ended; intervals are half-open [start, end) so a cutover date is the end of the old era and the start of the new one. Fill in usedBy, description, sources.

7. Validate, test, screenshot — make it PR-ready

Run, and fix anything that fails:

npm run validate:data                          # schema + geometry + dates
npm run test                                   # converter / engine tests still green
npm run gen:badges                             # refresh the "calendar data" count badge
npm run screenshot:calendar -- src/data/calendars/<slug>.json

The screenshot step pins a point inside the region at a representative date per era and captures the answer panel + shaded map into screenshots/calendars/<slug>/, so a reviewer can see a wrong polygon, an off-by-a-century era boundary, a miscategorized convertible/descriptive call, or a broken conversion. Attach these to the PR.

8. If you added or changed a converter

Add unit tests in src/utils/calendars.test.ts with a known date↔year pair, and update the convertible-calendars list in README.md and this skill's step 3.

Definition of done

Source
1---
2name: new-calendar
3description: Author a new calendar region dataset file for "When am I?" end-to-end — research a place/people's calendar system(s) with sourced citations, draft the GeoJSON region polygon and eras with proleptic-Gregorian dates, choose the right converter (or descriptive-only), then validate, screenshot, and prepare a PR-ready contribution. Use when adding a calendar/region, contributing calendar data, or extending coverage to a new place or people.
4---
5
6# Authoring a new calendar dataset
7
8This skill walks you through creating one `src/data/calendars/<slug>.json` region
9file for the "When am I?" app, the way a careful contributor would. The app's
10framing is plural: *"When am I?"* is asked of **a person**, so a region's eras
11collect **every valid answer** a local could give — overlapping calendars at the
12same place and time are expected, not an error.
13
14**Read these first** — they are the source of truth, defer to them over this skill:
15- `src/data/calendars/SCHEMA.md` — the human-readable field docs.
16- `scripts/validate-data.mts` — the authoritative machine-checkable schema.
17- `src/utils/calendars.ts` — which calendar strings are **convertible** (have a converter).
18- An existing file as a template, e.g. `src/data/calendars/iran.json` (two eras,
19 two converters) or `src/data/calendars/massachusett.json` (descriptive-only +
20 an `anchorEvents` "winters since" reckoning).
21
22## The one rule that overrides everything: never invent
23
24This dataset is only as trustworthy as its sources. **Do not invent** events,
25moon names, era boundaries, dates, or polygons. Every era and every anchor event
26must trace to a real, citable source (Wikipedia is acceptable as the project's
27*acceptance* gate). If you cannot source a claim, leave it out and say so. When a
28fact is uncertain or contested, prefer the conservative version and note it in
29the `description`. If you find yourself guessing a date or a boundary, stop.
30
31## Workflow
32
33### 1. Gather inputs
34Ask the user (or confirm) the **place** and the **people/polity** — e.g. "the
35Mughal Empire", "Coast Salish around Puget Sound", "Joseon Korea". The answer is
36about *whose* reckoning it is, so be specific: "Algonquian" is a language family,
37not one calendar; pick the actual nation.
38
39### 2. Research the calendar system(s) — with sources
40For that place + people, determine:
41- Which calendar system(s) were used, and over **which date ranges** (era
42 boundaries). Multiple eras are normal (e.g. a switch from a lunar to a solar
43 civil calendar, or a Julian→Gregorian cutover).
44- **Whose** answer each is (`usedBy`), e.g. "court and civil administration",
45 "Orthodox church", a specific people.
46- Real, dateable sources for each. Collect the URLs as you go.
47
48Use WebSearch/WebFetch to research; cite what you actually read.
49
50### 3. Choose the calendar string (convertible vs descriptive-only)
51This is **two independent gates** (see plan.md, Q3):
52- **Acceptance** — a sourced wiki page is enough to include the calendar at all.
53- **Convertibility** — whether a deterministic epoch+rule yields a numeric local
54 year. This is decided by `src/utils/calendars.ts`:
55 - **Convertible** strings hit a converter there: `Gregorian`, `Julian`, and the
56 Temporal-backed `Islamic`, `Hebrew`, `Persian`, `Indian`/`Saka`, `Buddhist`,
57 `Japanese`, `Ethiopic`, plus the hand-rolled `Chinese sexagenary cycle`,
58 `Maya Long Count`, `French Republican calendar` (year only, via a
59 sourced lookup table — its year began at the Paris equinox, an
60 observation, not a fixed rule), and the simple year-offset counts
61 `Dangi`/`Juche`, `ab urbe condita` (AUC), and `Seleucid era`.
62 Match an existing string **exactly** (the lookup is case/space-insensitive).
63 - **Descriptive-only** — a calendar with no continuous numbered year (e.g. an
64 observational lunar calendar). Use a clear `calendar` name; the engine shows
65 the era's name/description/sources + the Gregorian reference year and a
66 "no numbered year" note. Never mislabel a descriptive calendar as convertible.
67- If a genuinely new convertible system is needed, that's converter work in
68 `src/utils/calendars.ts` (a Temporal `calendarId` if Intl supports it, else
69 hand-rolled). **Caveat:** the Temporal `chinese` calendar is broken in
70 `@js-temporal/polyfill@0.5.1` (throws on every date) — that's why China uses a
71 hand-rolled `Chinese sexagenary cycle` converter instead. Verify any new
72 Temporal calendar actually converts before relying on it.
73
74### 4. Draft the region polygon
75GeoJSON `Polygon` (or `MultiPolygon`), coordinates as **`[lng, lat]`** (longitude
76first — easy to get backwards), outer ring **closed** (first position repeated as
77last), ≥4 positions. Keep it a reasonable approximation of the territory; the
78validator checks ranges (lng −180..180, lat −90..90) and closure, not accuracy —
79that's the reviewer's job against the screenshot. geojson.io is handy for drafting.
80
81### 5. Add `anchorEvents` for descriptive-only calendars (optional)
82For a calendar with no numbered year, an `anchorEvents` entry lets a local place
83you in time as "about N winters since &lt;event&gt;". Each event needs a `name`, a
84proleptic-Gregorian `date`, and **at least one source** — these must be real,
85documented events (e.g. the 1616–1619 New England epidemic), never invented.
86
87### 6. Write the file
88Match the shape of an existing file exactly. Dates (`start`/`end`, event `date`)
89are **proleptic Gregorian** `YYYY-MM-DD`; `null` start/end means open-ended;
90intervals are half-open `[start, end)` so a cutover date is the `end` of the old
91era and the `start` of the new one. Fill in `usedBy`, `description`, `sources`.
92
93### 7. Validate, test, screenshot — make it PR-ready
94Run, and fix anything that fails:
95```bash
96npm run validate:data # schema + geometry + dates
97npm run test # converter / engine tests still green
98npm run gen:badges # refresh the "calendar data" count badge
99npm run screenshot:calendar -- src/data/calendars/<slug>.json
100```
101The screenshot step pins a point inside the region at a representative date per
102era and captures the answer panel + shaded map into
103`screenshots/calendars/<slug>/`, so a reviewer can *see* a wrong polygon, an
104off-by-a-century era boundary, a miscategorized convertible/descriptive call, or
105a broken conversion. Attach these to the PR.
106
107### 8. If you added or changed a converter
108Add unit tests in `src/utils/calendars.test.ts` with a known date↔year pair, and
109update the convertible-calendars list in `README.md` and this skill's step 3.
110
111## Definition of done
112- `npm run validate:data` and `npm run test` pass.
113- Every era and anchor event is sourced; nothing is invented.
114- Convertible-vs-descriptive is correct and the conversion looks right in the
115 screenshot.
116- README's convertible-calendar list and the badge count are current.
117- **Do not commit.** Per repo policy, hand the file + screenshots to the human to
118 review against the sources, and let them commit.