An open archive of motion-captured graffiti, running since 2009. Every tag is a GML file: the writer's hand as coordinates and timestamps, replayable by anyone. Writers capture and share tags; programmers build things that read them. Live at 000000book.com.
Rails 8.1 on Ruby 3.4, MySQL 8.4, deployed as a container by Kamal. No Node build step: assets go through Propshaft and the player is plain ES modules.
docker compose up -d # MySQL 8.4, the version the server runs
bundle install
bin/rails db:prepare
bin/rails db:seed # development only: real app names on the test tags
bin/rails server # http://localhost:3000
bundle exec rspec # no environment variables neededMYSQL_PORT and MYSQL_PASSWORD override config/database.yml.
public/canvasplayer/<version>/is canvasplayer, byte for byte.SOURCEthere says how to update. It lives outside the asset pipeline because Propshaft's fingerprints would break the modules' relative imports.app/assets/javascripts/player.js,gml_thumbnails.jsandrecorder.jsare the only player code that belongs here: the tag page, the live grid cells, and the recorder on/upload.data/<id>.gmlis each tag's file, read and written byGmlObject. Images are Active Storage on local disk.docs/is the API and GML documentation, served at /docs and indexed by /llms.txt./apiredirects there and/openapi.yamlis the machine-readable version.
/and/dataplay one tag beside the grid. Click a cell, press ← →, or let it run on like a slideshow. The front page keeps quiet: no labels, just the tags and the player's readout./data/:idis one tag with a filmstrip of its neighbours. Controls opens the pane: looks, live or still, ink mode, effects, data layers./appsplays the newest tag made with each app./uploadexplains how to make a tag and lets you draw one.
GET /data/:id.gml,.jsonor.xml.?preview=1is about 300 points for thumbnails;?player=1is the full-fidelity payload the site plays.POST /datawithgml=uploads. Details in docs/api.
./script/rehearse-migrations.sh # pending migrations against production's real schema
bin/rails data:validate # read-only audit; exits non-zero on blockers
bin/rails gml_objects:save_to_disk
bin/rails gml_objects:fix_missing
bin/rails tags:find_missing_dataThe test database is built from schema.rb and has never looked like
production, which is still MyISAM and utf8mb3, so rehearse before any deploy.
Migrations never run on deploy; the pending set drops the comments table.
tags:delete_missing_data destroys rows and needs
CONFIRM_DELETE=yes-i-have-a-backup.
kamal deploy # beta: build, push, roll over
kamal rollback
kamal migrate # deliberate, never automatic
./deploy [git-ref] # production, until Kamal serves it
script/audit-production.sh # read-only
script/backup-production.sh
script/resync-beta.shdocs/deployment.md and docs/operations.md have the detail.
Jamie Wilkinson, Evan Roth, Theodore Watson, Chris Sugrue and Todd Vanderlin of the copyleft F.A.T. Lab, with Flash help from Manolis Perrakis. Contact info[at]000000book.com. MIT licensed. Copyfree 2009 onward. "Release early, often & w/ rap music."