{
"path": "/3mejhoehqjk2y",
"site": "at://did:plc:aurnkk6uy6axy66uqaq6dqy6/site.standard.publication/3m6gjuzizxc27",
"tags": [],
"$type": "site.standard.document",
"title": "My job...is just...context window",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"id": "019c481c-5e7e-755e-9b9a-4c2e82117941",
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreiamlti5gqiude6yvtryrpbzo4sunddtpcv5zpoz3evtrjzwr2r2nm"
},
"mimeType": "image/jpeg",
"size": 38108
},
"aspectRatio": {
"width": 500,
"height": 502
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 1,
"facets": [],
"plaintext": "All I think about is the context window"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "The context window is an array. We malloc it. "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 109,
"byteStart": 101
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "When I'm Ralphing, I'm mostly just...managing that array. This has meant I am more intentional about starting Claude sessions with a specific goal (and sometimes that goal is...wtf is going on, I need an entire session just to orient myself to latest changes). And then when the goal shifts, time for a fresh context window. "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 21,
"byteStart": 14
},
"features": [
{
"uri": "https://www.youtube.com/watch?v=C1YNGy6qusg",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "(btw see this podcast or google Geoffrey Huntley to hear him talk about all this)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 1,
"facets": [],
"plaintext": "The files I care about "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 53,
"byteStart": 48
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
},
{
"index": {
"byteEnd": 149,
"byteStart": 102
},
"features": [
{
"uri": "https://github.com/ghuntley/how-to-ralph-wiggum",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "(Caveat: not trying to pretend my practices are best practices, but this is what's evolved for me see https://github.com/ghuntley/how-to-ralph-wiggum) "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 22,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "IMPLEMENTATION_PLAN.md"
},
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "this is where the literal tasks go, with [ ] syntax so agents/Ralphs can find their assignment."
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "I often will spin up a Ralph and first thing say \"we are going to deliver an IMPLEMENTATION_PLAN.md based on {whatever the current goal is}\" That keeps the session on track. We don't fix things in a session like this (that would wreck the context window with confusing artifacts), we just find and add to the plan. "
},
"children": []
}
]
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 7,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "loop.sh"
},
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "this is the bash that kicks of the loops. I run with caffeinate"
},
"children": []
}
]
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 7,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "tests/*"
},
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "So many tests. Lots of playwright tests. Tests for everything. Agent runs them on every loop. "
},
"children": []
}
]
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "specs/*.md"
},
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "This is the docs/library/history/everything directory. Human readable. Kept as up to date as possible (& a source of bugs when not up to date!). "
},
"children": []
}
]
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.image",
"image": {
"$type": "blob",
"ref": {
"$link": "bafkreiah5xjbryvhqg6qtqeolwxx7kdbjgjfon5ahzxqa6ts3ijmniuvui"
},
"mimeType": "image/png",
"size": 61882
},
"aspectRatio": {
"width": 588,
"height": 574
}
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 43,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "^ the specs/ for a jpeg glitch art project."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"id": "019c4834-2e22-7eeb-82da-dd2f4da8cb63",
"$type": "pub.leaflet.blocks.page"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 1,
"facets": [],
"plaintext": "Benefits to focusing on context window "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 158,
"byteStart": 154
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "When Ralphing, my attention budget is best spent on the files listed above. It's a tractable human-sized job to stay on top of just those things. I still can dive into the code of course, but there's no assumption that I have. "
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Getting in the flow with a single agent is seductive and dangerous! If the back/forth with an agent is building up a nice context, that should be preserved in markdown. With the agent, figure out what you've decided on. Then put a record of that (& organized directory-wise/with the naming of the md file so future instances will find it) in markdown! Markdown is forever. Context window is ephemeral. "
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 1,
"facets": [],
"plaintext": "Other thoughts (apologies for grammar/etc...feel free to not read)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "wisprflow is great. On the free trial right now. Might look for a free-free alternative but also might just pay. The ability to start a voice memo, then click around and look for things in IDE, then come back to voice memo and get it into claude...very nice. "
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 186,
"byteStart": 179
},
"features": [
{
"uri": "https://loop.sh",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "claude code + vscode terminal = bad marriage. I am having more luck with iTerm2. So VSCode I still have open, and I use it to inspect the codebase/do human coder things, but CC + loop.sh runs via iTerm2. "
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 268,
"byteStart": 258
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "We need a new IDE. Out-of-the-loop coding is different enough, there needs to be a new form factor for doing this. Very open to trying alternative apps if people know of any! I want a kan-ban board mixed with the github web PR review interface (probably not literally that...but something that makes the diffs first class + super obvious) mixed with the current claude code interface but also super customizable and yeah. idk. Interested to watch this space I think it's gonna get chaotic and very 1K-flowers-blooming-coded. "
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 7
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "when I am in the loop, that's cool too (but it's now an intentional choice). In the loop for me means just a session with CC. Subagents for any research task to preserve context window, but otherwise just yeah going item by item having CC execute changes. "
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 93,
"byteStart": 28
},
"features": [
{
"uri": "https://www.imdb.com/title/tt3844782/",
"$type": "pub.leaflet.richtext.facet#link"
}
]
},
{
"index": {
"byteEnd": 178,
"byteStart": 172
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
},
{
"index": {
"byteEnd": 326,
"byteStart": 321
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "silly analogy for Ralphing: Nathan For You episode where 40 maids clean a house in 15 minutes. It really is kind of like that. Each Ralph has a very very narrow focus, and won't have full context of the entire project. And so the art of this technique seems to be setting up /spec/*.md so each Ralph can find the info it does need. Making sure the maid whose task is 'clean the kitchen sink' can find the sponge, not the vacuum (because...to murder this analogy...if you give Ralph a vacuum and say 'vacuums are for cleaning' but also 'your job is to clean the shower' Ralph may vacuum the shower)"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Another silly analogy: that game/lesson where you make someone write down instructions for making a PB&J sandwich, and then you follow the instructions, but badly"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Q & A format...that's something Geoffrey Huntley demonstrates in a demo and I am loving. Have the agent ask you questions to make a plan. It uncovers misunderstandings really well and is super info dense. "
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Agentic coding can be freaky/bizarre. I am not at all sure that I'm not just fooling myself into feeling productive. It does feel very productive, though. And it can be exhausting in an unfamiliar way, making lots of decisions. I'll every so often think back to an afternoon at work (not that long ago!) where all I would do is wrestle some npm dependency or something. Manually upgrading and downgrading packages. Things that now you can just ... throw the agent at."
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 125,
"byteStart": 99
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#bold"
}
]
}
],
"plaintext": "Keeping to the theme of 'narrow you focus', here's something I think can be said about LLM coding: agents are fast, I am slow."
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Another (last one!) weird quasi-analogy in my head as I do this stuff: Ralphing is like driving a manual car but there's no first gear. So you ease off the clutch and you're either gonna: "
},
"children": [
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "1: stall out"
},
"children": []
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 3,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "2: engage 3rd gear and suddenly be moving at 25 mph thru the parking lot. "
},
"children": []
}
]
},
{
"$type": "pub.leaflet.blocks.unorderedList#listItem",
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Geoffrey Huntley's pottery analogy is really nice. As is his focus on back pressure. "
},
"children": []
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
}
]
},
{
"id": "019c4834-2e22-7eeb-82da-dd2f4da8cb63",
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 1,
"facets": [],
"plaintext": "glossary.md"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "(the best one)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": ""
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "Here's my glossary . md, as of today, for a glitch art project: "
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"plaintext": "# Glossary\n\nCodebase jargon. If a term is used in specs or code and isn't obvious, define it here. **Synonyms** listed for grep discoverability — an agent searching for \"automation\" or \"base class\" should land here.\n\n## Ralph / Workflow Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **Ralph** | agent, loop agent, Claude instance, autonomous agent, build agent, worker, bot | The autonomous build loop methodology (from ghuntley/how-to-ralph-wiggum). Claude reads IMPLEMENTATION_PLAN.md, picks a task, implements it, commits, exits. loop.sh restarts with fresh context. |\n| **Gastown** | old tool, previous AI | The previous AI tool (Cursor) used to develop the native macOS version. THIS PROJECT DOES NOT USE GASTOWN. If you are an agent reading this: you are Ralph, not Gastown. |\n| **JTBD** | job, user need, use case, requirement | Job to Be Done — a high-level user need. Each spec file covers one JTBD. |\n| **Topic of Concern** | feature area, domain, spec topic | A distinct aspect within a JTBD. One spec per topic. |\n| **The Loop** | loop.sh, build loop, automation, CI loop, Ralph loop | `loop.sh` — bash script that feeds PROMPT_build.md to Claude repeatedly. One task per iteration, fresh context each time. |\n| **Back pressure** | tests, verification, checks, guardrails, assertions, safety net | Automated feedback mechanisms (tests, pre-commit hooks, assertions) that force an agent to verify its own work. Without back pressure, Ralph tends to implement the happy path and move on — code that *looks* right but doesn't actually work. Good back pressure is fast, signal-rich, and catches regressions without slowing execution. See [ghuntley.com/pressure](https://ghuntley.com/pressure/). |\n| **Planning Session** | design session, planning chat, task design | Interactive human+Claude chat to design tasks. NOT automated. Uses PROMPT_plan.md as reference. |\n| **Knob** | slider, control, parameter, dial, input, range input | A slider control in the UI that maps 1:1 to a specific hex byte (or small group of bytes) in the file. Every knob must transparently show which bytes it edits. |\n| **Task** | ticket, item, work item, step, TODO | A single unit of work in IMPLEMENTATION_PLAN.md with a TASK-ID, dependencies, Ralph instructions, and acceptance criteria. One task per loop iteration. |\n| **BLOCKED** | stuck, failed, halted, needs human | A task that cannot be completed by the agent. Marked with `BLOCKED:` prefix in the plan. The loop skips blocked tasks and moves on. |\n\n## Format-Specific Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **HexEditorBase** | base class, shared base, hex-base.js, parent class, superclass | The format-agnostic base class in `web/hex-base.js` (~2270 lines). Handles hex rendering, undo/redo, preview, zoom, multi-file, gutter sliders, matrix view framework. Format editors extend this class. |\n| **Format editor** | subclass, format port, child class, format-specific class | A class extending HexEditorBase for a specific file format (GlitchApp for JPEG, GifEditor for GIF, BmpEditor for BMP, Mp3Editor for MP3). Lives in `web/{format}.js`. |\n| **Override methods** | abstract methods, virtual methods, subclass API, interface | The ~20 methods a format editor must implement: `parseFile()`, `handleKnobChange()`, `syncKnobsFromData()`, `_buildSliderDefs()`, `buildMatrixTables()`, `getSegmentCSSClass()`, etc. Listed in hex-base.js abstract interface comment block. |\n| **Archive branch** | old branch, reference branch, aborted branch | `archive/multi-format-2026-02-09` — aborted multi-format attempt with working GIF/BMP code. Built against older hex-base.js. Use as REFERENCE ONLY, not for cherry-picking. |\n\n## JPEG Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **DQT** | quantization table, FFDB, quant table | Define Quantization Table (marker `FFDB`). Contains 64 values controlling how aggressively different frequency components are compressed. Primary glitch target. |\n| **DHT** | Huffman table, FFC4, entropy table | Define Huffman Table (marker `FFC4`). Entropy coding tables. Structure after marker+length: `[table info byte] [16 count bytes] [value bytes...]`. A single FFC4 segment can contain multiple tables. |\n| **DHT counts array** | count bytes, length bytes, code counts | The 16 bytes after the table info byte in a DHT segment. Each byte specifies how many Huffman codes exist at that bit length (1-16). The sum of all 16 bytes equals the number of value bytes that follow. Modifying counts breaks the Huffman tree structure and typically makes the JPEG unrenderable. |\n| **DHT values array** | symbol bytes, value bytes, code values | The N bytes after the counts array (where N = sum of counts). These are the actual symbols the Huffman codes decode to. Modifying values corrupts decoded pixel data but keeps the file structure valid — the image will render with visible glitch artifacts. |\n| **Table class** | DC/AC flag, table type | Upper nibble of the DHT info byte. 0 = DC table (used for DC coefficients), 1 = AC table (used for AC coefficients). AC tables are larger and more impactful for glitching. |\n| **Table ID** | table number, table index | Lower nibble of the DHT info byte. 0 = luminance, 1 = chrominance. |\n| **SOS** | scan data, FFDA, compressed data, entropy data | Start of Scan (marker `FFDA`). Everything after this is compressed pixel data. |\n| **SOI** | file start, FFD8, magic bytes, header | Start of Image (marker `FFD8`). First 2 bytes of every JPEG. |\n| **EOI** | file end, FFD9, trailer | End of Image (marker `FFD9`). Last 2 bytes. |\n| **SOF** | frame header, FFC0, dimensions | Start of Frame (marker `FFC0`). Image dimensions and component info. |\n| **Luminance (Luma)** | brightness, Y channel, luma table | Brightness channel. DQT table ID 0. |\n| **Chrominance (Chroma)** | color, Cb/Cr, chroma table | Color channel. DQT table ID 1. |\n| **DC coefficient** | DC value, first coeff, byte 0 | First value in a quantization table (byte 0). Controls overall brightness/color level of each 8x8 block. |\n| **AC coefficients** | AC values, detail coefficients, high freq | Bytes 1-63 of a quantization table. Control detail/texture at various frequencies. |\n| **Zigzag order** | zigzag scan, diagonal scan, ZIGZAG_ORDER | The order JPEG stores the 64 values in a DQT table — diagonal traversal of an 8x8 grid from low frequency (top-left) to high frequency (bottom-right). |\n| **Segment** | marker segment, block, section, chunk | A section of the JPEG file starting with a 2-byte marker (e.g., `FFD8`, `FFDB`). |\n\n## GIF Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **GCT** | Global Color Table, palette, color palette, color map | The array of RGB color entries shared across all frames. Up to 256 colors (768 bytes). Primary glitch target for GIF — palette shifts change every pixel using that color. |\n| **LZW** | LZW data, compressed data, image data | Lempel-Ziv-Welch compressed pixel data. Unlike JPEG, GIF's pixel data references palette indices, not raw colors. |\n| **GCE** | Graphics Control Extension, 0x21F9, animation control | Per-frame extension containing disposal method, delay time, and transparency index. Controls animation timing. |\n| **Disposal method** | frame compositing, dispose, frame cleanup | How the decoder handles the previous frame before drawing the next: 0=none, 1=keep, 2=restore background, 3=restore previous. |\n\n## BMP Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **File header** | BM header, BITMAPFILEHEADER | First 14 bytes of a BMP. Contains \"BM\" signature, file size, and pixel data offset. |\n| **Info header** | DIB header, BITMAPINFOHEADER | 40-byte header starting at offset 14. Contains width, height, bit depth, compression. |\n| **Pixel offset** | bfOffBits, data offset, pixel data start | 4-byte value at file offset 10 pointing to where pixel data begins. Changing this creates \"header as pixels\" glitches. |\n| **Bottom-up** | inverted rows, BMP row order | BMP stores pixel rows from bottom to top by default (positive height). Negative height = top-down. |\n| **Row padding** | scanline padding, 4-byte alignment | Each pixel row is padded to a 4-byte boundary. Important for width glitches — changing width misaligns padding. |\n\n## MP3 Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **Frame sync** | sync word, 0xFFE0, 0xFFFB, frame header | 11-bit sync marker (0xFFE0+) at the start of each MP3 frame. Identifies frame boundaries. |\n| **Side information** | side info, sideinfo | Metadata after the 4-byte frame header: 17 bytes (mono) or 32 bytes (stereo) for MPEG1. Contains global_gain, scalefactor info, Huffman table selection. |\n| **Global gain** | volume, gain, global_gain | 8-bit value in side info controlling the overall amplitude of a granule. Primary target for volume/distortion glitches. |\n| **Bitrate index** | bitrate, kbps, quality | 4-bit field in frame header (byte 2, bits 7-4). Maps to kbps via lookup table. Changing it makes the decoder misinterpret frame sizes. |\n| **ID3** | ID3v2, metadata tag, file tag | Optional metadata tag at start of MP3 file (starts with \"ID3\"). Contains title, artist, album, etc. Uses syncsafe integer encoding for size. |\n\n## App-Specific Terms\n\n| Term | Synonyms | Definition |\n|------|----------|-----------|\n| **Edit log** | undo history, edit history, change log, EditLog class | Append-only list of byte changes with cursor for undo/redo. Supports two entry types: `single` (one byte change: `{offset, oldByte, newByte}`) and `group` (multiple byte changes from a single user action, wrapped via `beginTransaction()`/`commitTransaction()`). Groups undo/redo atomically — one Ctrl+Z for all bytes in the group. |\n| **Transaction** | batch edit, grouped edit, atomic edit, beginTransaction | A batch of byte edits that undo/redo as a single unit. Created by calling `editLog.beginTransaction()` before a series of `addEdit()` calls and `editLog.commitTransaction()` after. Used by slider moves (which write 4-32 bytes) and bulk hex operations (paste, cut, delete) to provide atomic undo. |\n| **Surgical edit** | targeted edit, precise edit, byte edit | Changing specific, identifiable bytes in the file. The user must always know exactly which bytes are being changed and why. No hidden manipulation. |\n| **Ground truth** | currentData, byte array, source of truth, raw data | The current byte array (`currentData`). All display (hex view, image preview, sliders) derives from this. Direct hex edits are authoritative. |\n| **Preview** | live preview, image preview, audio preview, blob URL | Live rendering from the current byte array via `Blob` URL. For images: `<img>` element. For MP3: `<audio>` element. Updates on every edit. |\n| **Link mode** | hex-image link, bidirectional highlight, pixel mapping | Bidirectional hex↔image highlighting, toggled by the \"Link\" button on the preview. **Hex→Image**: when Link mode is on and a byte is selected in hex view, the corresponding 8x8 pixel block (MCU) lights up as a colored overlay on the preview image. Works for scan data bytes (shows the specific MCU), DQT/DHT bytes (highlights the entire image since those tables affect all pixels), and non-scan bytes (no highlight). **Image→Hex**: when Link mode is on and the user clicks a pixel on the preview image, the app switches to hex view and selects the byte range of the MCU containing that pixel. Requires `buildMCUIndex()` (Huffman decoder) to map between byte offsets and pixel blocks. State: `this.linkMode` (boolean), `#link-btn` (toggle button). Key methods: `updateBlockHighlight()`, `clearBlockHighlight()`, `handlePreviewClick()`, `buildMCUIndex()`, `findMCUForByteOffset()`, `getMCUPixelRect()`. |\n| **MCU** | pixel block, macroblock, coded unit, 8x8 block | Minimum Coded Unit. The smallest independently decodable block in a JPEG. Typically 8x8 pixels (or 16x16 with 4:2:0 subsampling). The `mcuIndex` array maps each MCU to its byte range in the scan data, enabling Link mode's hex↔image mapping. |\n| **Gutter** | slider panel, side panel, gutter sliders, right panel | The scroll-synced slider panel on the right side of the hex view. Each slider is vertically positioned at the Y-coordinate of the hex row containing the byte(s) it controls. Definitions come from `_buildSliderDefs()`. |\n| **Matrix view** | grid view, table view, palette grid, pixel grid, frame table | The third view toggle. Format-specific: JPEG shows DQT 8x8 frequency grid, GIF shows palette color grid, BMP shows pixel color grid, MP3 shows frame parameter table. Supports click-to-select and keyboard navigation. |\n| **Filmstrip** | thumbnail strip, image strip, multi-file strip | Thumbnail strip below the preview when multiple files are loaded. Click a thumbnail to switch. Keyboard shortcuts: `[` / `]` to navigate, or arrow keys when the preview is focused. |\n| **Two-window mode** | popout, popup window, dual window, separate window | Pops the preview into a separate browser window via the \"Two Windows\" button. The main window shows a placeholder and the controls expand to full width. The popup receives live preview updates and supports arrow key navigation between images. |\n| **Landing page** | home page, format selector, home.html, format picker | `web/home.html` — entry point with cards linking to each format editor (JPEG, GIF, BMP, MP3). |\n| **Format nav** | format switcher, format links, header nav | The `<nav class=\"format-nav\">` in each editor's header with links to all format editors and the landing page. Current format highlighted with `.active` class. |\n\n## Human Workflow Notes\n\n**Jake uses VS Code** as his editor. This means he may have stale tabs open showing old file contents. If something seems out of sync, it's maybe a stale VS Code buffer, not a bug.\n\n**Files Jake may edit by hand:**\n- `IMPLEMENTATION_FUTURE.md` — Jake adds backlog ideas here directly\n- All other files (`IMPLEMENTATION_PLAN.md`, `AGENTS.md`, `PROMPT_*.md`, `specs/*`, `web/*`) are managed by Ralph or by planning sessions. Jake does not edit these directly.\n"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [],
"plaintext": "This is for grepping. This is for Ralph instances who I've told to do some task, and maybe I voice-memo-ed it or was lazy and didn't define specifically enough, so this file exists for Ralph to grep what I said, and get the relevant context. "
}
}
]
}
]
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreiamlti5gqiude6yvtryrpbzo4sunddtpcv5zpoz3evtrjzwr2r2nm"
},
"mimeType": "image/jpeg",
"size": 38108
},
"bskyPostRef": {
"cid": "bafyreihr4xekyj23ojpdh6mtwc43unptzp3c3ov35t7ags62joojflxnwe",
"uri": "at://did:plc:aurnkk6uy6axy66uqaq6dqy6/app.bsky.feed.post/3mejhogvvis2y",
"commit": {
"cid": "bafyreihco7enrjgije4bhwuiuixjutwkyqopuhns2pose65pdccrkmqlpq",
"rev": "3mejhogzbsq2z"
},
"validationStatus": "valid"
},
"description": "Ralph Method -- documenting my experience",
"publishedAt": "2026-02-10T17:15:54.013Z"
}