Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

are.na-annual: validator + primary-source swap proposal

Adds validate-sources.mjs that reads the live channel and flags
every Wikipedia link (52 of 68) plus fetches are.na search results
to surface what other users are connecting for the same topic.
The search endpoint is Cloudflare-gated for unauthed requests, so
the 'nearby' column is empty until ARENA_TOKEN is exported.

Drafts source-swaps.md — a full replacement table with primary
URLs (UbuWeb, Monoskop, Fasola, Mela Foundation, Earle Brown
Foundation, Noa Eshkol Foundation, Dance Notation Bureau, Terry
Riley site, NYT Jalaiah profile, etc.). Also flags three wiki
links that redirect to unrelated pages (Water Yam → yam tuber,
Gahu → Iranian village, Renegade → K Camp song). Proposes blocks
to ADD from the whistlegraph paper citations: Goodiepal El Camino
del Hardcore, Dirt Magazine profile, Rhizome Longest Whistlegraph,
Paper Rad, Schloss-Post RDP manifesto, Sex Magazine, CI essay.

No channel writes yet — review swaps.md first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+286
+118
gigs/are-na-annual-vol-8/source-swaps.md
··· 1 + # Source swaps — remove wikipedia, add primary sources 2 + 3 + current channel: 68 blocks · **52 are wikipedia** · 3 go to the wrong page entirely 4 + 5 + ## critical fixes (wikipedia redirected to unrelated page) 6 + 7 + | # | current (broken) | swap to | 8 + |---|---|---| 9 + | 1 | `Renegade_(dance)` → goes to "Lottery (K Camp song)" | **NYT 2020 — Taylor Lorenz profile of Jalaiah Harmon**: https://www.nytimes.com/2020/02/13/style/the-original-renegade.html — the actual primary source for the story | 10 + | 33 | `Water_Yam` → goes to "Dioscorea alata" (yam tuber!) | **Monoskop — George Brecht, Water Yam**: https://monoskop.org/Water_Yam — scans + bibliography | 11 + | 31 | `Gahu` → goes to "Gahuiyeh, Kerman" (Iranian village) | **Ladzekpo / CNMAT archive** or **Mustapha Tettey Addy** – https://cnmat.berkeley.edu/library/cdr/ewa or drop for another drum tradition | 12 + | 52 | `moma.org/s/ge/curated_ge/styles/list_ge/artists/1191/` → Page not found | **MoMA — Notations (1969) catalog**: https://www.moma.org/calendar/exhibitions/3282 | 13 + 14 + ## graphic-score canon — swap to ubuweb, monoskop, foundations 15 + 16 + | # | wiki | primary | 17 + |---|---|---| 18 + | 38 | Treatise (Cardew) | **Monoskop — Cornelius Cardew**: https://monoskop.org/Cornelius_Cardew | 19 + | 39 | Fontana Mix | **UbuWeb — Cage Fontana Mix**: https://www.ubu.com/sound/cage.html | 20 + | 40 | Aria (Cage) | **UbuWeb — Cage Aria**: https://www.ubu.com/film/cage_aria.html | 21 + | 41 | Concert for Piano and Orchestra (Cage) | **Edition Peters — Cage Concert**: https://www.edition-peters.com/product/concert-for-piano-and-orchestra/ep6705 | 22 + | 42 | Variations I (Cage) | **UbuWeb — Cage Variations**: https://www.ubu.com/historical/cage/ | 23 + | 43 | December 1952 (Earle Brown) | **Earle Brown Music Foundation**: https://earle-brown.org | 24 + | 44 | Morton Feldman | **CNVill Feldman archive**: https://cnvill.net/mfhome.htm | 25 + | 45 | Christian Wolff | **CNVill Wolff archive**: https://cnvill.net/mfwolff.htm | 26 + | 46 | Artikulation (Ligeti) | **UbuWeb — Wehinger listening score video**: https://www.ubu.com/film/wehinger_artikulation.html | 27 + | 47 | Metastaseis (Xenakis) | **Iannis Xenakis site / CIX**: https://www.iannis-xenakis.org | 28 + | 48 | Sonic Meditations (Oliveros) | **Pauline Oliveros Foundation / Deep Listening**: https://deeplistening.rpi.edu | 29 + | 49 | I Am Sitting in a Room | **UbuWeb — Lucier**: https://www.ubu.com/sound/lucier.html | 30 + | 50 | In C (Riley) | **Terry Riley**: https://terryriley.net | 31 + | 51 | Composition 1960 (La Monte Young) | **Mela Foundation**: https://www.melafoundation.org | 32 + | 53 | Notations 21 | **Mark Batty / Theresa Sauer**: https://www.notations21.com (or author site) | 33 + 34 + ## fluxus / event scores 35 + 36 + | # | wiki | primary | 37 + |---|---|---| 38 + | 32 | Grapefruit (Yoko Ono) | **imagine-peace.com / Ono Grapefruit scans on Monoskop**: https://monoskop.org/images/c/c7/Ono_Yoko_Grapefruit_1971.pdf | 39 + | 34 | Dick Higgins | **Something Else Press archive / Estate of Dick Higgins**: http://www.dickhiggins.org | 40 + | 35 | An Anthology of Chance Operations | **Monoskop**: https://monoskop.org/An_Anthology_of_Chance_Operations | 41 + | 36 | Alison Knowles | **aknowles.com** (primary): https://www.aknowles.com | 42 + 43 + ## vernacular / folk notation 44 + 45 + | # | wiki | primary | 46 + |---|---|---| 47 + | 24 | Shape note | **Fasola.org — Sacred Harp Musical Heritage**: https://fasola.org | 48 + | 25 | Sacred Harp | **Sacred Harp Publishing Co.**: https://originalsacredharp.com | 49 + | 26 | Tablature | **Lute Society of America**: https://lutesocietyofamerica.org (or guitar tablature primary source?) | 50 + | 27 | Neume | **Gregobase — Gregorian chant notation**: https://gregobase.selapa.net | 51 + | 28 | Jianpu | consider dropping, or: **Zhu Zaiyu / historical primer**; no strong primary online | 52 + | 29 | Gongche notation | consider dropping, or a Kunqu / Peking opera archive link | 53 + | 30 | Sargam | **ITC Sangeet Research Academy**: https://www.itcsra.org | 54 + 55 + ## body / movement notation 56 + 57 + | # | wiki | primary | 58 + |---|---|---| 59 + | 14 | Labanotation | **Dance Notation Bureau**: https://dancenotation.org | 60 + | 15 | Eshkol–Wachman | **Noa Eshkol Foundation**: https://www.noaeshkol.org | 61 + | 16 | Benesh | **Royal Academy of Dance — Benesh**: https://www.royalacademyofdance.org/benesh | 62 + | 17 | Kata | **JKA — Japan Karate Association / kata catalog**: https://jka.or.jp | 63 + | 18 | American football plays | **Walsh's West Coast Offense playbook scans / NFL Coaches' resources** — or drop for a Bill Walsh interview | 64 + 65 + ## sport / line 66 + 67 + | # | wiki | primary | 68 + |---|---|---| 69 + | 19 | Skateboarding | **Thrasher Mag**: https://www.thrashermagazine.com | 70 + | 20 | Dogtown and Z-Boys | **Stacy Peralta / Z-Boys documentary**: https://www.imdb.com/title/tt0275309/ or https://www.dogtownskateboards.com | 71 + | 21 | Surf break | **Surfline**: https://www.surfline.com | 72 + | 22 | Yardage book | **StrackaLine — modern yardage-book publisher**: https://strackaline.com | 73 + | 23 | Parkour | **ADAPT / parkour UK governing body**: https://parkour.uk | 74 + 75 + ## instructional / craft 76 + 77 + | # | wiki | primary | 78 + |---|---|---| 79 + | 6 | Knitting abbreviations | **Craft Yarn Council standards**: https://www.craftyarncouncil.com/standards/knit-abbreviations | 80 + | 7 | Crease pattern | **Erik Demaine — origami and folding**: https://erikdemaine.org/origami | 81 + | 9 | Sewing pattern | **McCall's / Vogue pattern archive**: https://mccall.com | 82 + | 10 | IKEA | **IKEA assembly instructions library**: https://www.ikea.com/us/en/customer-service/services/assembly | 83 + | 11 | Lego | **LEGO building instructions archive**: https://www.lego.com/en-us/service/buildinginstructions | 84 + | 12 | Julia Child | **WGBH — The French Chef / American Archive of Public Broadcasting**: https://americanarchive.org/catalog?q=julia+child | 85 + | 13 | Japanese tea ceremony | **Urasenke**: https://www.urasenke.or.jp | 86 + 87 + ## viral / social kin 88 + 89 + | # | current | primary | 90 + |---|---|---| 91 + | 2 | Harlem Shake (meme) | **Filthy Frank original video**: https://www.youtube.com/watch?v=384IUU43bfQ | 92 + | 3 | Know Your Meme — Squidward (404!) | **Squidward tutorial original video** (YouTube search needed) | 93 + | 4 | Pictogram | **Otl Aicher — Munich '72 pictogram archive**: https://www.designreviewed.com/otl-aicher-munich-1972 | 94 + | 5 | ISOTYPE | **Otto Neurath / Gerd Arntz Web Archive**: https://www.gerdarntz.org/isotype | 95 + 96 + ## additional blocks to *add* (from whistlegraph.tex citations) 97 + 98 + these are specific, real, less cliché: 99 + 100 + - **Goodiepal — El Camino del Hardcore** (ALKU 83, 2012) — https://alku.org/alku-83 or discogs 101 + - **Jacob Ciocci — "The Butterfly Effect / Rules Set You Free"** (Whistlegraph Zine, 2023) — zine catalog page if exists 102 + - **Asher Penn — Sex Magazine**: https://sexmagazine.us 103 + - **Dirt Magazine — "What is a Whistlegraph?"** (2023): https://dirt.fyi/article/2023/09/whistlegraph 104 + - **Rhizome — First Look: The Longest Whistlegraph Ever**: https://rhizome.org/editorial/2022/sep/13/first-look-the-longest-whistlegraph-ever-so-far 105 + - **Feral File — Ten Whistlegraphs exhibition page**: https://feralfile.com/exhibitions/ten-whistlegraphs-thv 106 + - **Schloss-Post — Manifesto for Radical Digital Painting** (2017): https://schloss-post.com/manifesto-radical-digital-painting 107 + - **Creative Independent — "Drawing is the Best Videogame"** (2019): https://thecreativeindependent.com/weekends/drawing-is-the-best-videogame-by-jeffrey-alan-scudder 108 + - **Paper Rad** (Jacob Ciocci): http://www.paperrad.org 109 + 110 + ## execution plan 111 + 112 + 1. `gigs/are-na-annual-vol-8/swap-sources.mjs` — read approved swaps, for each: delete old block from channel, post new URL with same description 113 + 2. keep positions stable — post in reverse reading order so nothing rearranges 114 + 3. text blocks (§9 framing, §6 Ono quote) are untouched — they're already primary 115 + 116 + ## what the `nearby` validator can't tell us without a token 117 + 118 + are.na's `/v2/search/blocks` requires auth. once `ARENA_TOKEN` is exported, re-run `node validate-sources.mjs` and it will surface which URLs already have dozens of connections on are.na — those are the de-facto primaries.
+168
gigs/are-na-annual-vol-8/validate-sources.mjs
··· 1 + #!/usr/bin/env node 2 + // Validate the blocks in "the-score-that-teaches-itself": 3 + // - flag every Wikipedia link (we want primary sources) 4 + // - for each block, search are.na for existing uses of the same URL 5 + // and of the topic name — so we can see what other people 6 + // are connecting to for the same idea (usually the real source) 7 + // 8 + // Usage: 9 + // ARENA_TOKEN=... node validate-sources.mjs # all blocks 10 + // ARENA_TOKEN=... node validate-sources.mjs --wiki # wiki only 11 + // ARENA_TOKEN=... node validate-sources.mjs --json > report.json 12 + // 13 + // ARENA_TOKEN is optional but greatly raises rate limits. 14 + 15 + const SLUG = "the-score-that-teaches-itself"; 16 + const TOKEN = process.env.ARENA_TOKEN; 17 + const API = "https://api.are.na/v2"; 18 + 19 + const args = new Set(process.argv.slice(2)); 20 + const WIKI_ONLY = args.has("--wiki"); 21 + const JSON_OUT = args.has("--json"); 22 + 23 + const headers = TOKEN 24 + ? { Authorization: `Bearer ${TOKEN}` } 25 + : {}; 26 + 27 + async function j(url) { 28 + const r = await fetch(url, { headers }); 29 + if (!r.ok) throw new Error(`${r.status} ${r.statusText} — ${url}`); 30 + return r.json(); 31 + } 32 + 33 + function isWiki(url) { 34 + return url && /wikipedia\.org/i.test(url); 35 + } 36 + 37 + function hostOf(url) { 38 + try { return new URL(url).hostname.replace(/^www\./, ""); } catch { return ""; } 39 + } 40 + 41 + // Pull a short topic phrase out of a title like "Treatise (Cardew) - Wikipedia" 42 + function topicOf(title) { 43 + if (!title) return ""; 44 + return title 45 + .replace(/\s*[-–—|]\s*Wikipedia.*$/i, "") 46 + .replace(/^\s+|\s+$/g, ""); 47 + } 48 + 49 + // Search are.na for any blocks whose source matches the URL (or title) 50 + // Returns an array of { url, host, count, sample: [{channelSlug, user}] } 51 + async function searchSimilar(block) { 52 + const out = { exact: [], nearby: [] }; 53 + const url = block.source?.url; 54 + const topic = topicOf(block.title) || block.generated_title || ""; 55 + // 1) exact URL — search /search/blocks for the URL itself 56 + if (url) { 57 + try { 58 + const q = encodeURIComponent(url); 59 + const r = await j(`${API}/search/blocks?q=${q}&per=10`); 60 + for (const b of r.blocks || []) { 61 + if (b.source?.url === url) { 62 + out.exact.push({ 63 + id: b.id, 64 + title: b.title || b.generated_title, 65 + url: b.source.url, 66 + connections: b.connections_count || 0, 67 + }); 68 + } 69 + } 70 + } catch (e) { out.err = e.message; } 71 + } 72 + // 2) topic phrase — find the most-connected non-wiki blocks for the same idea 73 + if (topic) { 74 + try { 75 + const q = encodeURIComponent(topic); 76 + const r = await j(`${API}/search/blocks?q=${q}&per=20`); 77 + const seen = new Set(); 78 + for (const b of r.blocks || []) { 79 + const bu = b.source?.url; 80 + if (!bu) continue; 81 + if (seen.has(bu)) continue; 82 + seen.add(bu); 83 + if (bu === url) continue; 84 + if (isWiki(bu)) continue; 85 + out.nearby.push({ 86 + url: bu, 87 + host: hostOf(bu), 88 + title: b.title || b.generated_title, 89 + connections: b.connections_count || 0, 90 + }); 91 + } 92 + out.nearby.sort((a, b) => b.connections - a.connections); 93 + out.nearby = out.nearby.slice(0, 5); 94 + } catch (e) { out.err = (out.err || "") + "; " + e.message; } 95 + } 96 + return out; 97 + } 98 + 99 + function fmtReport(rows) { 100 + const lines = []; 101 + for (const row of rows) { 102 + const flag = row.isWiki ? "🟡 WIKI" : "⚪ primary"; 103 + const url = row.url || "(text)"; 104 + const host = hostOf(url) || "—"; 105 + lines.push(`\n#${row.position} ${flag} [${host}]`); 106 + lines.push(` title : ${row.title || row.content?.slice(0, 80) || "(empty)"}`); 107 + lines.push(` url : ${url}`); 108 + lines.push(` desc : ${(row.description || "").slice(0, 100)}`); 109 + if (row.sim) { 110 + if (row.sim.exact?.length) { 111 + lines.push(` ↳ already on are.na: ${row.sim.exact.length} exact block(s), top connections: ${row.sim.exact.slice(0, 3).map(e => e.connections).join("/")}`); 112 + } else if (url) { 113 + lines.push(` ↳ not on are.na (exact URL) — fresh`); 114 + } 115 + if (row.sim.nearby?.length) { 116 + lines.push(` ↳ alternate sources people connect for this topic:`); 117 + for (const n of row.sim.nearby) { 118 + lines.push(` • [${n.host}] ${n.connections}× conn — ${n.url}`); 119 + } 120 + } 121 + } 122 + } 123 + return lines.join("\n"); 124 + } 125 + 126 + async function main() { 127 + console.error(`fetching /channels/${SLUG}/contents …`); 128 + const ch = await j(`${API}/channels/${SLUG}/contents?per=100&direction=desc`); 129 + const blocks = ch.contents || []; 130 + console.error(`got ${blocks.length} blocks${TOKEN ? "" : " (unauthed, rate limits apply)"}\n`); 131 + 132 + const rows = []; 133 + for (const b of blocks) { 134 + const url = b.source?.url; 135 + const row = { 136 + position: b.position, 137 + class: b.class, 138 + title: b.title, 139 + content: b.content, 140 + description: b.description, 141 + url, 142 + isWiki: isWiki(url), 143 + }; 144 + if (WIKI_ONLY && !row.isWiki) { rows.push(row); continue; } 145 + if (b.class === "Link") { 146 + try { 147 + row.sim = await searchSimilar(b); 148 + process.stderr.write("."); 149 + } catch (e) { 150 + row.simErr = e.message; 151 + process.stderr.write("x"); 152 + } 153 + await new Promise(r => setTimeout(r, 400)); // gentle rate limit 154 + } 155 + rows.push(row); 156 + } 157 + console.error("\n"); 158 + 159 + if (JSON_OUT) { 160 + console.log(JSON.stringify({ channel: SLUG, at: new Date().toISOString(), rows }, null, 2)); 161 + } else { 162 + console.log(fmtReport(rows)); 163 + const wikiCount = rows.filter(r => r.isWiki).length; 164 + console.log(`\n\nsummary: ${rows.length} blocks · ${wikiCount} wikipedia link(s) flagged for swap`); 165 + } 166 + } 167 + 168 + main().catch(e => { console.error("error:", e.message); process.exit(1); });