maeul-in-the-sky
v2.1.0
Published
Build an animated isometric village from your GitHub contributions
Maintainers
Readme
Maeul in the Sky
Build a living isometric village from your GitHub contributions.
Open the SVG village studio · 3D tour · Day · Night · Quick start · Showcase
Maeul (마을) means “village” in Korean. Each day in your Contribution Calendar becomes part of a floating Terrain: quiet days form water and open land, while active days grow forests, farms, villages, cities, and rare wonders.
The default experience is the animated diagonal SVG village shown above. The profile output is a pair of standalone SVG files, with no client-side JavaScript required. Choose Day or Night in the studio. Under README picture, follow the viewer’s GitHub theme automatically or keep either appearance fixed. Motion respects reduced-motion preferences.
Prefer the original artwork? Choose Classic in the SVG studio. It uses the preserved pre-upgrade renderer, and its setup workflow pins 05a10eff07575acf2c81adcd66a66bc501507217 so future updates do not change that design.
Version 2.1.0 adds a walkable 3D Calendar village, detailed external wildlife and scenery, improved map navigation, and readable day details. The original animated calendar remains the default; the geographic landscape experiment is archived separately. See the release notes.
Migrating from 1.x: when constructing ContributionData manually, set stats: computeStats(weeks) to include the four new required statistics fields. Regenerated scenes use layout version 3 and updated artwork; saved version-1 and version-2 prepared scenes remain supported.
What your village includes
- Deterministic isometric Terrain with 100 elevation levels
- Four calendar-aligned seasons with distinct foliage, silhouettes and material colors
- Procedural rivers, ponds, forests, weather, and ambient animation; miniature ground textures, flowing currents and waterfalls spilling beneath the sky island
- 210 ordinary asset IDs: 197 classic and 13 Korean, with 68 seasonal and 142 year-round IDs
- 30 discoverable Epic Wonders across Rare, Epic, and Legendary tiers, with collection badges for discoveries in the displayed landscape
- Refreshed artwork plus 9 Korean rural and 8 nature additions: 240 catalog IDs in total
- Nature-led compositions with sparse architecture, varied water scenery and three silhouettes per new nature asset
- Independent miniature/pixel artwork and daily rewards based on raw contribution counts
- Seasonal consistency effects earned through active days in the trailing 28-day window
- Dark and light SVGs with accessible titles, descriptions, and reduced-motion support
- Northern and Southern Hemisphere season mapping
- Visible contribution range, active days, streaks, busiest month, and Wonder count
- Banner/card layouts, full/subtle/off motion, static PNG, and a zoomable browser explorer
- Versioned settings, contribution snapshots, multi-year comparisons, and local authenticated preview
- An Activity dashboard directly in the SVG studio, with contribution trends, weekday activity and monthly commit/PR charts when the imported snapshot includes them
The README previews and six preset images use seeded synthetic data, with 364 supplied days from 2025-01-05 to 2026-01-03. They are examples, not a fetched account or a complete 2025 calendar. Sparse and maximum previews use separate seeded patterns; the original benchmark fixtures remain frozen for reproducible comparisons.
Walk inside your Calendar village
The 3D tour opens the same dated Calendar as a Three.js miniature, with English menus and locally hosted wildlife, trees, buildings, props and selected Wonder models. The default tour is clearly labeled sample data.
- Walk with WASD, turn in place with Q/E or the left/right arrows, and drag to look around. Touch movement and turning controls are also available.
- Click the map or, while walking, the visible terrain to jump to nearby safe ground. The translucent map has square tiles, docks at either bottom corner, and accompanies a compass that follows your viewing direction.
- Explore seasonal viewpoints, take a guided flight, or choose day, golden-hour or night lighting. Animated wildlife, wind and water respect reduced motion. Day details use an opaque panel and hide the overview text while open.
The local library includes 24 animal species and 65 GLB files. The 3D asset credits identify each model's creator, license and adaptations. The complete coverage ledger accounts for all 240 catalog IDs: 95 use external models, 31 combine them with existing details, and 114 retain their designs. Generated terrain, water, paths and ambient effects keep their Calendar behavior. Asset files and attribution are included in both the Pages demo and the packaged preview; the tour does not download models from a runtime CDN.
For your own village, enable snapshot output in the Action step and commit the generated maeul-in-the-sky.snapshot.json alongside your SVGs:
- uses: t1seo/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
write_snapshot: 'true'Replace USERNAME in this tour URL with your GitHub username:
https://t1seo.github.io/maeul-in-the-sky/tour/?snapshot=https%3A%2F%2Fraw.githubusercontent.com%2FUSERNAME%2FUSERNAME%2Fmain%2Fmaeul-in-the-sky.snapshot.jsonThe example uses the Quick start's main branch. Studio-generated workflows publish to output; adjust the snapshot URL to your actual publication branch and file path.
Wrap your existing README <picture>…</picture> in an <a href="TOUR_URL">…</a>. GitHub displays the original SVG; clicking opens the interactive tour on Pages. Both theme-specific image sources stay the same. Visit a real profile village.
The tour preserves the snapshot's dates, contribution counts, placement IDs, seasonal water and earned Wonders. Meshes reinterpret the original artwork in three dimensions; it does not add unearned homes or Wonders. Some land is separated by water, so the map and seasonal viewpoints provide access where walking cannot. Public HTTPS snapshots on GitHub Pages or raw GitHub are supported, up to 2 MiB and an 800-day span. Invalid sources show an error instead of substituting a sample.
Choose a village preset
Try each preset in the SVG studio, with day and night previews of the same landscape.
Presets change the mix of extra decorations. They do not change contribution counts, elevation, colors or daily reward tiers.
| Nature | Balanced | Civilization |
| :----------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------: |
| |
|
|
| Light decoration and open space | Balanced scenery details | Richer decoration on active days |
|
preset: nature | preset: balanced | preset: civilization |
Archived experiments
The 2D island maps, 3D worlds, monthly archipelago, annual island, four seasonal islands, circular island, waterfalls and 3D profile captures are preserved as archived experiments. They are outside the default SVG experience. Existing saved worlds and shared links remain usable.
Open Archive · 3D & island experiments at the bottom of the studio, or read the archived world guide. The optional 3D capture Action remains available for existing integrations; normal profile setup generates SVGs.
Quick start
1. Add the Action
For a GitHub profile, use the repository whose name matches your username. Add .github/workflows/maeul-sky.yml:
These examples pin @v2.1.0. Use @v2 to follow compatible updates; @v1 remains on the previous major. For immutable runs, pin the full commit SHA you have tested.
name: Update Maeul in the Sky
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
contents: write
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: t1seo/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
preset: balanced
- uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: 'chore: update Maeul in the Sky'The repository owner is used as the GitHub username. Set username explicitly when the Terrain should represent someone else.
2. Run it once
Open Actions → Update Maeul in the Sky → Run workflow. The first run creates:
maeul-in-the-sky-dark.svgmaeul-in-the-sky-light.svg
If the commit step is denied, open Settings → Actions → General → Workflow permissions and allow read and write permissions.
3. Add it to your README
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./maeul-in-the-sky-dark.svg" />
<source media="(prefers-color-scheme: light)" srcset="./maeul-in-the-sky-light.svg" />
<img alt="My GitHub contribution village" src="./maeul-in-the-sky-dark.svg" width="100%" />
</picture>Action reference
| Input | Description | Default |
| ---------------- | -------------------------------------------------------- | --------------------------- |
| username | GitHub user whose Contribution Calendar is used | Repository owner |
| github_token | Token used for the GitHub GraphQL API | ${{ github.token }} |
| theme | Theme renderer | terrain |
| title | SVG title | @username |
| output_dir | Directory for both SVG files | ./ |
| year | Calendar year; omit for the rolling last 52 weeks | Rolling 52 weeks |
| hemisphere | Seasonal mapping: north or south | north |
| preset | nature, balanced, or civilization | balanced |
| density | Extra decoration mix override from 1 to 10 | Preset value |
| config | Version-1 settings JSON path | None |
| input | Snapshot JSON path; skips the network request | None |
| write_snapshot | Write a reusable snapshot: true or false | false |
| motion | full, subtle, or off | full |
| layout | banner or card | banner |
| village_style | Cultural style: classic or korean | classic |
| art_style | Artwork: miniature or pixel, independent of culture | miniature |
| layout_seed | Optional deterministic layout override | Username/year/date identity |
| normalization | relative, fixed, or shared for multi-year archives | relative |
| max_count | Positive fixed-scale maximum; requires fixed | None |
| format | svg, png, or both | svg |
| scale | Static PNG scale from 1 to 4 | 2 |
| years | Two to five distinct comma-separated years | None |
Outputs: dark_svg_path and light_svg_path contain the default generated paths. Optional and archive runs also expose dark_png_path, light_png_path, snapshot_path, archive_path, comparison_dark_svg_path, and comparison_light_svg_path when applicable.
Common customizations
- uses: t1seo/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
username: octocat
preset: nature
village_style: korean
art_style: pixel
hemisphere: south
title: 'Octocat’s coding village'Use density from 1 to 10 to vary extra scenery. The visible effect depends on available space and daily growth stages. It does not lower daily reward tiers or remove a positive day's guaranteed primary asset.
How Terrain Generation works
Height keeps the default relative scale: the positive-count P90 and a square-root mapping produce levels 1–99, while zero stays 0. fixed uses your maxCount instead. Daily growth is separate and uses the original Contribution Calendar count, not just commits, normalized height or density.
| Daily contribution count | Reward tier | | ------------------------ | ----------- | | 0 | 0, no reward | | 1–4 | 1 | | 5–9 | 2 | | 10–24 | 3 | | 25–49 | 4 | | 50+ | 5 |
Every positive day receives a primary asset, or a Wonder in its place, plus a visible tier marker. Lower tiers favor nature; higher tiers use more developed silhouettes suited to the culture and Biome. The marker remains when a Wonder occupies the date. For example, with fixed maximum 20, counts 25 and 50 share the maximum height but retain tiers 4 and 5.
These tiers are visual rewards, not GitHub classifications or code-quality scores. Raising a day's count cannot lower its tier. Other dates, normalization and density cannot change that tier; the whole random scene, extra decorations and global Wonder selections are not guaranteed to grow monotonically.
Counts determine terrain height. Supplied dates keep their actual UTC weekday and Sunday-based week, including partial weeks and gaps. Missing dates remain absent; known zero-count dates remain real zero days. Decorations never add contributions.
Epic Wonders
High-activity Terrain can reveal one of 30 special landmarks:
- Rare (14): Mount Fuji, Giant Sequoia, Colosseum, Coral Reef, and more
- Epic (10): Aurora, Taj Mahal, Glacier Peak, Bioluminescent Pool, and more
- Legendary (6): Floating Island, Dragon Nest, World Tree, Ancient Portal, and more
Wonder selection considers the cell’s activity, the richness of nearby cells, and overall contribution statistics. Up to three Wonders are placed with spacing rules so they remain meaningful and readable.
The SVG's Village collection panel shows badges for unique Wonder types actually present in the displayed landscape, plus earned seasonal effects. Duplicate Wonders count once; uncollected types stay undiscovered. These badges describe the current period, rather than a saved lifetime inventory. Open the Wonder encyclopedia in the demo to browse all 30 types and their eligibility rules. Discovery remains deterministic for the same data and settings; refreshing or switching Day/Night does not reroll it.
Explore and set up
Open the demo to choose a preset, username/year/title and hemisphere. Controls cover density, motion, banner/card, classic/Korean culture, miniature/pixel artwork, height scale and layout seed. Culture and artwork are independent; either culture supports both art styles. Changing sample settings does not fetch an account. Import a snapshot for actual counts, or use the local service below.
Select a date to inspect its count, reward tier, Biome and placements. The explorer displays source, exact dates, total, active days, streak and a height/season legend. Zoom supports +/−/reset, keyboard panning, Escape and focus return. The Wonder encyclopedia shows discovered/locked landmarks and their actual gates. Eligibility does not guarantee selection: spacing, neighboring terrain, chance and the maximum-three budget also apply.
The setup section downloads settings JSON, a workflow and a README snippet. Its workflow uses t1seo/[email protected] and publishes to the output branch; its snippet points there, as an alternative to the main-branch quick start above. Pin a tested full commit SHA if you need a fixed version. Only the publication job receives contents: write. Titles or layout seeds containing ${{ cannot be exported to a workflow because GitHub evaluates Actions expressions; they remain valid in images and JSON.
CLI
Node.js 20 or newer is required. The commands below run the published 2.1.0 CLI with npx.
git clone --branch v2.1.0 https://github.com/t1seo/maeul-in-the-sky.git
cd maeul-in-the-sky
npm ci
npx tsx scripts/pixel/generate.ts --check
npm run buildGITHUB_TOKEN="$(gh auth token)" npx [email protected] maeul-sky \
--user octocat --preset civilization --output ./terrain
npx [email protected] maeul-sky --input village.snapshot.json \
--layout card --village-style korean --art-style pixel --motion off --format both --scale 2 \
--write-snapshot --output ./terrain
GITHUB_TOKEN="$(gh auth token)" npx [email protected] maeul-sky \
--user octocat --years 2024,2025 --normalization shared --output ./archive| CLI flag | Action input | Values / behavior |
| --------------------------------- | ---------------- | -------------------------------------------------------------------------- |
| --user, -u | username | Account inferred from input/config; Action otherwise uses repository owner |
| --token | github_token | Generation token; explicit --token overrides GITHUB_TOKEN |
| --theme, -t | theme | terrain |
| --title | title | Default @username |
| --output, -o | output_dir | Default current directory |
| --year, -y | year | Calendar year; omit for rolling 52 weeks |
| --years | years | 2–5 distinct comma-separated years; conflicts with --year |
| --preset | preset | nature (density 2), balanced (5), civilization (9) |
| --density | density | Integer 1–10 |
| --hemisphere | hemisphere | north / south |
| --config | config | Settings JSON path |
| --input | input | Snapshot/archive JSON path; no network |
| --write-snapshot [path] | write_snapshot | CLI optional path; Action true/false; default off |
| --motion | motion | full / subtle / off |
| --layout | layout | banner (840×240) / card (420×360) |
| --style, --village-style | village_style | classic / korean |
| --art-style | art_style | miniature / pixel; independent artwork, default miniature |
| --normalization | normalization | relative / fixed / shared (archive only) |
| --max-count | max_count | Positive finite maximum; required with fixed, invalid without it |
| --layout-seed | layout_seed | Optional deterministic seed override |
| --format | format | svg / png / both; default svg |
| --scale | scale | Integer PNG scale 1–4; default 2 |
| --help, -h; --version, -V | — | CLI help/version |
Run npx [email protected] maeul-sky --help and npx [email protected] maeul-sky preview --help for this checkout. Invalid/conflicting options fail with field-specific errors.
Defaults remain terrain, balanced, density 5, north, classic, full, banner, relative P90 and a rolling range; artwork defaults to miniature. Render settings resolve in this order: explicit CLI/Action/UI field → loaded settings → selected preset defaults → library defaults. In single-render CLI/API calls, --config supplies loaded settings in preference to snapshot settings; they are not merged field by field. An explicit preset alone does not replace saved density. Omitted flags do not override saved settings. Format and PNG scale are output options, not saved render settings.
The default still writes maeul-in-the-sky-dark.svg and maeul-in-the-sky-light.svg. Optional output adds matching .png files and maeul-in-the-sky.snapshot.json. With --format png, SVG path results are empty strings. Additional Action outputs are dark_png_path, light_png_path, snapshot_path, archive_path, comparison_dark_svg_path and comparison_light_svg_path.
Local preview with your account
GITHUB_TOKEN="$(gh auth token)" npx [email protected] maeul-sky preview --port 4318Open http://127.0.0.1:4318/ and select Fetch contributions. The service binds loopback only and reads its token from the server environment. There is no browser token field: do not place tokens in links, JSON or forms. The static public demo imports JSON and never contacts your localhost service. Missing credentials produce an actionable error; upstream errors are sanitized. The local process caches account/year responses for five minutes, up to 32 entries.
Saved data, comparisons and privacy
Settings (kind: maeul-settings), snapshots (maeul-snapshot) and archives (maeul-archive) use schemaVersion: 1. Settings contain username, optional year and render settings. Snapshots add year, date/count/level weeks and source.kind (github, import, sample), with optional fetchedAt. Newly fetched snapshots also include optional activity metadata with validated monthly GitHub contribution breakdowns. Older snapshots remain valid without this metadata. Parsers recompute statistics, reject unsupported versions, duplicate/invalid dates and invalid counts/options, and limit imports to 2 MiB and 20,000 days across at most 20 snapshots.
The envelope stays at version 1. Settings save culture as style: classic | korean and artwork as artStyle: miniature | pixel; older settings without artStyle load as miniature. Both choices survive settings/snapshot imports, share links and archive generation.
Save current year stores a snapshot in this browser's local storage. Replacing a saved username/year requires confirmation. Compare 2–5 years of one account: the default pools positive counts across selected snapshots, takes their P90 and stores that common maximum as fixed normalization in the archive manifest. Equal counts then have equal levels/heights. An explicit fixed maximum overrides it; individual relative views remain available outside comparisons. CLI archives contain year directories with images/snapshots, archive.json and two vertically stacked maeul-in-the-sky-comparison-{dark,light}.svg files. Replay with --input archive.json; --normalization shared recomputes the pooled scale.
Settings links contain configuration, including username/title, but no counts, token or snapshot payload. They do not fetch the named account. Snapshots/archives contain daily counts and dates, may include monthly contribution categories, and may reveal private activity totals visible to your token; review them before sharing. Source labels record provenance, not cryptographic proof of GitHub origin. There is no tracking, account database or telemetry endpoint; the Activity dashboard reads your local snapshot. Network generation contacts GitHub directly; imports work offline. SVGs contain dates/counts, not repository names or contribution details, and no executable scripts or external resources.
Layout, motion and stable villages
Dark and light shade one prepared scene with matching geometry, ordinary assets and Wonders. New scenes emit layoutVersion: 3, using normalized username, optional layoutSeed and absolute dates for deterministic random identities. Existing version-1 and version-2 prepared scenes remain renderable; regenerating data uses version 3 and changes asset, biome and Wonder selection seeds. With fixed normalization and unchanged local context, overlapping interior dates retain terrain and ordinary placements when a rolling range shifts; screen positions move with the window. Relative P90 can change heights, neighbors can change eligibility, and the global Wonder budget can change selections. Different settings/ranges or layout versions need not produce identical pixels. Source timestamps do not affect placement.
Seasons follow real dates and hemisphere: spring flowers and new leaves, full summer foliage, autumn color and harvests, winter snow and bare branches. Seasonal material colors reinforce those silhouettes. Korean culture retains hanok, pavilion, stoneWall and onggi, adding choga, jangseung, sotdae, riceTerrace, koreanWatermill, hanokGate, kimchiGarden, stoneBridge and hanokEstate. Higher-tier ordinary rewards mix substantial natural scenery with sparse Korean rural architecture, with paths between eligible neighborhood buildings. Counts and Wonder gates stay unchanged.
Nature now appears throughout the reward ladder. New cedar groves, ancient oaks, wildflower meadows, bamboo thickets, lotus ponds, reed marshes, alpine rocks and willow ponds each have three geometric variants. Architecture and vessels remain occasional focal points. Candidate IDs are deduplicated after culture mapping, and absolute-date spatial variation reduces neighboring repeated silhouettes without using neighboring contribution counts.
Daily primary assets and consistency effects follow calendar seasons: December–February winter, March–May spring, June–August summer and September–November autumn in the north, shifted six months in the south. Terrain colors still blend gradually between seasons. Full motion adds drifting cherry petals, summer rain, falling autumn leaves and winter snowfall in their dated regions. These ambient weather effects are separate from earned seasonal collection badges.
Consistency rewards count positive-contribution days in the inclusive trailing 28 calendar days. At 5, 12 and 20 active days, seasonal petals, fireflies, leaves or frost gain detail. Only supplied dates count; metadata records observed days separately, so unavailable history is not mistaken for measured inactivity. At most 10 effect groups are displayed, anchored to active days. These are decorative rewards, not additional contributions or a claim of an unbroken streak; ordinary daily tiers remain 0/1/5/10/25/50. Off, subtle and reduced-motion output retain static reward shapes.
artStyle changes artwork while preserving selected IDs, dates, counts and reward tiers. The default miniature uses detailed SVG artwork; pixel uses compiled SVG paths on a logical 0.5 SVG-unit grid, with a limited palette whose colors still adapt to season and dark/light mode. Pixel asset rendering needs no runtime Resvg or external bitmap. The grid describes asset geometry, not physical screen pixels: scene fitting and external fractional scaling can soften edges or prevent exact pixel alignment.
Both banner and card retain the full supplied period. Card places larger statistics around fitted terrain. API width/height set display dimensions; layout sets the logical viewBox. SVGs retain accessible title/description. full enables ambient effects; subtle limits motion to slow clouds and gentle water; off omits CSS animations/keyframes and SMIL. Reduced-motion preference selects a visible static fallback. PNG always rerenders with motion: off, an opaque mode background and scale 1–4 (default 2); it is static. Node uses bundled resvg WASM and Noto Sans KR; browser export uses SVG/canvas, so rasterization and available fonts can differ.
JavaScript and browser API
Install the released package, including the Node and browser APIs:
npm install [email protected]Run this example as an .mjs file in the project where you installed the package:
import { generateTerrain, generateArchive } from 'maeul-in-the-sky';
const result = await generateTerrain({
username: 'octocat',
token: process.env.GITHUB_TOKEN,
preset: 'balanced',
layout: 'card',
style: 'korean',
artStyle: 'pixel',
motion: 'off',
format: 'both',
writeSnapshot: true,
outputDir: './terrain',
});
console.log(result.darkPath, result.lightPath, result.darkPngPath, result.snapshotPath);
await generateArchive({
username: 'octocat',
token: process.env.GITHUB_TOKEN,
years: [2024, 2025],
normalization: 'shared',
outputDir: './archive',
});The source build provides dist/lib.js (ESM), dist/lib.cjs (CommonJS) and dist/browser.js (portable ESM). The browser entry exports rendering, parsers, settings, snapshot/archive helpers, catalogs and TypeScript types without Node filesystem, token client or WASM rasterizer dependencies. Given JSON from your file input, import the built browser entry:
import {
parseSnapshot,
snapshotToContributionData,
renderTerrain,
prepareTerrainScene,
renderTerrainScene,
} from 'maeul-in-the-sky/browser';
export function renderSavedVillage(snapshotJson) {
const snapshot = parseSnapshot(snapshotJson);
const data = snapshotToContributionData(snapshot);
const options = {
...snapshot.settings,
style: 'korean',
artStyle: 'pixel',
layout: 'card',
motion: 'off',
};
const { dark, light, metadata } = renderTerrain(data, options);
const scene = prepareTerrainScene(data, options);
const inlineDark = renderTerrainScene(scene, 'dark', { namespace: 'profile-village' });
return { dark, light, metadata, inlineDark };
}renderTerrain returns SVGs and metadata covering dates, statistics, normalization and actual placements. TerrainScene is JSON-safe. Use distinct namespaces for multiple identical inline scenes. Portable and Node inputs accept style or villageStyle; conflicting aliases are rejected. Canonical v1 settings serialize as style. Types TerrainRenderOptions and TerrainSceneRenderOptions are exported. Existing Theme.render still returns only { dark, light }.
Custom Theme archive comparisons parse SVG and CSS locally, including namespace prefixes and character references. XML declarations and DOCTYPEs are removed when embedding each row. External DTDs and custom entities are not loaded; malformed XML or unsupported references raise InputValidationError before archive files are written. If adding prefixes makes reference values indistinguishable so a CSS attribute selector cannot preserve its original matches, the same error is raised before writing.
Local stylesheet selectors are restricted to their annual row so generic rules keep row-specific paint references. This is SVG composition, not a CSS encapsulation boundary: imported styles, global names such as keyframes and fonts, and selectors that depend on an external document retain their existing CSS semantics. Custom themes should keep those names unique and their styling self-contained.
Catalog and reproducible previews
The interactive catalog groups assets by domain, season and culture, with separate Wonder tiers and a miniature/pixel selector. It includes all 13 Korean IDs. Counts and SVG/PNG sheets come from the renderer registries: 210 ordinary IDs = 197 classic + 13 Korean; 68 are seasonal and 142 are year-round. 30 Wonders = 14 Rare + 10 Epic + 6 Legendary, counted separately, for 240 total IDs. Variants, art styles and instances do not increase ID totals.
After editing artwork, regenerate the compiled pixel assets. Check for drift before tests or builds, then regenerate the previews/catalog:
npx tsx scripts/pixel/generate.ts
npx tsx scripts/pixel/generate.ts --check
npx tsx scripts/generate-preview.ts
npx tsx scripts/generate-demo.ts
npx tsx scripts/generate-examples.ts
npx tsx scripts/generate-cases.ts
npx tsx scripts/generate-catalog.ts docs/demo/catalogGenerators use fixed seeds and UTC dates. The early-activity case supplies known zeros after five active weeks; it is not a partial import. Offline previews use guarded geometry/path optimization. The earlier optimization experiment saved 16.54–17.06% gzip on six captured SVGs, with small subpixel differences. Those measurements predate this artwork update; they do not measure its size, rendering speed or FPS. See measured rendering and SVG size for the historical inputs, rejected approaches and limits.
Troubleshooting
- Action publication denied: check the job's
contents: write, repository workflow permissions and branch protections. - Wrong account or dates: set
username/--userandyear/--year; a sample stays a sample until data is loaded. - No motion: check
motion, reduced-motion preference and the host's SVG policy. Static terrain remains visible. - Private activity missing: only counts visible to the supplied token are available.
- Import fails: use version-1 JSON, unique valid dates and nonnegative integer counts within the limits above.
- Local fetch fails: set
GITHUB_TOKENin the server environment and open its exact loopback URL.
See Support or open an issue.
Community
- Share a profile in the Showcase
- Read the contribution guide
- Report vulnerabilities through the security policy
- Follow the code of conduct
Support
License
Third-party 3D models retain their own licenses; see the model credits and license files.

