Source code for all codedoodl.es doodles
  • GLSL 65.3%
  • JavaScript 24.1%
  • Shell 4%
  • Processing 3.1%
  • CSS 2.5%
  • Other 1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-30 01:22:41 -05:00
.github Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
andrevenancio gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
ayamflow/knacki gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
brunoimbrizi/go-with-the-flow gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
cabbibo/arrows gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
caostar/n-chaosphere gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
container Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
dmmn Restore Substrate and Particulate and curate published artwork 2026-09-29 02:33:59 -05:00
dmnsgn gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
docs Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
doormat23/nebulon gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
edankwan gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
flexi23 gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
fredericbriolet/dispositions gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
gianab/neon-bubbles gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
grgrdvrt gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
gwenvanhee gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
hellochar gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
inconvergent gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
ivxvixviii/limbo gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
j0n/sea-something gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
jeremboo/orchid gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
jpweeks/particulate Restore Substrate and Particulate and curate published artwork 2026-09-29 02:33:59 -05:00
mannytan/lilypad gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
montoyadiego/atombeat gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
naso/spike-path gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
neilcarpenter gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
nicoptere gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
raurir/racing-lines gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
robin-dela/flocon gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
rolyatmax gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
samsy Restore Substrate and Particulate and curate published artwork 2026-09-29 02:33:59 -05:00
scripts Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
security Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
silviopaganini gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
sirgodart/interstellar gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
soulwire gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
sterlingcrispin/a-particular-nowhere gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
stopyransky/pixeloze gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
tdhooper/icosahedron-snake gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
tests Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
tholman/generative-boids gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
williamapan gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
yiwenl gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
zadvorsky gzip uncompressed text assets 2026-04-27 14:27:03 -05:00
.dockerignore Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
.gitignore Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
.node-version Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
compose.yml Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
Dockerfile Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00
master_manifest.json Restore Substrate and Particulate and curate published artwork 2026-09-29 02:33:59 -05:00
master_manifest_DEV.json Restore Substrate and Particulate and curate published artwork 2026-09-29 02:33:59 -05:00
README.md Containerize the published artwork archive with validated candidate releases (#2) 2026-09-30 01:22:41 -05:00

codedoodl.es artwork archive

This fork preserves the artwork used by doodles.treyturner.info and its locally installed Chrome extension. The codedoodles-assets image serves the 76 published sketches at the existing doodle.treyturner.info paths. It is independent of the site application.

Build and run

Requires Git, Docker with BuildKit and Compose, and Linux AMD64. Node 24.21.0 is pinned for build/test tooling; the running server contains no Node runtime.

bash scripts/build-image.sh codedoodles-assets:local
docker compose up -d
curl http://127.0.0.1:8080/health

The wrapper supplies the source commit and its timestamp. Build from a clean checkout when recording a release. The multi-stage Dockerfile pins Node and unprivileged Nginx 1.30.5 Alpine slim by digest. The container runs as UID/GID 101:101, accepts HTTP on port 8080, and works with a read-only filesystem and /tmp tmpfs. Logs go to stdout/stderr. Compose binds only loopback; the existing reverse proxy remains responsible for HTTPS.

For deployment, set ASSETS_IMAGE to an accepted registry digest, not a moving tag. See publication and rollout.

Asset preparation and serving contract

scripts/prepare.mjs uses Node's standard library. The production master_manifest.json is the allowlist: it copies each selected sketch directory including _original resources, plus both root master manifests. Every DEV entry must be included in production. Catalogue IDs, numbers, dates and surviving bytes are preserved. Unpublished sketches, experiments, hidden metadata/editor files, and repository-level build/test tooling are excluded from the served tree.

Many archived files contain gzip bytes despite their ordinary filename. The preparer detects the signature, writes decoded bytes to the original filename, and retains the exact archived bytes in a .gz companion. Other bytes stay unchanged. Nothing rewrites the source archive. Corrupt gzip, invalid catalogues, missing entrypoints/manifests/previews, unsafe paths and symlinks fail the build. Files and directories receive the source commit timestamp; both representations share their modification time. An internal inventory records sizes and SHA-256 hashes. Nginx negotiates gzip with gzip_static; direct companion URLs are hidden.

Response Cache-Control
HTML, both master manifests, each sketch's manifest no-cache
Other successful assets (including previews, fonts, shaders and scripts) public, max-age=86400
Health and errors no-store

ETag and Last-Modified support revalidation. Negotiated responses vary on Accept-Encoding. Directory and explicit index.html URLs, HEAD and video ranges are supported; directories without an index and missing/excluded paths return 404. No directory listing or SPA fallback is enabled. Responses permit public cross-origin reads without credentials. No iframe restriction is added, so the site and extension can embed artwork; the external proxy must preserve this.

Range requests use a loopback-only static listener inside the same Nginx process. This lets the public listener apply cache/CORS headers after Nginx determines the final 206 or 416 status; invalid ranges cannot inherit successful asset caching.

There is no immutable policy. Repaired scripts/media reuse filenames and may remain in returning visitors' caches for up to 24 hours. Rolling back an image does not immediately invalidate those browser caches. HTML and catalogues always revalidate; this change does not add offline extension storage.

Validation

node --test tests/unit/*.test.mjs tests/publish/*.test.mjs
bash tests/publish/check-credentials.sh
bash scripts/build-image.sh codedoodles-assets:local
bash scripts/test-image.sh codedoodles-assets:local
bash scripts/scan-image.sh codedoodles-assets:local
bash scripts/describe-image.sh codedoodles-assets:local
npm audit --prefix tests --audit-level=high

Use the pinned Node version for host commands. Building the image runs unit tests inside its pinned builder. The integration wrapper checks out exact merged site/extension commits from tests/integration.lock, builds them unchanged, and runs HTTP and Chromium/installed-extension tests in a pinned Playwright container. Do not change those clients' historical suites here. Update the fixture pins deliberately when testing a newer client.

The candidate, real clients and a local TLS proxy share an isolated Docker network. Both production hostnames resolve to that proxy only inside this test network. Self-signed certificate handling is test-only; extension packages and permissions remain unchanged. Tests exercise every packaged byte and gzip companion, all 76 entrypoints/manifests/previews, MIME types, caching, validators, ranges, exclusions, health and runtime restart. Browser tests cover Substrate, Particulate, Canvas/WebGL, preview seeking, refresh, input and real HTTP cache hits without request interception. Results and failure traces are in ignored tests/artifacts/; test certificates are excluded from CI artifacts.

External checks are separate: node scripts/smoke-host.mjs https://doodle.treyturner.info checks the currently exposed archive without expecting the new health/cache contract. Add --candidate when validating this image through an HTTPS proxy. External-service failures are reported separately from deterministic tests.

Runtime scans block unaccepted high/critical findings. The exception list starts empty; any future exception must be narrow, owned, time-limited and without an available fix. The tested image is saved with a checksum in CI artifacts even when publication credentials are unavailable. Size reporting distinguishes uncompressed layers from compressed registry-transfer layers; actual transfers can be smaller when the host already has layers.

Archive repairs and maintenance boundaries

Substrate's xp-substrate host has explicit block layout and positioning so its canvas has a usable size without the original Shadow DOM styling behavior. Particulate derives its route base from its script URL and accepts directory and index.html entrypoints, including the site's /__doodles/ development mount. Both repaired files retain gzip encoding under their original filenames.

Fury Ribbons (samsy/fury-ribbons, #073) was removed from both catalogues because the archive had only an unresolved submodule pointer with no artwork or source URL. Boobs (samsy/boobs, #074) is unpublished by editorial choice; its source remains in Git but is not in the image. The remaining entries retain their original IDs/numbers, preserving the site's existing shortlink destinations.

This container does not update artwork libraries, promise all historical sketches work on every GPU/browser, deploy production, or alter extension distribution.