A Chromatic Atlas of Cities
Chromapolis is a FLOSS, privacy-respecting web app for exploring city color palettes. The current milestone is a lightweight public demo: a static Vite + React + TypeScript application that loads auditable city records from plain JSON and renders palette exports in the browser.
- Version:
0.1.0, with the app moving through a focusedv0.4 Dataset Expansion + Palette Methodologyslice. - App shape: static-first frontend only; no backend, login, analytics, or heavy map library.
- Dataset: manifest-driven city records in
data/cities/with runtime validation before records are exposed to the UI, plus palette completeness guidance for Minimal, Standard, and Complete records. - UI: available city records can be searched/selected locally, selected from a lightweight SVG/CSS visual atlas, and viewed in the palette panel.
- Exports: JSON, city-scoped CSS variables, GPL palette text, HEX copy, and a clearly labeled plain-text ASE placeholder are available from the palette panel.
- Open source and maintainable
- Privacy by default (no tracking, no analytics, no login)
- Human-auditable dataset formats in plain text
- Accessible and readable interface
- Local-first friendly architecture
- Static hosting friendly for GitHub Pages
.
├── data/
│ └── cities/
│ ├── city.schema.json
│ ├── index.json
│ └── <city>-<country>.json
├── src/
│ ├── components/
│ ├── lib/
│ ├── pages/
│ └── types/
├── index.html
├── package.json
└── vite.config.ts
Install dependencies:
npm installStart the Vite development server:
npm run devThen open the local URL printed by Vite, usually http://localhost:5173.
Create a production build:
npm run buildThe build runs TypeScript project checks first (tsc -b) and then writes the
static site to dist/ with Vite.
Preview the built site locally:
npm run previewBecause the public demo is configured for GitHub Pages under
/chromapolis/, the Vite base path is set to that repository path in
vite.config.ts.
This repository includes a GitHub Actions workflow at
.github/workflows/pages.yml that:
- checks out the repository,
- installs dependencies with
npm ci, - runs
npm run build, - uploads
dist/as a Pages artifact, and - deploys it to GitHub Pages.
Manual repository settings still required:
- In GitHub, open Settings → Pages for
sigilabcodex/chromapolis. - Set Build and deployment → Source to GitHub Actions.
- Ensure Actions are enabled for the repository.
- Push to
mainor run theDeploy to GitHub Pagesworkflow manually.
Once deployed, the site should be served from the repository Pages URL using the
/chromapolis/ base path.
- TypeScript model:
src/types/chromapolis.ts - JSON schema:
data/cities/city.schema.json - Dataset manifest:
data/cities/index.json - Example city record:
data/cities/lisbon-pt.json
The app uses the manifest to load city JSON files and validates each city record at runtime. Invalid or missing records are skipped and reported through loader diagnostics in the UI and browser console.
ChromaPolis supports variable-length palettes because cities do not all have the same evidence, visual complexity, or design need. A careful three-color starter is better than a nine-color record padded with weak claims.
Recommended curated palette sizes:
- Minimal: 1–3 colors — cautious starter records, single dominant identity cues, or cities needing better sourcing.
- Standard: 4–6 colors — useful working palettes with primary identity plus natural, material, cultural, or accent layers.
- Complete: 7–9 colors — mature records with multiple defensible layers and enough range for design-system use.
Not every city must have 9 colors. A palette is “complete” when its colors cover multiple well-rationalized layers rather than when it simply reaches the maximum recommended size.
-
Start from
docs/city-record-template.md, then create a new JSON file indata/cities/using the naming pattern<city>-<country>.json, for exampleporto-pt.json. -
Match the structure in
data/cities/city.schema.json:- stable lowercase
slug, - city and country metadata,
- coordinates,
- one or more palette colors; the schema allows palettes from 1 color upward, and the recommended editorial range is 1–9 colors using Minimal, Standard, and Complete completeness labels,
- one or more source references,
- an
editorialSummary.
- stable lowercase
-
Add the file to
data/cities/index.json:{ "slug": "porto", "countryCode": "PT", "file": "porto-pt.json" } -
Run
npm run buildto confirm the manifest entry and city record pass the existing TypeScript/Vite build. Loader diagnostics will also report malformed records when the app runs. -
Keep records human-reviewable: cite sources, distinguish official colors from editorial interpretation with the
officialflag, and use confidence and prominence values to document uncertainty. Do not mark a color official unless an authoritative source supports that status; otherwise keep it editorial, symbolic, architectural, cultural, historical, or natural as appropriate.
- The first atlas is a static SVG/CSS world-plane scatter view, not a geographic
map engine. It projects each record's
coordinates.latandcoordinates.lononto a simple equirectangular plane so the app stays static-hosting friendly, privacy-respecting, and dependency-light. - The atlas is intended as orientation and palette browsing, not as a precise cartographic product. Future PRs can improve projection details, collision handling, or optional map layers without changing the data model.
- JSON, city-scoped CSS variables, GPL palette text, HEX copy, and the ASE text placeholder are generated from the full palette array, so variable-length palettes are preserved.
- CSS exports use city-scoped variable names such as
--chromapolis-lisbon-1-limestone-creamto make pasted palettes safer in multi-city design systems. - The ASE control currently downloads a plain-text
.ase.txtplaceholder only; it is intentionally labeled as a placeholder until real binary Adobe Swatch Exchange generation is implemented.
npm run dev– start local development servernpm run build– type-check and create production buildnpm run preview– preview the production build locally
This repository currently includes a LICENSE file.
If you decide to revisit licensing, good options for this type of project include:
- MIT (very permissive)
- Apache-2.0 (permissive with explicit patent grant)
- GPL-3.0-or-later (strong copyleft)
Choose based on your contribution and redistribution goals.