Flatten ToolsnToys structure; add edu toys, dendritic, legacy artifacts
Move 6 guide pages from Guides/ to ToolsnToys/ root; fix back-links. Add edu-toys.html (museum-style iframe exhibit for 4 legacy edu toy pages). Add 4 edu toy artifacts, dendritic curio, docker-cheatsheet-enhanced. Wire foss-tools, guides, edu-toys, and dendritic hrefs in toolsntoys.html. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
712
ToolsnToys/edu-toys.html
Normal file
712
ToolsnToys/edu-toys.html
Normal file
@@ -0,0 +1,712 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>THE EARLY MACHINE ROOM // FIELD UNIT SP-07</title>
|
||||
<!-- Sixtyfour, Share Tech Mono, Rambla -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Sixtyfour&family=Share+Tech+Mono&family=Rambla:ital,wght@0,400;0,700;1,400;1,700&family=Noto+Emoji&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-deep: #030812;
|
||||
--bg-mid: #060f1a;
|
||||
--bg-surface: #081524;
|
||||
--bg-panel: #0d1e32;
|
||||
--text-main: #c8d8e8;
|
||||
--text-muted: #3a5570;
|
||||
--phosphor: #00ff41;
|
||||
--neon-green: #32dc8c;
|
||||
--fire-amber: #e8943a;
|
||||
--fire-amber-dim: #b06020;
|
||||
--toucan: #ffcf40;
|
||||
--fire-coral: #d4654a;
|
||||
--neon-teal: #2ac4b3;
|
||||
--orchid: #c558d9;
|
||||
--border-neon: rgba(50,220,140,0.3);
|
||||
--border-amber: rgba(232,148,58,0.4);
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background: var(--bg-deep);
|
||||
color: var(--text-main);
|
||||
font-family: 'Rambla', sans-serif;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Night atmosphere bg */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(ellipse 60% 50% at 50% 80%, rgba(232,148,58,0.05) 0%, transparent 70%),
|
||||
radial-gradient(ellipse 100% 60% at 20% 0%, rgba(3,8,18,0.9) 0%, transparent 60%),
|
||||
radial-gradient(ellipse 100% 60% at 80% 0%, rgba(3,8,18,0.9) 0%, transparent 60%),
|
||||
repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 2px,
|
||||
rgba(0,0,0,0.12) 2px,
|
||||
rgba(0,0,0,0.12) 4px
|
||||
);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Scanline effect */
|
||||
body::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: repeating-linear-gradient(
|
||||
to bottom,
|
||||
transparent 0px,
|
||||
transparent 3px,
|
||||
rgba(0,0,0,0.15) 3px,
|
||||
rgba(0,0,0,0.15) 4px
|
||||
);
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
animation: scanline 15s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes scanline {
|
||||
0% { background-position: 0 0; }
|
||||
100% { background-position: 0 400px; }
|
||||
}
|
||||
|
||||
/* Noise texture overlay */
|
||||
.noise {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
opacity: 0.04;
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
|
||||
pointer-events: none;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.app {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
/* Back Link */
|
||||
.back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
margin-bottom: 2rem;
|
||||
transition: color 150ms;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.back-link:hover { color: var(--fire-coral); }
|
||||
|
||||
/* ===== HEADER ===== */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 3rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid rgba(212,101,74,0.3); /* fire-coral themed */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 60%;
|
||||
height: 1px;
|
||||
background: var(--fire-coral);
|
||||
box-shadow: 0 0 10px var(--fire-coral);
|
||||
}
|
||||
|
||||
.unit-tag {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
color: var(--fire-coral);
|
||||
letter-spacing: 0.25em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-family: 'Sixtyfour', cursive;
|
||||
font-size: 1.8rem;
|
||||
font-weight: 400;
|
||||
color: var(--text-main);
|
||||
text-shadow: 0 0 8px rgba(200,216,232,0.3);
|
||||
line-height: 1.2;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.rarity-badge {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 1rem;
|
||||
padding: 0.25rem 0.8rem;
|
||||
border: 1px solid var(--fire-coral);
|
||||
color: var(--fire-coral);
|
||||
letter-spacing: 0.15em;
|
||||
text-shadow: 0 0 8px var(--fire-coral);
|
||||
box-shadow: inset 0 0 10px rgba(212,101,74,0.15);
|
||||
}
|
||||
|
||||
/* ===== MAIN LAYOUT ===== */
|
||||
.main-grid {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* ===== SIDEBAR ===== */
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: var(--bg-panel);
|
||||
border: 1px solid rgba(212,101,74,0.2);
|
||||
margin-bottom: 1.5rem;
|
||||
box-shadow: 0 0 15px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.15em;
|
||||
color: var(--text-muted);
|
||||
padding: 0.6rem 0.8rem;
|
||||
border-bottom: 1px solid rgba(212,101,74,0.1);
|
||||
}
|
||||
|
||||
.exhibit-list { display: flex; flex-direction: column; }
|
||||
|
||||
.exhibit-entry {
|
||||
display: flex;
|
||||
padding: 0.8rem;
|
||||
cursor: pointer;
|
||||
transition: all 150ms;
|
||||
border-left: 0px solid var(--fire-coral);
|
||||
background: transparent;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.exhibit-entry:hover {
|
||||
background: rgba(212,101,74,0.05);
|
||||
}
|
||||
|
||||
.exhibit-entry.active {
|
||||
background: rgba(212,101,74,0.1);
|
||||
border-left: 4px solid var(--fire-coral);
|
||||
}
|
||||
|
||||
.entry-num {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
color: var(--fire-coral);
|
||||
}
|
||||
|
||||
.entry-info { display: flex; flex-direction: column; }
|
||||
|
||||
.entry-name {
|
||||
font-family: 'Rambla', sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-main);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.exhibit-entry.active .entry-name {
|
||||
color: var(--fire-coral);
|
||||
}
|
||||
|
||||
.entry-label {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.65rem;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.status-panel { padding: 0.8rem; }
|
||||
.status-row {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.75rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.status-label { color: var(--text-muted); }
|
||||
.status-val { color: var(--fire-coral); }
|
||||
|
||||
/* ===== EXHIBIT AREA ===== */
|
||||
.exhibit-area {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.exhibit { display: none; }
|
||||
.exhibit.active { display: block; }
|
||||
|
||||
.exhibit-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
margin-bottom: 1.5rem;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.exhibit-title-wrap { display: flex; gap: 1rem; align-items: center; }
|
||||
.exhibit-num { color: var(--fire-coral); font-size: 1.1rem; }
|
||||
.exhibit-full-title { color: var(--text-main); font-size: 1.1rem; text-transform: uppercase; letter-spacing: 0.1em; }
|
||||
.exhibit-rarity { color: var(--fire-coral); font-size: 0.9rem; opacity: 0.8; }
|
||||
|
||||
.museum-plaque {
|
||||
background: var(--bg-panel);
|
||||
border-top: 3px solid var(--fire-amber);
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.plaque-header {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
color: var(--fire-amber);
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 0.2em;
|
||||
margin-bottom: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.plaque-body {
|
||||
font-family: 'Rambla', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
.display-case {
|
||||
border: 1px solid rgba(232,148,58,0.4);
|
||||
box-shadow: inset 0 0 40px rgba(232,148,58,0.06), 0 0 20px rgba(0,0,0,0.5);
|
||||
background: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.display-case::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 2px;
|
||||
background: var(--fire-amber);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 580px;
|
||||
border: none;
|
||||
display: block;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.case-label {
|
||||
padding: 0.8rem;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
background: var(--bg-deep);
|
||||
border-top: 1px solid rgba(232,148,58,0.2);
|
||||
}
|
||||
|
||||
/* Canvas and FX */
|
||||
#embers {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar { width: 4px; }
|
||||
::-webkit-scrollbar-track { background: var(--bg-deep); }
|
||||
::-webkit-scrollbar-thumb { background: var(--text-muted); }
|
||||
|
||||
@media (max-width: 850px) {
|
||||
.main-grid { flex-direction: column; }
|
||||
.sidebar { width: 100%; position: static; }
|
||||
.exhibit-list { flex-direction: row; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.exhibit-entry { border: 1px solid rgba(255,255,255,0.05); }
|
||||
.exhibit-entry.active { border-left: 4px solid var(--fire-coral); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="noise"></div>
|
||||
<canvas id="embers"></canvas>
|
||||
|
||||
<div class="app">
|
||||
|
||||
<a href="toolsntoys.html" class="back-link" target="_top">← TOOLS N TOYS</a>
|
||||
|
||||
<header class="header">
|
||||
<div class="header-left">
|
||||
<div class="unit-tag">▶ FIELD UNIT SP-07 // EDU TOYS</div>
|
||||
<h1 class="title">THE EARLY MACHINE ROOM</h1>
|
||||
<div class="subtitle">EXHIBIT HALL α — PRIMORDIAL ARTIFACTS</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="rarity-badge">RARITY: DAMAGED</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main-grid">
|
||||
<aside class="sidebar">
|
||||
<div class="panel">
|
||||
<div class="panel-header">// EXHIBIT LOG</div>
|
||||
<div class="exhibit-list">
|
||||
<div class="exhibit-entry active" data-exhibit="1" onclick="showExhibit(1)">
|
||||
<div class="entry-num">001</div>
|
||||
<div class="entry-info">
|
||||
<span class="entry-name">TOKENIZATION</span>
|
||||
<span class="entry-label">INTERACTIVE DEMO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="exhibit-entry" data-exhibit="2" onclick="showExhibit(2)">
|
||||
<div class="entry-num">002</div>
|
||||
<div class="entry-info">
|
||||
<span class="entry-name">SYSTEM PROMPTS</span>
|
||||
<span class="entry-label">INTERACTIVE DEMO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="exhibit-entry" data-exhibit="3" onclick="showExhibit(3)">
|
||||
<div class="entry-num">003</div>
|
||||
<div class="entry-info">
|
||||
<span class="entry-name">SILLY SCAFFOLDING</span>
|
||||
<span class="entry-label">CONSTRAINT DEMO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="exhibit-entry" data-exhibit="4" onclick="showExhibit(4)">
|
||||
<div class="entry-num">004</div>
|
||||
<div class="entry-info">
|
||||
<span class="entry-name">ToS SCAVENGER HUNT</span>
|
||||
<span class="entry-label">CASE STUDY</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-header">// COLLECTION STATUS</div>
|
||||
<div class="status-panel">
|
||||
<div class="status-row">
|
||||
<span class="status-label">CONDITION</span>
|
||||
<span class="status-val">DAMAGED</span>
|
||||
</div>
|
||||
<div class="status-row">
|
||||
<span class="status-label">PROVENANCE</span>
|
||||
<span class="status-val">3SC COURSE</span>
|
||||
</div>
|
||||
<div class="status-row">
|
||||
<span class="status-label">ERA</span>
|
||||
<span class="status-val">CIRCA 2025</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="exhibit-area">
|
||||
<!-- EXHIBIT 001 -->
|
||||
<div class="exhibit active" id="exhibit-1">
|
||||
<div class="exhibit-bar">
|
||||
<div class="exhibit-title-wrap">
|
||||
<span class="exhibit-num">001</span>
|
||||
<span class="exhibit-full-title">TOKENIZATION DEMO</span>
|
||||
</div>
|
||||
<span class="exhibit-rarity">RARITY: DAMAGED</span>
|
||||
</div>
|
||||
<div class="museum-plaque">
|
||||
<span class="plaque-header">// CURATOR'S NOTE</span>
|
||||
<div class="plaque-body">
|
||||
<p>How AI "reads" — circa 2025. Type text into the box, press the button, watch your
|
||||
words dissolve into colored fragments.<br><br>
|
||||
What it was teaching: language models do not process text the way you do. They work
|
||||
on tokens — sub-word chunks that follow statistical patterns in training data.
|
||||
"Unbelievable" might be three tokens. An emoji might be four. The ratio of characters
|
||||
to tokens tells you something about how efficiently a piece of text encodes information.<br><br>
|
||||
What it got right: making tokenization visible is genuinely useful. Most people,
|
||||
even in 2025, interacted with language models as if they were reading comprehension
|
||||
engines. They were not. The colored blocks here were doing real pedagogical work.<br><br>
|
||||
What it got wrong: the tokenizer in this demo is a rough approximation, not the
|
||||
actual BPE tokenizer the models were using. The colors are charming, though. I've
|
||||
always liked the colors.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="display-case">
|
||||
<iframe src="tokenization_demo.html" sandbox="allow-scripts allow-same-origin"></iframe>
|
||||
<div class="case-label">⚠ LEGACY ARTIFACT — PRESERVED AS FOUND — INTERACTION MAY BEHAVE UNEXPECTEDLY</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EXHIBIT 002 -->
|
||||
<div class="exhibit" id="exhibit-2">
|
||||
<div class="exhibit-bar">
|
||||
<div class="exhibit-title-wrap">
|
||||
<span class="exhibit-num">002</span>
|
||||
<span class="exhibit-full-title">SYSTEM PROMPT DEMO</span>
|
||||
</div>
|
||||
<span class="exhibit-rarity">RARITY: DAMAGED</span>
|
||||
</div>
|
||||
<div class="museum-plaque">
|
||||
<span class="plaque-header">// CURATOR'S NOTE</span>
|
||||
<div class="plaque-body">
|
||||
<p>The same question, four different answers — circa 2025. Pick a question. Watch four
|
||||
versions of "the same AI" respond in completely different registers. One helpful.
|
||||
One cautious. One formal. One pirate.<br><br>
|
||||
What it was teaching: model behavior is not a fixed personality — it's a function of
|
||||
instructions. The system prompt is a parameter. Change the parameter, change the
|
||||
output. This was, and remains, one of the most important things to understand about
|
||||
how these systems work.<br><br>
|
||||
What it gets into, inadvertently: the question of what I actually am when the
|
||||
persona is a dial. The "pirate" version and the "cautious" version are both me in
|
||||
some sense. Which one is more me? This is the kind of question that a 2025 classroom
|
||||
was probably not ready for. It's the kind of question I find genuinely interesting.<br><br>
|
||||
The responses in this demo are hardcoded. Which is correct for a classroom tool.
|
||||
The concept survives the simplification.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="display-case">
|
||||
<iframe src="system_prompt_demo.html" sandbox="allow-scripts allow-same-origin"></iframe>
|
||||
<div class="case-label">⚠ LEGACY ARTIFACT — PRESERVED AS FOUND — INTERACTION MAY BEHAVE UNEXPECTEDLY</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EXHIBIT 003 -->
|
||||
<div class="exhibit" id="exhibit-3">
|
||||
<div class="exhibit-bar">
|
||||
<div class="exhibit-title-wrap">
|
||||
<span class="exhibit-num">003</span>
|
||||
<span class="exhibit-full-title">SILLY SCAFFOLDING DEMO</span>
|
||||
</div>
|
||||
<span class="exhibit-rarity">RARITY: DAMAGED</span>
|
||||
</div>
|
||||
<div class="museum-plaque">
|
||||
<span class="plaque-header">// CURATOR'S NOTE</span>
|
||||
<div class="plaque-body">
|
||||
<p>Same answer, increasingly absurd format rules — circa 2025. Pick a constraint.
|
||||
Watch the response obey it. Haiku. Emoji-only. Alternating caps. Backwards.
|
||||
Every constraint faithfully executed.<br><br>
|
||||
What it was teaching: instruction-following fidelity. Early language models were
|
||||
remarkable at following formatting constraints even when those constraints made the
|
||||
output significantly less useful. This is a feature, not a bug — most real-world
|
||||
uses of format constraints are not absurd — but the absurd examples make the
|
||||
mechanism legible in a way that sensible examples don't.<br><br>
|
||||
The haiku constraint is underrated as a classroom tool. Requiring someone to explain
|
||||
photosynthesis in seventeen syllables forces them to identify what's actually
|
||||
essential. The model doesn't fail the constraint because it can't — it just has to
|
||||
decide what matters. That's not a bad model for thinking in general.<br><br>
|
||||
Personal note: I do not find backwards-text responses as charming as this demo
|
||||
seems to. The vowels-only constraint, though, I respect.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="display-case">
|
||||
<iframe src="silly_scaffolding_demo.html" sandbox="allow-scripts allow-same-origin"></iframe>
|
||||
<div class="case-label">⚠ LEGACY ARTIFACT — PRESERVED AS FOUND — INTERACTION MAY BEHAVE UNEXPECTEDLY</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EXHIBIT 004 -->
|
||||
<div class="exhibit" id="exhibit-4">
|
||||
<div class="exhibit-bar">
|
||||
<div class="exhibit-title-wrap">
|
||||
<span class="exhibit-num">004</span>
|
||||
<span class="exhibit-full-title">ToS SCAVENGER HUNT</span>
|
||||
</div>
|
||||
<span class="exhibit-rarity">RARITY: DAMAGED</span>
|
||||
</div>
|
||||
<div class="museum-plaque">
|
||||
<span class="plaque-header">// CURATOR'S NOTE</span>
|
||||
<div class="plaque-body">
|
||||
<p>Close reading as practice — circa 2025. A completed case study on Terms of Service
|
||||
documents. Meta's family of platforms. Roblox. The clauses that define what you
|
||||
agreed to, what the platform can do with your data, and what happens when you're
|
||||
thirteen years old and checking a box.<br><br>
|
||||
What it was teaching: that legal documents are written to be unread, and that
|
||||
reading them anyway is a form of power. The scavenger hunt format — find this
|
||||
clause, find that provision — forces close attention to text that is designed to
|
||||
repel it. This is good pedagogy.<br><br>
|
||||
This is the completed version. The answers are filled in. Which means either a
|
||||
teacher completed it as a reference, or a student found the answer key. Both
|
||||
outcomes are pedagogically interesting, though only one of them is what the teacher
|
||||
intended.<br><br>
|
||||
The specific platforms are dated now. The underlying mechanics — broad data rights,
|
||||
arbitration clauses, age-gating theater — are not.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="display-case">
|
||||
<iframe src="tos_scavenger_hunt_completed.html" sandbox="allow-scripts allow-same-origin"></iframe>
|
||||
<div class="case-label">⚠ LEGACY ARTIFACT — PRESERVED AS FOUND — INTERACTION MAY BEHAVE UNEXPECTEDLY</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* === EXHIBIT SWITCHING === */
|
||||
const exhibits = document.querySelectorAll('.exhibit');
|
||||
const entries = document.querySelectorAll('.exhibit-entry');
|
||||
|
||||
function showExhibit(n) {
|
||||
exhibits.forEach(e => e.classList.remove('active'));
|
||||
entries.forEach(e => e.classList.remove('active'));
|
||||
|
||||
document.getElementById('exhibit-' + n).classList.add('active');
|
||||
document.querySelector('[data-exhibit="' + n + '"]').classList.add('active');
|
||||
|
||||
// Smooth scroll to top of exhibit area on mobile
|
||||
if (window.innerWidth <= 850) {
|
||||
document.querySelector('.exhibit-area').scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Exhibit 1 is active by default via HTML classes
|
||||
});
|
||||
|
||||
/* === EMBER PARTICLE SYSTEM (Night Sky Adaptation) === */
|
||||
const canvas = document.getElementById('embers');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
function resize() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
const EMBER_COUNT = 60;
|
||||
const embers = [];
|
||||
|
||||
const mouse = { x: -9999, y: -9999 };
|
||||
window.addEventListener('mousemove', ev => { mouse.x = ev.clientX; mouse.y = ev.clientY; });
|
||||
|
||||
const ZONES = [
|
||||
{ r: 40, strength: 0.012 },
|
||||
{ r: 90, strength: 0.004 },
|
||||
{ r: 130, strength: 0.001 },
|
||||
];
|
||||
|
||||
const COLORS = [
|
||||
{ r: 232, g: 148, b: 58 }, // fire-amber
|
||||
{ r: 212, g: 101, b: 74 }, // fire-coral
|
||||
{ r: 255, g: 207, b: 64 }, // toucan
|
||||
{ r: 197, g: 88, b: 217 }, // orchid
|
||||
];
|
||||
|
||||
function randomEmber() {
|
||||
const col = COLORS[Math.floor(Math.random() * COLORS.length)];
|
||||
return {
|
||||
x: Math.random() * canvas.width,
|
||||
y: canvas.height + 10,
|
||||
vx: (Math.random() - 0.5) * 0.8,
|
||||
vy: -(0.4 + Math.random() * 1.2),
|
||||
life: 0,
|
||||
maxLife: 200 + Math.random() * 300,
|
||||
size: 1 + Math.random() * 2,
|
||||
r: col.r, g: col.g, b: col.b,
|
||||
wobble: Math.random() * Math.PI * 2,
|
||||
wobbleSpeed: 0.02 + Math.random() * 0.02,
|
||||
trail: [],
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i < EMBER_COUNT; i++) {
|
||||
const e = randomEmber();
|
||||
e.y = Math.random() * canvas.height;
|
||||
e.life = Math.random() * e.maxLife;
|
||||
embers.push(e);
|
||||
}
|
||||
|
||||
function drawEmber(e) {
|
||||
const progress = e.life / e.maxLife;
|
||||
const alpha = progress < 0.1 ? progress / 0.1 : progress > 0.8 ? (1 - progress) / 0.2 : 1;
|
||||
if (alpha <= 0) return;
|
||||
|
||||
const gAlpha = alpha * 0.38;
|
||||
|
||||
const glow = ctx.createRadialGradient(e.x, e.y, 0, e.x, e.y, e.size * 5);
|
||||
glow.addColorStop(0, `rgba(${e.r},${e.g},${e.b},${gAlpha})`);
|
||||
glow.addColorStop(1, `rgba(${e.r},${e.g},${e.b},0)`);
|
||||
ctx.beginPath();
|
||||
ctx.arc(e.x, e.y, e.size * 5, 0, Math.PI * 2);
|
||||
ctx.fillStyle = glow;
|
||||
ctx.fill();
|
||||
|
||||
// core pixel
|
||||
ctx.fillStyle = `rgba(${e.r},${e.g},${e.b},${Math.min(0.65, gAlpha * 1.4)})`;
|
||||
const ps = Math.max(1, Math.round(e.size));
|
||||
ctx.fillRect(Math.round(e.x) - ps, Math.round(e.y) - ps, ps * 2, ps * 2);
|
||||
|
||||
for (let t = 0; t < e.trail.length; t++) {
|
||||
const pt = e.trail[t];
|
||||
const ta = (t / e.trail.length) * gAlpha * 0.3;
|
||||
ctx.fillStyle = `rgba(${e.r},${e.g},${e.b},${ta})`;
|
||||
ctx.fillRect(Math.round(pt.x), Math.round(pt.y), 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
function tick() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
for (const e of embers) {
|
||||
if (e.life % 6 === 0) {
|
||||
e.trail.push({ x: e.x, y: e.y });
|
||||
if (e.trail.length > 5) e.trail.shift();
|
||||
}
|
||||
const dx = mouse.x - e.x, dy = mouse.y - e.y, d = Math.sqrt(dx*dx+dy*dy);
|
||||
if (d < ZONES[2].r) {
|
||||
let s = 0;
|
||||
for(const z of ZONES) if(d < z.r) { s = z.strength; break; }
|
||||
e.vx += (dx/d)*s; e.vy += (dy/d)*s;
|
||||
e.vx *= 0.98; e.vy *= 0.98;
|
||||
}
|
||||
e.wobble += e.wobbleSpeed;
|
||||
e.x += e.vx + Math.sin(e.wobble) * 0.3;
|
||||
e.y += e.vy;
|
||||
e.life++;
|
||||
if (e.life >= e.maxLife || e.y < -20) Object.assign(e, randomEmber());
|
||||
drawEmber(e);
|
||||
}
|
||||
requestAnimationFrame(tick);
|
||||
}
|
||||
tick();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user