# F1 Singapore Crash Map

A working Singapore F1 weekend incident atlas and video project, inspired by the accumulating shot-chart format. Crashes and contacts appear over historical Marina Bay circuit schematics, leaving a persistent record as the seasons advance.

**Current release: research cut 01.** The ledger contains **137 sourced incidents**, of which **88 have source-backed turn references**. The other **49 are retained without map pins**. This is not yet a verified “every crash” census.

Scope: F1 practice, qualifying, Sprint sessions where applicable, and the Grand Prix from 2008 onward. Physical barrier contact and car-to-car collisions count, including confirmed minor contact. A multi-car sequence counts as one incident.

The graphic uses a white, red and black design, the F1 title mark and typeface, verified historical driver/team pairings, and six geographically aligned Singapore landmarks. Each new crash triggers layered red shock rings and impact streaks. Team logos, landmark alignment and brand asset provenance are stored with the source data.

Research cutoff: **11 October 2026, 14:43 Singapore time**. The completed 2026 sessions are included; that evening's Grand Prix is pending and excluded. The cancelled 2020 and 2021 events are explicitly recorded.

## Open it

- **Double-click [preview.html](preview.html)** for the self-contained editor. Its fonts, team logos, data and code are embedded, so playback does not require a server or network. Source links open external websites. Keep the project folder together for the video and documentation links.
- **Watch [the vertical MP4](exports/research-cut.mp4)**: 1080 × 1920, H.264, 60 fps, 20 seconds. The research cut is silent. It begins with a crash at time zero, accumulates for 18 seconds and holds the final map for two seconds.
- **Inspect [the source ledger](data/incidents.csv)** or [structured dataset](data/incidents.json).

For development, Node.js 20+ is sufficient; the app itself has no runtime dependencies:

```sh
npm run dev
```

Open the printed local URL, normally `http://127.0.0.1:4173`. Space toggles playback. Arrow keys step between incidents. Click a season, a map marker, or a ledger row to inspect the evidence. Switch between the overview and 9:16 composition, or filter practice, qualifying, and race sessions.

## Rebuild the video

```sh
npm ci
# Only needed when no installed Google Chrome is available:
npx playwright install chromium
npm run render
```

The renderer uses the same Canvas code as the editor. It renders individual frames at deterministic times, then encodes an H.264 MP4 with ffmpeg. `CHROME_PATH` and `FFMPEG_PATH` can select existing executables. `CODEX_NODE_MODULES` optionally points to an existing module directory.

```sh
npm run render -- --width 1080 --height 1920 --fps 60 --duration 20
```

Browser exports include the current frame as PNG, the ledger as CSV, and a real-time vertical WebM using the current session filter. The included MP4 uses the complete sourced subset, regardless of the editor's active filter.

## Work with the evidence

Canonical app data lives in `data/incidents.json`. Each row has a driver list, year, session, nullable lap and turn, source title/URL, location confidence and notes. `data/research/` preserves the three era research inputs, with corresponding coverage notes in `docs/`.

To regenerate the canonical JSON/CSV from the reviewed research inputs:

```sh
node scripts/import-research.mjs data/research/2008-2014.json data/research/2015-2019.json data/research/2022-2026.json
npm run validate
```

Review scope and cutoff metadata in the importer before advancing the research boundary. Update both the era input and canonical data, or regenerate after editing the era input. Never assign a turn from a guess. Vague aggregate accounts stay in `data/research-only.json` outside the count.

The five schematic eras are 2008–2012, 2013–2014, 2015–2017, 2018–2022 and 2023 onward. Old Turns 16–19 remain on the retired waterfront branch; old Turns 20–23 correspond to current Turns 16–19. The original licensed SVGs are included. Rebuild sampled paths with:

```sh
node scripts/prepare-layouts.mjs
```

**Placement is schematic and at turn level.** Dots are arranged around a turn anchor for legibility. Their offsets are not surveyed impact coordinates. Year/session order is historical; within-session timing is approximate where reports do not establish order. Mapped crashes arrive at a steady editorial cadence during the first 18 seconds, so seasons with more plotted incidents receive more screen time. Unlocated records remain in chronological order between those arrivals and never create map dots. The final two seconds hold the complete map; animation time is not elapsed racing time.

## Verify and package

```sh
npm test
npm run validate
npm run qa
node scripts/bundle-preview.mjs
npm run build
```

The tests cover uncertain locations, original/modern corner mapping, the historical SVG label-order regression, cumulative playback, session filtering and the research cutoff. Browser QA checks playback, search, filtering, season seeking, source ledger, CSV/PNG exports, portrait view, responsive layout and deterministic frames. QA screenshots and render metadata are in `exports/`. `npm run build` creates a static `dist/` directory. No accounts, credentials or network services are required by the app.

## Research still to complete

Use [the methodology](docs/METHODOLOGY.md), [research notes](docs/research-2008-2014.md) and [release gate](docs/RELEASE-GATE.md). The substantial remaining work is a full session-footage audit, second-source verification, resolution of disputed corners, exact within-session ordering, and completion of the 2026 weekend after the frozen cutoff. Report search coverage alone does not establish completeness or zero-incident sessions.

## Hosting

Source is maintained in the private [johnwanghere/f1crashes GitHub repository](https://github.com/johnwanghere/f1crashes). The public production deployment is available at [f1crashes.vercel.app](https://f1crashes.vercel.app); the configured custom domain is [f1crashes.com](https://f1crashes.com). The custom domain requires the GoDaddy DNS records recommended by this Vercel project. Vercel's GitHub integration must have access to this repository before pushes can trigger automatic deployments.

`vercel.json` builds the static distribution with Node.js. The production build publishes the two release MP4s from `assets/video/`, omits QA exports, and serves the final-map sharing image at `assets/social/crash-map-share.png`. Rebuild and check the production package locally with:

```sh
npm run build:production
npm run check:deployment
```

## Licenses

Application code is MIT. The adapted map graphics, combined map dataset and original visual contributions are released under **CC BY-SA 4.0**; the F1 mark, proprietary F1 font and third-party team marks retain their separate rights. Retain [the complete attribution](docs/ATTRIBUTION.md) when sharing the cut. Unmodified reference SVGs retain their original listed licenses. Open source fonts retain their included SIL Open Font Licenses. This project is independent and is not affiliated with Formula 1, the FIA, or Singapore GP.
