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
npm run validate:dataandnpm run testpass.- Every era and anchor event is sourced; nothing is invented.
- Convertible-vs-descriptive is correct and the conversion looks right in the screenshot.
- README's convertible-calendar list and the badge count are current.
- Do not commit. Per repo policy, hand the file + screenshots to the human to review against the sources, and let them commit.