# skip-intro A study lab for web design, roughly 1998 to 2004. Praystation-era experimental work, the dark studio sites, the k10k boxed grid, bevelled chrome, and the bitmap type that held all of it together. Every study is a **whole page**, not a component. That era designed pages, not systems, which is why two sites from the same year could share no vocabulary at all. The structure of this repo follows from that and is explained under [House rules](#house-rules). ## Thesis **Constraint is the subject.** Every technique here existed to defeat a hard limit. A 760px ceiling. 56k. No web fonts. No control over antialiasing. No layout primitive but the table. No alpha in GIF. The 10px pixel font was not a style, it was the only way to get legible type that small. So each study names the constraint it solved, and answers one question: **does the technique survive the removal of its constraint?** | verdict | meaning | | --- | --- | | **SURVIVES** | Good design independent of the limit that produced it. | | **ARTIFACT** | Pure workaround. Dies the instant the constraint lifts. | | **CONTESTED** | Defensible now only as deliberate style, and the study has to argue it. | | **ABSORBED** | Won so completely it stopped being a visible decision. Invisible, not gone. | | **REVOKED** | Not outgrown. A browser vendor withdrew the capability on purpose, and the technique would still work if they had not. | That column is what makes this a lab rather than a nostalgia reel. ## Run it ```sh python3 -m http.server 8792 open http://localhost:8792/ ``` Needs a server, not `file://`. The index and harness are ES modules, and the harness reads real transfer sizes from the studies' performance entries. ## Layout | path | what | | --- | --- | | `index.html` | contact sheet: every study live, filterable by verdict, area and palette | | `harness.html` | every study at 640x480, 800x600 and 1024x768, fold drawn, weight measured against a 60 KB budget | | `studies//` | one self-contained page per study | | `lab/catalog.js` | the single source of truth | | `lab/lab.css` | chrome for the two lab pages only | | `vendor/fonts/` | pinned bitmap faces, both SIL OFL | | `scripts/vendor.sh` | re-pulls every vendored asset; versions live there and nowhere else | | `scripts/corpus.py` | censuses archived **source** across 78 domains (written, correct, **never yet run**) | | `scripts/shoot.py` | screenshots the captures the census measures (written, **never yet run**) | | `corpus/` | the census output and its on-disk fetch cache | | `captures/` | screenshots (gitignored: third-party content, reproducible from the script) | | `audit.html` | every study audited with axe, `incomplete` printed beside `violations`, no total score | | `vendor/axe/` | axe-core, pinned and vendored; its licence sits beside it | | `NOTES.md` | the written study: 43 findings, read it before touching anything | ## The studies Forty-two, across seven areas. | study | area | palette | verdict | | --- | --- | --- | --- | | `dark-studio` | composition | dark | SURVIVES | | `boxed-grid` | grid | dark | SURVIVES | | `bento-dense` | grid | dark | SURVIVES | | `two-value-dark` | color | dark | SURVIVES | | `palette-split` | color | both | SURVIVES | | `hud-console` | composition | dark | SURVIVES | | `tdr-numeric` | composition | light | SURVIVES | | `foundry-store` | typography | light | SURVIVES | | `community-board` | grid | light | SURVIVES | | `art-diagram` | imagery | light | SURVIVES | | `art-shard` | imagery | light | SURVIVES | | `art-duotone` | imagery | dark | SURVIVES | | `light-shaft` | imagery | dark | SURVIVES | | `light-chrome` | construction | light | CONTESTED | | `type-ladder` | typography | both | CONTESTED | | `portal-density` | grid | light | CONTESTED | | `jp-minimal` | composition | light | CONTESTED | | `net-art-broken` | composition | dark | CONTESTED | | `form-controls` | construction | light | CONTESTED | | `dot-notation` | typography | dark | CONTESTED | | `art-glitch` | imagery | light | CONTESTED | | `art-wireframe` | imagery | dark | CONTESTED | | `art-scene` | imagery | dark | CONTESTED | | `shard-burst` | imagery | light | CONTESTED | | `art-texture` | imagery | dark | CONTESTED | | `art-studio` | imagery | dark | CONTESTED | | `art-pixel` | imagery | dark | CONTESTED | | `chevron-hatch` | imagery | dark | CONTESTED | | `bar-glitch` | imagery | light | CONTESTED | | `organic-motif` | imagery | dark | CONTESTED | | `splash-gate` | navigation | dark | ARTIFACT | | `requirements-gate` | navigation | light | ARTIFACT | | `art-render` | imagery | dark | ARTIFACT | | `rollover` | navigation | dark | ABSORBED | | `art-chassis` | imagery | dark | ABSORBED | | `thumbnail-strip` | navigation | dark | ABSORBED | | `image-map` | navigation | light | ARTIFACT | | `text-as-gif` | typography | light | ARTIFACT | | `websafe-216` | color | light | ARTIFACT | | `popup-window` | navigation | dark | REVOKED | | `ambient-audio` | construction | dark | REVOKED | | `status-caption` | navigation | both | REVOKED | Two of them exist to stop the lab agreeing with itself: `net-art-broken` is the aesthetic control (as `useit.com` is the usability one) and `jp-minimal` is the counterexample to "the era was dense and dark." ## Provenance is declared, always Some studies are built on values read out of archived markup. Some are built from the shape of the thing. **They are not the same and every study says which**, in its own source and in its catalogue entry, because the difference is the whole credibility of the lab. `boxed-grid`, `two-value-dark`, `hud-console`, `dark-studio`, `rollover`, `requirements-gate`, `popup-window`, `art-diagram`, `thumbnail-strip` and `palette-split` carry measured values. `portal-density`, `tdr-numeric` and `jp-minimal` are designed from the vocabulary and stay flagged until a corpus run confirms or corrects them, which is exactly how `dark-studio` got its palette wrong and then right. Four studies carry a **measured negative**, which is a different and stronger thing: `ambient-audio` (no `bgsound`, `embed`, `object`, `applet` or audio file reference in either capture), `form-controls` (no `form`, `input`, `select` or `textarea` in either capture) and `dot-notation` (241 dot-joined tokens across both, zero of them set as display text). A negative bounds what the lab is entitled to claim, and each of those studies says so on its own face rather than quietly building on the absence. `image-map` carries the fourth, and it is the first one that argues **against** its own study: zero ``, `` or `usemap` in either capture, but that is two studio pages and the image map was a vernacular idiom, so the absence is a gap in the corpus rather than a fact about the era. Finding 42 draws the rule out of it. **A measured negative is only evidence where the sample could have contained the thing.** `text-as-gif` carries something else again, a **replication**: finding 7's census re-run against a different capture that finding 7 never saw, giving 39 images and 2 `` tags where the original gave 40 and 2. See finding 39, and note that the two cached captures are NOT the two that findings 6 to 9 were taken from. And `palette-split` measures the shape of the gap: **every measured colour in this repository comes from two studio sites**, so finding 1's other wing has no evidence here at all. That is now the corpus run's specific job, and `greyscale.net` is the first row in it: a 2001 studio site whose ground appears to be near white, which if confirmed makes finding 1's "the studio wing is dark" wrong rather than merely untested. Appears to be, because that one comes off a screenshot rather than out of markup. See finding 32b. ## Adding a study 1. Add an entry to `lab/catalog.js`. `id` must equal the directory name. 2. Create `studies//index.html` as a complete, standalone page. 3. Write its CSS inside it. Import nothing from a sibling. ## House rules **No shared design layer.** A study may load `vendor/fonts/fonts.css` and nothing else. It may not load `lab/lab.css`, and it may not load another study's CSS. This is the thesis holding: the moment a common panel style gets factored out across two studies, the lab has quietly invented 2014 and stopped studying 2001. Captions are drawn **around** a study by the index, never injected into it. **Motion is period-plausible, or says it is not.** The era's motion vocabulary was bounded by what its hardware could afford. Rollovers and instant state swaps are in. Staggered entrances and eased transitions are a modern compositor idiom and are out, unless a study is explicitly about the difference and declares it in its `motion` field. **`font-display: block`, never `swap`.** A bitmap face that falls back to a proportional serif does not degrade, it lies: the layout still renders, nothing throws, and the result is wrong. `type-ladder` asserts the faces actually loaded and shows a loud banner when they did not. **Measurements over claims.** The harness measures weight and draws the fold. `light-chrome` counts the DOM of both builds. `type-ladder` measures advance width against the device pixel grid instead of asserting crisp sizes from memory. ## Known browser traps Four of these were paid for once already in a sibling project and are written down here so they are not paid for twice. - **Offscreen iframes do not render.** Chrome throttles anything not intersecting the viewport. A contact sheet or harness that parks its stage offscreen reports a flawless result for a page it never drew. Both lab pages use `IntersectionObserver` and set `src` on first intersection. - **A missing `@font-face` fails silently to serif.** See the rule above. - **Vendored CSS keeps its relative `url()`s.** Anything vendored needs its assets as siblings, or every reference 404s quietly. - **axe reports `incomplete`, not a pass, when it cannot resolve a background**, and a background image is enough to trigger it. This era is built on background images and sliced cells, so an audit page here must read `incomplete` beside `violations` or it will look cleanest exactly where it measured least. `audit.html` now exists and meets that requirement literally: the two columns sit side by side, are never summed, and **the page prints no total score at all**, because a single number is what would let a study with many unresolved background checks outrank one with a real failure. - **A progress counter that counts only successes** cannot tell "nothing yet" apart from "everything is failing." The corpus fetcher reported zero done for twelve minutes while raising on every call. Report failures beside successes. The same trap caught `audit.html` during its build, in a second costume: in a headless shell the `IntersectionObserver` never fires, so the page sat at zero looking exactly like an audit in progress. It now gives up after six seconds and says nothing was audited and why, while still refusing to audit frames that never drew. - **`getBoundingClientRect()` on an `` returns all zeroes** in Chrome, so an image map's hit regions cannot be measured by asking the elements where they are. `image-map`'s first instrument did exactly that and would have printed a confident invented number for every row. Hit-test with `elementFromPoint` instead, and test an instrument against a known case before trusting its output, because plausible output is not evidence. ## Do not automate the archives `archive.org` and `webdesignmuseum.org` are curated, served at somebody's expense, and defended against scripted access. Both throttled this project in a single day, and the museum's Cloudflare challenge locked the author out of her own browsing mid-session. The arrangement that works: **a human browses them**, and the lab reads what is already open in a tab. `scripts/corpus.py` is the one exception, and it gets one patient run at a 10s throttle after a real cooling-off period. Retrying a rate limit extends it; backoff cannot recover a budget already spent. ## Licence and credits This lab's own work is MIT, see [LICENSE](LICENSE). That covers `studies/`, `lab/`, `scripts/`, the tool pages and [NOTES.md](NOTES.md). The studies are original drawings of documented techniques, not copies of anyone's pages; cited numbers are attributed in NOTES.md to the capture they were read from. Everything under `vendor/` is unmodified upstream and stays under its own licence. [CREDITS.md](CREDITS.md) is the inventory, and `vendor/licenses/` holds the real text of each. Three items, three different licences: axe-core is MPL-2.0, Silkscreen is OFL 1.1, Departure Mono is MIT. `corpus/cache/` holds archived captures of third-party sites and is **not** published. It is gitignored, and `tools/deploy.sh` withholds it by staging the upload with rsync and refusing to deploy if it survives. Listing it in `.assetsignore` was not enough on its own: `wrangler pages deploy` does not read that file, and both captures were briefly live on the first deploy. See CREDITS.md. **The site is public, the repository is not.** The lab publishes findings, not a distributable codebase. The studies and NOTES.md are the part worth reading and they are on the web; the repo adds a frozen snapshot and the local archive cache, neither of which should be handed out.