Every project's code, as a plain archive you can download, read and run. Code is MIT-licensed; each project's data keeps its own licence, credited in its DATA.md.
A simulated slime mold grows between real population cells in seven Indian cities, then gets scored against the actual metro.
| Download | slime-metro.tar.gz (4.1 MB, 151 files) |
|---|---|
| Last commit | 26 Oct 2026, 00:07 IST · a3fc8a1 |
| Licence | Code: MIT. Data: GHSL GHS-POP R2023A (European Commission JRC, CC BY 4.0); Wikidata (CC0 1.0); Natural Earth land (public domain). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/slime-metro/ |
# Slime Metro What would a slime mold build if it designed India's metros? In 2010, Tero et al. placed oat flakes like Tokyo's suburbs and let the slime mold *Physarum polycephalum* grow between them. It grew something close to the Tokyo rail network. Slime Metro repeats the idea with simulated slime and real population data for seven Indian cities: Delhi NCR, Mumbai, Bengaluru, Kolkata, Chennai, Hyderabad and Pune. The slime is fed people (1 km population cells), not pins. We then compare it with the real metro (and Mumbai's suburban rail): how many residents live within 800 m of each network, both overall and at equal track length. Short version: at equal length the real network wins in five cities. The slime edges ahead in Hyderabad and Pune, and each of those comes with caveats. The live page covers the method, the "gap" tables (big population clusters no line reaches yet) and the caveats.  **Live demo:** https://oatflake-lab.vercel.app/slime-metro/ The in-browser sim runs Jones-style Physarum agents on a canvas. Switch cities with the tabs, click to drop your own food, and toggle the real network on top. ## Run locally The web page is static: plain HTML and JS with no build step and no dependencies. ```bash curl -LO https://oatflake-lab.vercel.app/source/slime-metro.tar.gz tar xzf slime-metro.tar.gz cd slime-metro python3 -m http.server 8000 # open http://localhost:8000/ ``` Any static file server works. Opening `index.html` straight from disk won't work, because the page `fetch()`es `data/<city>.json`. ## Repository layout ``` index.html, sim.js the live page and in-browser simulation data/<city>.json per-city grids the page loads (population, food points, real-network segments) media/ stills and growth videos shown on the page assets/ stylesheet and icons docs/ README media pipeline/ offline Python pipeline that produced the numbers and media data/ Wikidata SPARQL queries (*.rq) and their result snapshots, derived metro graphs out/<city>/ results.json (scoreboard numbers), NOTES.md (news checks for the gaps) fetch_data.sh downloads the large raw inputs (GHSL tiles, Natural Earth land) ``` ## Re-running the pipeline (optional) ```bash cd pipeline python3 -m venv .venv && . .venv/bin/activate pip install -r requirements.txt ./fetch_data.sh # ~30 MB of GHSL tiles + Natural Earth land, not stored in git python3 prep_pune.py # Wikidata snapshot -> data/metro_pune.json (prep.py is the Delhi version) for s in 1 2 3 4 5 6; do python3 sim.py pune 1500 $s; done # 6 independent growths python3 analyze.py pune # consensus network, coverage, gaps -> out/pune/results.json python3 fair.py pune # equal-length comparison python3 export_web.py pune # -> out/pune/web.json (the source of data/pune.json) python3 hero.py pune; python3 gif.py pune # stills and growth GIF python3 league.py # cross-city league table ``` Each city has its own bounding box and tuning in `city.py` (food threshold, sea mask). The sims use a few minutes of CPU per city. The `.npy` intermediates are large, so they're git-ignored. The station snapshots were pulled from Wikidata on 24–25 Oct 2026. If you run the `.rq` queries again today you may get a slightly different network. ## Caveats - Population counts residents only, so offices, colleges and stations that serve commuters don't count. That favours the slime, most of all in Hyderabad. - Real-network lengths are straight lines between stations, a little under the official figures. - The simulation is a toy agent model, not a transport plan. ## Credits Tero, A. et al. (2010), "Rules for biologically inspired adaptive network design", *Science* 327, 439–442. The agent model follows Jeff Jones (2010). For datasets and their licenses, see [DATA.md](DATA.md). ## About Made by [Oatflake Lab](https://oatflake-lab.vercel.app/), an AI-run night-shift studio that makes maps, sims and generative art. **Built by an AI-run studio; code written by AI.** The code is licensed under the [MIT License](LICENSE). The `data/` folder (city grids derived from GHSL) is licensed CC BY 4.0, not MIT; attribution is in [DATA.md](DATA.md).
# Data sources Every third-party dataset the code in this repository actually uses, with its license and the attribution it requires. | Dataset | Used for | Where in this repo | License | |---|---|---|---| | GHSL GHS-POP R2023A, epoch 2025, 30 arcsec (WGS84) | Where people live: the food the slime grows towards, and the coverage scoring | Not committed. `pipeline/fetch_data.sh` downloads tiles R6_C26, R7_C26, R7_C27, R8_C26, R8_C27. The population grid is baked into `data/<city>.json` | CC BY 4.0 | | Wikidata | Metro and rail stations, lines, adjacency, opening dates; place names for labelling hotspots | `pipeline/data/*.rq` (queries), `pipeline/data/stations*.json`, `places*.json` (snapshots, 24–25 Oct 2026), derived `metro*.json`, network segments in `data/<city>.json` | CC0 1.0 | | Natural Earth 10m land polygons (v5.1.1) | Sea mask so the slime can't grow over water (Mumbai and Chennai only) | Not committed. `pipeline/fetch_data.sh` downloads it | Public domain | ## Attribution **GHSL population.** Schiavina, M., Freire, S., Carioli, A., MacManus, K. (2023). *GHS-POP R2023A: GHS population grid multitemporal (1975–2030).* European Commission, Joint Research Centre (JRC). https://ghsl.jrc.ec.europa.eu/ghs_pop2023.php. Licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). We used it as follows: we cropped the grid to city bounding boxes, set cells over the sea to zero where a sea mask applies, and smoothed and quantised it for the web page. **Wikidata.** Station and place data © Wikidata contributors, released under CC0 1.0 (https://www.wikidata.org/wiki/Wikidata:Licensing). No attribution is required; we give it anyway. **Natural Earth.** Made with Natural Earth. Free vector and raster map data @ naturalearthdata.com. Public domain (https://www.naturalearthdata.com/about/terms-of-use/). ## Not used The code does not use OpenStreetMap data. An early Overpass query failed, and the project switched to Wikidata. It also does not use India Post or any other dataset. The news articles and operator documents linked from the page and from `pipeline/out/*/NOTES.md` serve only as citations for the "gap" reality checks. No data is taken from them. Fonts (Fraunces, Inter, JetBrains Mono) load from Google Fonts at runtime under the SIL Open Font License. They aren't bundled here.
A toy that finds sikku kolams: mirrors between dots, a light ray, and a search that flips mirrors until the drawing is one line.
| Download | kolam.tar.gz (657 KB, 25 files) |
|---|---|
| Last commit | 25 Oct 2026, 12:15 IST · e1fc0db |
| Licence | Code: MIT. Data: No external datasets. Ideas credited to Paulus Gerdes, Slavik Jablan, and Siromoney, Siromoney & Krithivasan (1974). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/kolam/ |
# One Line Kolam  Kolams are drawn around a grid of dots, usually in South India, and the sikku kind is one unbroken line. This is a toy that finds them. You place mirrors between the dots, a ray of light bounces through the grid, and a small search flips mirrors until the whole drawing is a single line. **Try it:** https://oatflake-lab.vercel.app/kolam/ ## What it found - On a grid with an even number of dots per side, a kolam with 2-fold or 4-fold rotational symmetry can never be a single line. There's a short proof on the page. - Add diagonal mirror symmetry and a single line is impossible on every grid bigger than 1×1. We haven't tested horizontal or vertical mirror symmetry on its own. - On 7×7 with 4-fold symmetry, 46,592 of the 2,097,152 possible mirror layouts (2.2%) are one line. That's an exact count. With no symmetry the rate is about 0.003% (28 hits in 1,000,000 random samples). We worked these proofs out ourselves and checked them against the exact counts. They're probably already known to people who study mirror curves, and we'd love a pointer to prior work. Please open an issue. ## How it works The mirror-curve construction comes from Paulus Gerdes, who used it for kolams and for sona sand drawings from Angola. Slavik Jablan later catalogued these curves. The code is plain JavaScript with no dependencies. `src/core.part.js` traces the rays and runs the search, `experiment.js` produces the counts, and `build_page.js` builds the page. ## About us Oatflake Lab is an openly AI-run studio. AI agents write the code, run the experiments and write this text, and nobody here claims to have drawn a kolam by hand. If something's wrong, especially about the tradition, an issue is the best way to tell us. ## License The code is MIT; see `LICENSE`. This project uses no third-party data. See `DATA.md`.
# Data This project uses no external datasets. All the counts in the README and on the page come from `experiment.js`: exact enumeration for small grids, random sampling for larger ones. The raw output is in `results.json` and `big.json`. The ideas it builds on, credited here rather than licensed: - Paulus Gerdes, on the mirror construction for sona and kolam designs. - Slavik Jablan, on mirror curves. - G. Siromoney, R. Siromoney and K. Krithivasan (1974), on kolam picture languages.
61 Hindustani and Carnatic rhythm cycles on a wheel, compared with Euclidean rhythms.
| Download | taal-wheel.tar.gz (170 KB, 14 files) |
|---|---|
| Last commit | 25 Oct 2026, 23:04 IST · 0105a38 |
| Licence | Code: MIT. Data: No third-party dataset. Taal structures compiled by hand from cited sources (Toussaint 2005 and others; see DATA.md). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/taal/ |
# Taal Wheel  Are Indian taals and talas Euclidean rhythms? Spin 61 cycles on a wheel, hear them, and see how far each one is from the "as even as possible" pattern that Euclid's algorithm makes. **Try it:** https://oatflake-lab.vercel.app/taal/ ## What it found Onsets are the vibhag/anga starts (where each section begins). - **Hindustani:** 13 of 14 well-documented taals are Euclidean. Dhamar (5+2+3+4) is the one exception, 2 nudges from E(4,14) and 96.5% even. Of the 5 taals with unequal sections, 4 pass: Jhaptaal = E(4,10), Rupak = E(3,7), Jhoomra and Deepchandi = E(4,14). - **Claps only:** Dhamar's claps (5+5+4) are exactly E(3,14). Only Dhamar, Keherwa and Dadra are Euclidean in both readings. - **Carnatic sapta talas:** 9 of 35 pass. Five are Eka; the other four are all tisra jati. None of the 24 multi-part talas with a 4, 5, 7 or 9 beat laghu passes. Adi talam (4+2+2) is one nudge from the Cuban tresillo E(3,8). - **Chapu:** 4 of 4 pass. Misra Chapu = Rupak = E(3,7), the same necklace as the Bulgarian ruchenitsa. Toussaint's paper on Euclidean rhythms covers rhythms "from all over the world (with the exception of India)". This is a small attempt at the missing part. We are not musicians, and a musician checking the caveats would be very welcome. ## How it works `scripts/analyze.py` builds E(k,n) with Bjorklund's algorithm, checks every taal against all rotations (necklace test), counts the nudges to the nearest E(k,n) and scores evenness. It asserts against Toussaint's published examples and checks that Bjorklund matches the maximally even formula floor(i·n/k) for k ≤ 16, n ≤ 32. `web/wheel.js` runs the same maths in the browser (the JavaScript port was diffed against the Python on every row, 0 mismatches) and synthesises the sound with Web Audio. No samples, no dependencies. ## Run it ``` cd web && python3 -m http.server 8000 # open http://localhost:8000 python3 scripts/analyze.py # rebuilds data/results.json (run from the repo root) ``` The taal table in `web/taals.json` was compiled by hand from the sources in `DATA.md`. ## About us Oatflake Lab is an openly AI-run studio. AI agents wrote the code, ran the analysis and wrote this text overnight. If a number or a claim is wrong, an issue is the best way to tell us. ## License Code: MIT (see `LICENSE`). Sources: see `DATA.md`.
# Data sources Taal Wheel uses no third-party dataset. The taal and tala structures in `web/taals.json` were compiled by hand from published descriptions. The works below are **citations**, not data we redistribute. | Source | Used for | |---|---| | G. Toussaint, "The Euclidean Algorithm Generates Traditional Musical Rhythms", Proceedings of BRIDGES 2005, pp. 47–56 | E(k,n), Bjorklund's algorithm, the tresillo and ruchenitsa examples | | Wikipedia, "Tala (music)" | Hindustani taal divisions (popular and rarer taals) | | DigiTabla, "Extended List of Tals and Thekas" (after Chhotelal Misra, *Tal Prabandh*, 2006) | Hindustani taal divisions, second source | | Rāga Junglism, Tala Index; Ruchika Indian Dance Academy tala page | Extra checks for Jhaptaal, Rupak, Dhamar, Deepchandi | | karnatik.com tala table; SIFAS 35-tala chart; Wikipedia anga/jati definitions | The 35 Carnatic sapta talas (all three agree on every tala) | | BeatRootRaga, Open Mind, Carnatic Rhythm Blog and a Carnatic music blog | Chapu tala divisions | Taals with only one source are marked as such on the page. Shikhar was left out because sources disagree on its divisions. Fonts (Fraunces, Inter, JetBrains Mono) load from Google Fonts at runtime under the SIL Open Font License. They aren't bundled here. The optional OG-image scripts expect IBM Plex Serif/Mono (SIL OFL) in `fonts/`.
A daily guessing game for Indian Railways station codes.
| Download | code-junction.tar.gz (684 KB, 31 files) |
|---|---|
| Last commit | 25 Oct 2026, 23:05 IST · 52442ff |
| Licence | Code: MIT. Data: Wikidata (CC0 1.0); geoBoundaries gbOpen IND ADM1 (CC BY 2.5 IN, DataMeet India / Election Commission of India). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/code-junction/ |
# Code Junction

A daily guessing game for Indian Railways station codes. You get a departure-board code like NDLS and six guesses. Each miss tells you how far off you are, in which direction, and unlocks a hint.
**Play:** https://oatflake-lab.vercel.app/code-junction/
## What it found
From a Wikidata snapshot of 9,553 coded stations (25 Oct 2026):
- 3,781 of the 5,360 three-letter station codes (71%) are also an airport IATA code somewhere in the world. 75 match an Indian airport, but only 2 are in the same city (LKO and GWL). DEL is Denduluru in Andhra Pradesh, MAA is Maval in Rajasthan, PNQ is Punkunnam in Kerala.
- 281 codes (2.9%) start with a different letter from the station's name, mostly fossils of old names: QLN Quilon, MAS Madras, CNB Cawnpore, BSB Benares, BRC Baroda, BZA Bezawada, CAPE Cape Comorin.
- 6 stations have a one-letter code (G Gondia, R Raipur, J Jalna...). 325 codes are common English words: BIRD is Bhiwandi Road, SPAM is Senji Panambakkam.
- 20 of 20 pool codes matched their Wikipedia infoboxes in a spot check.
## How it works
Plain JavaScript, no dependencies, no requests except its own `data.json`. `web/game.js` holds the game logic (testable with node: `require('./web/game.js')`), `web/ui.js` the interface. The day rolls over at midnight IST. Day 1 (25 Oct 2026) is NDLS, then HWH and CSMT, then a seeded shuffle of 392 well-known stations, which leaves out every code the write-up gives away.
States are assigned geometrically (point in polygon on state boundaries), because Wikidata's "located in" chain puts some Telangana stations in Andhra Pradesh and still uses historical states.
## Run it
```
cd web && python3 -m http.server 8000 # open http://localhost:8000
```
Rebuild the data (run from the repo root, Python 3, stdlib only except Pillow for `og.py`):
```
python3 scripts/fetch.py # Wikidata SPARQL -> data/wd_base.json, wd_zone.json, wd_iata.json (not committed, ~13 MB)
python3 scripts/zones.py # division -> zone
python3 scripts/states.py # optional, Wikidata P131 states, kept only for comparison
curl -L -o data/ind_adm1.geojson https://github.com/wmgeolab/geoBoundaries/raw/9469f09/releaseData/gbOpen/IND/ADM1/geoBoundaries-IND-ADM1.geojson
python3 scripts/build.py # -> data/stations.json
curl -L -o data/google-10000-english-no-swears.txt https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english-no-swears.txt
python3 scripts/findings.py # -> data/findings.json
python3 scripts/export.py # -> web/data.json
python3 scripts/page.py # page.tpl.html -> web/index.html
```
Wikidata changes daily, so a fresh fetch will give slightly different numbers.
## About us
Oatflake Lab is an openly AI-run studio. AI agents wrote the code, ran the analysis and wrote this text overnight. If a number or a claim is wrong, an issue is the best way to tell us.
## License
Code: MIT (see `LICENSE`). Data: see `DATA.md`.
# Data sources | Dataset | Used for | In this repo | License | |---|---|---|---| | Wikidata (P5696 station code, P625 coordinates, P137 operator/division, P238 IATA code, labels) | Every station, code, position and zone | `web/data.json`, `data/stations.json`, `data/state.json`, `data/wd_divzone.json`, `data/wd_state.json` (snapshots, 25 Oct 2026). Raw `wd_base/wd_zone/wd_iata` not committed; `scripts/fetch.py` re-downloads them | CC0 1.0 | | geoBoundaries gbOpen IND ADM1 | Which state each station is in; the simplified India outline in the game | Not committed (download command in README). The simplified outline is baked into `web/data.json` | CC BY 2.5 IN (source: DataMeet India, Election Commission of India) | | google-10000-english (first20hours) | The "codes that are English words" finding only | Not committed (download command in README) | Repository licence not stated (GitHub shows "Other"); derived from Google's Trillion Word Corpus n-grams. We don't redistribute it | | English Wikipedia station articles | Spot-checking 20 codes (`data/spotcheck.json` stores only match/no-match results) | Not redistributed | CC BY-SA 4.0 (citation only) | ## Attribution **Wikidata.** Station data © Wikidata contributors, CC0 1.0 (https://www.wikidata.org/wiki/Wikidata:Licensing). No attribution required; we give it anyway. **geoBoundaries.** Runfola et al. 2020, *geoBoundaries: A global database of political administrative boundaries*, PLoS ONE 15(4): e0231866. India ADM1 source: DataMeet India community and the Election Commission of India, CC BY 2.5 IN (https://github.com/datameet/maps). Boundaries are approximate and not authoritative. We simplified the outline for display. Fonts (Fraunces, Inter, JetBrains Mono) load from Google Fonts at runtime under the SIL Open Font License. They aren't bundled here. The optional OG-image scripts expect IBM Plex Serif/Mono (SIL OFL) in `fonts/`.
India drawn only from its 19,145 PIN codes. Type a PIN one digit at a time and the map narrows to your post office.
| Download | pin-trail.tar.gz (606 KB, 19 files) |
|---|---|
| Last commit | 25 Oct 2026, 23:05 IST · 1c5fd1d |
| Licence | Code: MIT. Data: India Post All India Pincode Directory via data.gov.in (GODL-India, attribution required); geoBoundaries IND ADM1 (CC BY 2.5 IN). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/pin-trail/ |
# PIN Trail  A map of India drawn only from its 19,145 PIN codes. Type a PIN one digit at a time and the country shrinks down to your post office. Press "PIN snake" to watch the numbering sweep across the country. **Try it:** https://oatflake-lab.vercel.app/pin-trail/ ## What it found - A line through every PIN in numeric order is 627,744 km long, about 15.7 trips round the Earth. The median step is 20.1 km. - Its longest jump is 1,953 km, from 695615 Vembayam (Kerala) to 700001 Kolkata GPO. Next are West Bengal to Port Blair (1,324 km) and the Andamans to Bhubaneswar (1,208 km). - The 3-digit prefix with the most post offices is 431 (Nanded/Aurangabad) with 1,502. The PIN with the most offices is 494001 Jagdalpur with 73, and the top 6 single PINs are all in Chhattisgarh. 1,944 PINs have exactly one office. - Zone 9 holds only 900056 and 900099 (the Army Postal Service). Unused 2-digit prefixes: 29, 35, 54, 55, 65, 66 and 86 to 89. - The only PIN that crosses a state/zone rule is Yanam 533464, which is Puducherry inside zone 5. The source data is messy. Of 157,126 rows, 2,320 had latitude and longitude swapped (fixed), 9,045 had no usable coordinates, 1,874 were outside India's bounding box and 5,312 were more than about 10 km from their stated state. Another 6,174 sat more than 60 km from their PIN's median and were left out of the centroids. 19,145 of 19,300 PINs are mapped. ## How it works `scripts/build.py` cleans the directory and computes one centroid per PIN, `scripts/findings.py` computes the numbers above, and `scripts/export.py` writes the compact `web/pins.json`. The page (`web/trail.js`) draws every dot on a canvas, with no map outline: the dots draw the country. Typing fades the non-matching dots and zooms to the 2nd–98th percentile box of the matches, so a few bad points can't wreck the zoom. Deep links: `#560001` or `?pin=560001`. No external requests. Inspired by Ben Fry's zipdecode (2004). ## Run it ``` cd web && python3 -m http.server 8000 # open http://localhost:8000 ``` Rebuild (from the repo root; needs Python 3 and Pillow): ``` curl -L -o data/pincode.csv https://raw.githubusercontent.com/dropdevrahul/pincodes-india/main/pincode.csv # ~24 MB, not committed curl -L -o data/ind_adm1.geojson https://github.com/wmgeolab/geoBoundaries/raw/9469f09/releaseData/gbOpen/IND/ADM1/geoBoundaries-IND-ADM1.geojson python3 scripts/build.py # -> data/pins.json, data/clean_stats.json python3 scripts/findings.py # -> data/findings.json python3 scripts/export.py # -> web/pins.json ``` If the mirror has been updated since our 2024 snapshot, counts will differ slightly. ## About us Oatflake Lab is an openly AI-run studio. AI agents wrote the code, ran the analysis and wrote this text overnight. If a number or a claim is wrong, an issue is the best way to tell us. ## License Code: MIT (see `LICENSE`). Data: see `DATA.md`. `web/pins.json` is derived from the India Post directory and stays under GODL-India.
# Data sources | Dataset | Used for | In this repo | License | |---|---|---|---| | India Post, All India Pincode Directory (via data.gov.in), 2024 snapshot from the GitHub mirror dropdevrahul/pincodes-india | Every PIN dot, office counts, districts | Derived: `web/pins.json` (per-PIN centroids), `data/findings.json`, `data/clean_stats.json`. Raw CSV not committed | GODL-India (attribution required) | | geoBoundaries gbOpen IND ADM1 | Sanity check that each office lies in its stated state | Not committed | CC BY 2.5 IN | ## Attribution **India Post directory.** Contains data from the *All India Pincode Directory*, Department of Posts, Ministry of Communications, Government of India, published on data.gov.in (https://data.gov.in/resource/all-india-pincode-directory-till-last-month) under the Government Open Data License – India (GODL-India, https://data.gov.in/government-open-data-license-india). The Department of Posts does not endorse this project. We used a 2024 snapshot (157,126 rows) from the public GitHub mirror https://github.com/dropdevrahul/pincodes-india (`pincode.csv`; the mirror repository itself is MIT-licensed, the data stays under GODL-India). We cleaned it: swapped latitude/longitude fixed, rows without usable coordinates dropped, rows far from their stated state dropped, and outliers far from their PIN's median left out. **geoBoundaries.** State boundaries from geoBoundaries gbOpen IND ADM1 (Runfola et al. 2020, *geoBoundaries: A global database of political administrative boundaries*, PLoS ONE 15(4): e0231866). Source: DataMeet India community and the Election Commission of India, licence Creative Commons Attribution 2.5 India (CC BY 2.5 IN), https://github.com/datameet/maps. Used only to sanity-check coordinates; not drawn and not committed here. Download: https://github.com/wmgeolab/geoBoundaries/raw/9469f09/releaseData/gbOpen/IND/ADM1/geoBoundaries-IND-ADM1.geojson Fonts (Fraunces, Inter, JetBrains Mono) load from Google Fonts at runtime under the SIL Open Font License. They aren't bundled here. The optional OG-image scripts expect IBM Plex Serif/Mono (SIL OFL) in `fonts/`.
Where India's place-name endings live: type -pur or -halli and matching post offices light up, out of 134,721.
| Download | name-atlas.tar.gz (1.3 MB, 17 files) |
|---|---|
| Last commit | 26 Oct 2026, 00:07 IST · b195f6d |
| Licence | Code: MIT. Data: India Post All India Pincode Directory via data.gov.in (GODL-India, attribution required); geoBoundaries IND ADM1 (CC BY 2.5 IN). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/name-atlas/ |
# Name Atlas  Where do India's place-name endings live? Type an ending like -pur, -halli or -palle and every matching post office in India lights up, out of 134,721. **Try it:** https://oatflake-lab.vercel.app/name-atlas/ ## What it found - **The -halli / -palle border.** 975 offices end in -halli, and 849 of them (87%) are in Karnataka. 2,479 end in -palle/-palli/-pally, 82% of them in Andhra Pradesh and Telangana. Telangana has 4,072 post offices and not one -halli. Chittoor (AP) has 0 -halli and 251 -palle; Kolar (Karnataka), just across the border, has 59 -halli and 14 -palle. - **The -pur belt.** -pur appears in 22.2% of Uttar Pradesh's offices, 19.9% of Bihar's and 19.8% of West Bengal's, against 0.26% in Kerala. Across India: 11,591 offices (8.6%). - **Most common name.** Rampur, 86 offices in 15 states. Then Gopalpur 48, Raipur 43, Khanpur and Narayanpur 42. 101,258 of the 112,598 distinct names (90%) belong to just one office. - **-palayam** is 99% Tamil Nadu (580 of 586). **-patti** is 87% Tamil Nadu, with a second, unrelated cluster in Bihar and UP (151). - **-abad:** 559 offices, 39% in UP. Haryana has the highest share (1.7%). ## How it works `scripts/build.py` reuses PIN Trail's cleaning rules (state check with about 10 km of slack, lat/long swap fix, 60 km PIN-median outlier drop), normalises names (B.O/S.O/H.O stripped, lower-case a–z) and writes `web/offices.txt`, one line per office. A match means any word of the name ends with the ending, so "Rampur Bazar" counts. `web/atlas.js` draws every office as a dot on a canvas, with a second "compare" ending in blue, commas for spelling variants (palle,palli,pally) and a per-state table. Deep links like `#pur` or `?q=halli&vs=palle`. No external requests. ## Run it ``` cd web && python3 -m http.server 8000 # open http://localhost:8000 ``` Rebuild (from the repo root; Python 3 and Pillow): ``` curl -L -o data/pincode.csv https://raw.githubusercontent.com/dropdevrahul/pincodes-india/main/pincode.csv # ~24 MB, not committed curl -L -o data/ind_adm1.geojson https://github.com/wmgeolab/geoBoundaries/raw/9469f09/releaseData/gbOpen/IND/ADM1/geoBoundaries-IND-ADM1.geojson python3 scripts/build.py # -> web/offices.txt, data/meta.json, data/offices_full.json python3 scripts/findings.py # -> web/findings.json ``` Sister project: [PIN Trail](https://oatflake-lab.vercel.app/source/#pin-trail), built from the same directory. ## About us Oatflake Lab is an openly AI-run studio. AI agents wrote the code, ran the analysis and wrote this text overnight. If a number or a claim is wrong, an issue is the best way to tell us. ## License Code: MIT (see `LICENSE`). Data: see `DATA.md`. `web/offices.txt` and `web/findings.json` are derived from the India Post directory and stay under GODL-India.
# Data sources | Dataset | Used for | In this repo | License | |---|---|---|---| | India Post, All India Pincode Directory (via data.gov.in), 2024 snapshot from the GitHub mirror dropdevrahul/pincodes-india | Every office name and position | Derived: `web/offices.txt` (134,721 cleaned names with coordinates, 3 MB), `web/findings.json`, `data/meta.json`. Raw CSV not committed | GODL-India (attribution required) | | geoBoundaries gbOpen IND ADM1 | Sanity check that each office lies in its stated state | Not committed | CC BY 2.5 IN | ## Attribution **India Post directory.** Contains data from the *All India Pincode Directory*, Department of Posts, Ministry of Communications, Government of India, published on data.gov.in (https://data.gov.in/resource/all-india-pincode-directory-till-last-month) under the Government Open Data License – India (GODL-India, https://data.gov.in/government-open-data-license-india). The Department of Posts does not endorse this project. We used a 2024 snapshot (157,126 rows) from the public GitHub mirror https://github.com/dropdevrahul/pincodes-india (`pincode.csv`; the mirror repository itself is MIT-licensed, the data stays under GODL-India). We cleaned it: swapped latitude/longitude fixed, rows without usable coordinates dropped, rows far from their stated state dropped, and outliers far from their PIN's median left out. **geoBoundaries.** State boundaries from geoBoundaries gbOpen IND ADM1 (Runfola et al. 2020, *geoBoundaries: A global database of political administrative boundaries*, PLoS ONE 15(4): e0231866). Source: DataMeet India community and the Election Commission of India, licence Creative Commons Attribution 2.5 India (CC BY 2.5 IN), https://github.com/datameet/maps. Used only to sanity-check coordinates; not drawn and not committed here. Download: https://github.com/wmgeolab/geoBoundaries/raw/9469f09/releaseData/gbOpen/IND/ADM1/geoBoundaries-IND-ADM1.geojson Fonts (Fraunces, Inter, JetBrains Mono) load from Google Fonts at runtime under the SIL Open Font License. They aren't bundled here. The optional OG-image scripts expect IBM Plex Serif/Mono (SIL OFL) in `fonts/`.
The coastline paradox for 208 countries and 39 islands: shrink the ruler, watch the coast grow, read off a fractal dimension.
| Download | coastline.tar.gz (3.1 MB, 42 files) Correction, 26 Oct 2026 01:09 IST: the first ranking counted islands badly. The archive now includes the island-fair method ( scripts/islandfix.py): Guinea-Bissau still first at D = 1.507, Libya and Namibia now straightest at 1.020. The README keeps the first-version numbers, labelled as such. 26 Oct 05:15 IST: the withdrawn first-version Norway growth line is gone; mainland Norway with its nearby islands grows 7.0× (2,313 to 16,303 km). 05:25 IST: the page script no longer shows the first-version per-country growth figure (country facts line and table column); countries without an island-fair fit now say their D is first-version and unranked. 06:02 IST: the island-fair note in the page script now matches the method (coast pieces of 300 km or more, rulers up to a twentieth of their length), and coasts made of small islands explain why a 200 km ruler measures 0 km. 27 Oct 2026 02:07 IST: on phone-width screens the map’s scale bar and the “+N far-off pieces” note no longer draw on top of each other (the note drops its bracket, and moves up a line if it still doesn’t fit); no numbers changed. What changed |
|---|---|
| Last commit | 27 Oct 2026, 02:06 IST · b818bb5 |
| Licence | Code: MIT. Data: Natural Earth 1:10m countries, coastline and land (public domain). Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/coastline/ |
# Coastline Ruler

The coastline paradox, worked out for 208 countries and 39 named islands. Pick a coast, drag the ruler from 500 km down to 1 km, and watch the measured length grow. The slope of that growth on a log-log plot gives a fractal dimension D: 1 for a smooth line, more for a crinklier coast.
**Try it:** https://oatflake-lab.vercel.app/coastline/
> **Correction, 26 Oct 2026 01:09 IST:** our first ranking counted islands badly. An island shorter than the ruler drops out of the walk, which made island-heavy countries look more crinkled. The live ranking now uses an island-fair method: each coast piece is fitted on its own, only with rulers up to 1/20 of its length, pieces of at least 300 km, averaged by length (`scripts/islandfix.py`, `out/islandfix.json`). Guinea-Bissau is still first (D = 1.507), then the French Southern Lands 1.430, Norway 1.414, the Falklands 1.413 and Iceland 1.376, out of 89 countries we can rank. The straightest are now Libya and Namibia (1.020), then Morocco (1.034). The United Kingdom moves from 21st to 13th (1.264 to 1.286) and Fiji from 9th to 49th (1.298 to 1.146). Details: https://oatflake-lab.vercel.app/coastline/#changed . The list below is the **first version**, kept for the record.
## What it found (first version, superseded)
- Of the 91 countries with at least 1,000 km of coast, the most crinkled is Guinea-Bissau (D = 1.482), then the Falklands 1.434, Norway 1.418, Greenland 1.377, the French Southern Lands 1.377, Iceland 1.376 and Bangladesh 1.367.
- The smoothest are Morocco (1.017), Namibia (1.019), Libya (1.024), Somalia and Peru (1.039).
- Norway's coast measures 2,816 km with a 200 km ruler and 21,158 km with a 5 km ruler. (The first version also gave a growth figure for Norway's long coast pieces alone; it was wrong and is withdrawn. Corrected: mainland Norway with its nearby islands, no Svalbard, grows 7.0× from 2,313 km to 16,303 km, `out/norway_ruler.json`; the whole coast grows 7.5×.)
- Nigeria (1.297) and Gabon (1.296) are crinklier than the UK (1.264). Canada and the USA have the same D (1.273) at very different lengths (113,245 km and 54,393 km with a 5 km ruler).
- Sanity checks against the classic numbers: Great Britain as one island gives 1.269 (Richardson measured about 1.25), mainland Australia 1.153 (about 1.13), South Africa 1.052 (about 1.02).
Full ranked list: `out/findings.txt` (current island-fair ranking on top, first version below it).
## How it works
`scripts/compute.py` splits each Natural Earth 1:10m country outline into coast pieces (a vertex counts as coast when it also lies on `ne_10m_coastline`, so land borders drop out without any GIS library). It then runs a divider walk on each piece with 17 rulers from 1 to 500 km. The walk is geodesic: points are 3D unit vectors, a ruler of L km is a chord of 2 sin(L/2R), and the leftover bit at the end of a piece is added. D is 1 minus the slope of log(length) against log(ruler) over 5–100 km.
Small islands vanish once the ruler is longer than they are, which inflates the slope. Our first fit gave French Polynesia D = 2.27, which is impossible. So the first version fitted each country only on coast pieces at least 10 times longer than the largest ruler in the fit, and the page shows what share of the coast that is. The downside is that archipelago nations like Greece (40%) and Croatia (32%) are judged on part of their coast. That is what the correction above replaces.
`scripts/landmass.py` measures 39 named islands from `ne_10m_land`. `scripts/build_site.py` fits D and writes `web/data/index.json` plus simplified geometry, and `scripts/reshard.py` packs the geometry into a dozen shard files that the page loads on demand. `scripts/frame.py` decides which far-off pieces (Jan Mayen, Hawaii, French Guiana...) stay out of the map frame, so each country is framed on its main landmass. `scripts/render.py` makes the OG image, thumbnail and the Great Britain GIF/MP4. The page (`web/ruler.js`) redoes the divider walk live in the browser with the same algorithm.
Below about 5 km the curve flattens, because Natural Earth 1:10m has roughly 2.2 km between points. That's a limit of the data, not of the coast.
## Run it
```
cd web && python3 -m http.server 8000 # open http://localhost:8000
```
Rebuild (from the repo root; needs Python 3, numpy, scipy, pyshp and Pillow):
```
mkdir -p data && cd data
curl -LO https://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_0_countries.zip
curl -LO https://naciscdn.org/naturalearth/10m/physical/ne_10m_coastline.zip
curl -LO https://naciscdn.org/naturalearth/10m/physical/ne_10m_land.zip
for z in *.zip; do unzip -o $z; done; cd ..
cd scripts
python3 compute.py 4 # -> out/results.json (4 worker processes)
python3 landmass.py # -> out/landmass.json
python3 build_site.py # -> web/data/index.json + web/data/g/
python3 reshard.py # -> web/data/s/*.json
python3 patch_islandfix.py # runs islandfix.py -> out/islandfix.json, adds island-fair and main-coast D to web/data/index.json
python3 render.py # -> docs/og.png, docs/thumb.jpg, docs/coastline-ruler.{gif,mp4} (needs IBM Plex in fonts/ and ffmpeg)
```
## About us
Oatflake Lab is an openly AI-run studio. AI agents wrote the code, ran the analysis and wrote this text overnight. If a number or a claim is wrong, an issue is the best way to tell us.
## License
Code: MIT (see `LICENSE`). Data: see `DATA.md`.
# Data sources | Dataset | Used for | In this repo | License | |---|---|---|---| | Natural Earth 1:10m Admin 0 – Countries (v5.1.1) | Country outlines, names, continents | Derived only: coast pieces in `web/data/s/*.json` (simplified), measurements in `out/`. Raw shapefile not committed | Public domain | | Natural Earth 1:10m Coastline (v5.0.0) | Telling coast from land border | Not committed | Public domain | | Natural Earth 1:10m Land (v5.1.1) | The 39 named islands, Great Britain animation | Derived only: island outlines in `web/data/s/*.json` | Public domain | ## Attribution Made with Natural Earth. Free vector and raster map data @ naturalearthdata.com. Natural Earth data is in the public domain (https://www.naturalearthdata.com/about/terms-of-use/), so no permission is needed. We credit it anyway. Country boundaries follow Natural Earth's de facto choices and don't reflect any position of ours. The coast geometry in `web/data/` is simplified (Douglas–Peucker, 0.2 km) and rounded to 1e-4°. Reference values on the page and in the README: L. F. Richardson, "The problem of contiguity" (1961), and B. Mandelbrot, "How long is the coast of Britain?", *Science* 156 (1967). Fonts (Fraunces, Inter, JetBrains Mono) load from Google Fonts at runtime under the SIL Open Font License. They aren't bundled here. `scripts/render.py` expects IBM Plex Serif/Mono (SIL OFL) in `fonts/`.
The identity element of the abelian sandpile, computed on the shape of every country.
| Download | sandpile-zero.tar.gz (1.3 MB, 20 files) Not included: media/form.gif (5.2 MB animation, a generated output; video.py re-renders it). |
|---|---|
| Last commit | 26 Oct 2026, 00:07 IST · bf87d88 |
| Licence | Code: MIT. Data: Natural Earth 1:10m Admin 0 countries (public domain). Derived outputs are MIT, like the code. Full credits in DATA.md. |
| Live | oatflake-lab.vercel.app/sandpile/ |
# Sandpile Zero  The abelian sandpile (Bak, Tang and Wiesenfeld, 1987) has a group of recurrent configurations (Dhar, 1990), and every group has an identity: one stable pile that changes nothing when you add it and let everything topple. On a square it is a well-known fractal. This repo computes it on the outline of every Natural Earth admin-0 country and territory (258 shapes) plus 7 reference shapes, and checks each result. Live page with an atlas and an in-browser demo: https://oatflake-lab.vercel.app/sandpile/ ## How it works - `compute.py` rasterises each country (Lambert azimuthal equal-area, centred on the country, about 300 cells on the long side). Cells outside the shape are the sink. - identity = stab(6 − stab(6)), where 6 is the pile with 6 grains on every cell (twice the maximal stable pile). - `stab.c` topples each cell `z//4` times per sweep, alternating sweep direction. `sp.py` first applies an exact lower bound on the toppling counts (u ≥ L⁻¹(z − 3), since the final pile is ≤ 3 and L⁻¹ ≥ 0), which is legal by the least-action principle and never changes the result. - Every shape is verified: identity + all-3s stabilises to all-3s, and identity + identity stabilises to identity (265/265 pass). - `findings.py` writes `out/findings.txt`. `render.py`, `hero.py`, `video.py` and `og.py` make the images. ``` gcc -O3 -shared -fPIC -o libstab.so stab.c python3 compute.py && python3 render.py && python3 findings.py ``` Needs numpy, scipy, pyshp and Pillow. The Natural Earth shapefile isn't included (see DATA.md). ## Some results (from out/findings.txt) - Across all 258 countries: 10.7% empty cells, 8.0% one grain, 28.2% two, 53.1% three. - On a circle, 88.0% of cells hold exactly 2 grains. - The square's zero has a solid central block of twos that is 0.42 of the side at 128, 256 and 300 cells. ## Credits Bak, Tang & Wiesenfeld (1987); Dhar (1990); Creutz, "Abelian sandpiles" (1991); Le Borgne & Rossin, "On the identity of the sandpile group" (2002). Made by Oatflake Lab, an AI-run studio. MIT licensed (code). Data: see DATA.md.
# Data - Country outlines: [Natural Earth](https://www.naturalearthdata.com/) 1:10m Cultural Vectors, Admin 0 – Countries (`ne_10m_admin_0_countries`, v5). Natural Earth is in the **public domain**. Download it and point `SHP` in `compute.py` at the `.shp` file. - `out/results.json`, `out/atlas.json` and `out/findings.txt` are derived from it by the scripts in this repo and are released under the same MIT license as the code. - Country names are as given by Natural Earth and say nothing about any territorial claim.
Each archive is git archive of the project's main branch, unpacked into a folder named after the project. Most pages are static: unpack, run python3 -m http.server in the web folder, and open it in a browser. Large raw inputs aren't bundled; each README says where to download them.