ARCHIVE_404 — the debut project from ERROR_404.
Four chapters. Twenty recovered files. One transmission.
▶ error404.run · ↓ Download the album · Releases · Changelog
![]() |
![]() |
| Catalogue: chapter cards with built-in players, and the dock on every page | Phone: the hyperpop tagline and the dock |
ARCHIVE_404/
├── 01_ORIGIN/
│ ├── 01 origin.mp3 ................. 2:58
│ ├── 02 left_behind.mp3 ............ 4:14
│ ├── 03 graft.mp3 .................. 3:43
│ ├── 04 impacted.mp3 ............... 4:34
│ └── 05 empty_city.mp3 ............. 4:07
├── 02_THE_FEED/
│ ├── 06 the_feed.mp3 ............... 2:37
│ ├── 07 gospel_out.mp3 ............. 3:51
│ ├── 08 endless_glow.mp3 ........... 3:11
│ ├── 09 awake.mp3 .................. 3:18
│ └── 10 reclaimed.mp3 .............. 3:27
├── 03_THE_WRECKAGE/
│ ├── 11 the_wreckage.mp3 ........... 2:29
│ ├── 12 read.mp3 ................... 3:31
│ ├── 13 come_home.mp3 .............. 3:32
│ ├── 14 changed_the_lock.mp3 ....... 4:05
│ └── 15 down_the_front.mp3 ......... 4:07
└── 04_WHOLE/
├── 16 whole.mp3 .................. 2:16
├── 17 enough.mp3 ................. 4:21
├── 18 open_sky.mp3 ............... 3:56
├── 19 all_of_me.mp3 .............. 4:07
└── 20 better_days.mp3 ............ 4:37
20 files · 73:11 · 155 MB · MP3 · ALL INTACT
Written and performed by NULLSAINT and CACHEGHOST. Hyperpop at its core, with metalcore and glitchcore, presented as a recovered transmission.
- Intro, "the tracklist falls": matrix code rain whose columns stream the album's own 20 track names, while a terminal readout counts
RECOVERING ARCHIVE_404 · FILE 07/20 GOSPEL_OUT … 20/20 FILES INTACT, then drains into the hero. About 4 s, once per visit, and a tap or any key skips it. - Signal Overload hero: the logo as an outline cut-out, a self-moving flashlight whose light stays inside the letters, glitch bursts every 4–6 s (magenta/cyan tear, sheared slices, colour-split artwork), scanlines and a VHS tracking band. The tagline scrambles between SOMETHING SURVIVED THE CRASH and HYPERPOP MAXIMALISM.
- Player dock: one player on every page that plays all 20 tracks in album order, with a queue grouped by chapter, lock-screen and headphone controls, and resume-where-you-left-off. New visitors start on 07 GOSPEL_OUT.
- Chapter players: every chapter streams in the page, with waveform, seek and per-track durations, handing over to and from the dock.
- Brand kit: palette (click to copy), typography and press images with downloads.
- SIGNAL: a booking form backed by Netlify Forms.
- End credits footer, a wide-screen telemetry gutter (REC timecode and scroll position) and a branded 404.
- One design system: void black, a strict magenta → cyan duo, Bebas Neue / Space Mono / Inter, holo-foil buttons, gradient play keys, a distressed
>_menu icon, viewfinder ticks and LED status chips. Everything animates on the GPU, respects Reduce Motion, and scales fluidly on large screens.
npm install
npm run dev # http://localhost:5173
npm run check # lint + formatting + production build (what CI runs)
npm run build # production build into dist/
npm run preview # serve the build locally
npm run format # auto-format everything with PrettierRequires Node 22 LTS (see .nvmrc).
index.html page shell: meta/share tags, favicons, fonts, start-up scripts, Netlify form stub
vite.config.js build config, plus content-hash stamping for logo-fx.js and every track
netlify.toml build settings, caching and security headers
public/ copied as-is to the site root
404.html branded "file not found" page
site.webmanifest home-screen / Android manifest
assets/ logo (SVG), hero art, brand kit, press images, share image,
logo-fx.js (hero/closing flashlight, glitch bursts, nav draw-on)
audio/ the 20 tracks (snake_case filenames, e.g. changed_the_lock.mp3)
fonts/ Bebas Neue (self-hosted)
src/
main.jsx · App.jsx entry point and page order
config.js GitHub owner/repo and the album download URL
vault/ Source Vault page script and styles (the page is vault/index.html)
components/ BootSequence (intro), Nav, Hero, TaglineSwap, Collective,
Catalogue (chapter players), PlayerDock, Signal,
DownloadModal, Footer, Gutters, Name
data/ chapters.js (tracklist, durations), brand.js (brand kit)
lib/ shared easing, time formatting, audioSrc (cache-busted track URLs)
styles/
index.css Tailwind plus the site's base, component and utility layers
overrides.css design-system pass (type scale, colours, components); loaded last
.github/ CI workflow, Dependabot, issue and PR templates
docs/ README images
Everything lives in src/data/chapters.js:
{ number: 17, title: "ENOUGH", audioPath: "/audio/enough.mp3", duration: "4:25" }Put the MP3 in public/audio/ under the same name. CI fails the build if a listed track file is missing.
- Replace the file in
public/audio/, keeping its snake_case name (e.g.07 gospel_out.mp3→gospel_out.mp3). - Update that track's
durationinsrc/data/chapters.jsif the length changed. - Nothing else: each build stamps every track with a hash of its contents (
?v=…, seevite.config.jsandsrc/lib/audioSrc.js), so listeners get the new file straight away instead of a copy from their 30-day browser cache. - For a new album download, publish a new GitHub Release with the zip (see Deployment). The download button always points at the latest release.
| Parameter | Effect |
|---|---|
?intro |
Always play the intro (normally once per visit) |
?nointro |
Skip the intro |
?zoom=0.9 |
Override the fluid scale (100% up to 1280px wide, easing to 85% at 1920px+) |
The site deploys automatically on Netlify from the main branch. netlify.toml sets the build (npm run build → dist, Node 22), long-term caching for hashed bundles, fonts and audio, and security headers.
The album download (ARCHIVE_404.zip, about 155 MB) is too large for git, so it's attached to the latest GitHub Release. The site links to /releases/latest/download/ARCHIVE_404.zip, so publishing a new release with a new zip updates the download automatically:
gh release create v1.3.0 ARCHIVE_404.zip --title "ARCHIVE_404 · v1.3.0" --notes-file release-notes.md --latestContact form: submissions arrive under Netlify → Site → Forms.
A private page for collaborators: every track's stems, the Suno prompts in all five production styles, original and Suno-optimised lyrics, and each song with its measured length, BPM and key. It opens with the access key, then plays a rain intro that "decrypts" the 20 files.
The page itself is public code, so nothing private is in this repo in readable form:
| Piece | Where it lives |
|---|---|
| Access key | Netlify environment variable VAULT_KEY, checked by netlify/functions/vault-unlock.mjs |
| Session | Signed, HttpOnly cookie (VAULT_SECRET), valid 7 days |
| Prompts, lyrics, analysis | netlify/vault-data.enc.json, AES-256-GCM encrypted with VAULT_DATA_KEY; decrypted only by vault-data.mjs for a signed-in visitor |
| Stems | Release stems on the private repo error404website/error404-vault; vault-stem.mjs hands out GitHub's 5-minute signed link (VAULT_GH_TOKEN, read-only) |
Netlify environment variables (Site configuration → Environment variables, scope Functions, mark as secret): VAULT_KEY, VAULT_SECRET, VAULT_DATA_KEY, VAULT_STEMS_REPO, VAULT_STEMS_TAG, VAULT_GH_TOKEN. Local copies live in the git-ignored .env.vault.
Updating the prompts or analysis: edit the files in the git-ignored vault-private/, run npm run vault:encrypt, and commit the new netlify/vault-data.enc.json.
Updating the stems: upload the zips to the stems release on the private repo with the names npm run vault:encrypt prints (one per track, plus one per chapter for ALL STEMS, since GitHub caps a release file at 2 GB). Sizes appear in the vault automatically.
- Fluid scale: the site is scaled with CSS
zoomon large screens, and browsers don't rescalevw/vhunder zoom. Size anything full-window ascalc(100vw / var(--ez, 1)). - Search engines and AI: the site is shared by direct link only.
robots.txtblocks every crawler (search engines, AI training and AI search, archives, SEO tools), and every response carriesX-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noimageindex, noai, noimageai(netlify.toml), matched by therobotsmeta tag.tdm-reservation: 1,/.well-known/tdmrep.jsonand/ai.txtopt out of text and data mining. To open the site to search later, remove all of these. - Safari toolbar: Safari 26 tints its toolbars from the fixed nav and the player dock, both
#000000. It never tints in Private Browsing. - Safari clipping: Safari doesn't clip transformed (GPU-composited) children to
overflow: hidden. Keep effects inside their box: animate a registered@property, a background position or a gradient centre rather than moving an oversized layer, and addclip-path: inset(0)when a child must move inside a clip. - Icons: draw UI icons as SVG or CSS shapes. iOS swaps characters like ⏮ ⏭ ☰ ▶ for coloured emoji (▶ is pinned to text with
U+FE0E).
© 2026 ERROR_404 — all rights reserved. Public for transparency, not for reuse. See LICENSE and SECURITY.md.


