The Short Version
Over a weekend, a single Intelligrit engineer processed all 807 chapters of a 12-million-word web serial and turned 600 filtered locations into an interactive, spoiler-aware map. The codebase is 3,200 lines of Go and 1,000 lines of JavaScript. Development and the compiled map runtime fit on a laptop; extracting the locations called Anthropic’s hosted API.
Project contextRead why this toy problem is a useful analogue for document-heavy mission work
This was a recreational R&D project built to test whether one engineer could turn a very large document collection into traceable data over a weekend. The same problem shape appears in federal modernization, customer-feedback analysis, and research: large volumes of unstructured data, months of manual extraction, and timelines that can stretch into years.
The Problem We Solved
The Wandering Inn is a web serial and one of the longest works of fiction in the English language, at over 12 million words across 10 volumes. It builds a detailed fantasy world with hundreds of named locations: continents, nations, cities, dungeons, roads, and landmarks. There is no official map, and fan-created maps are incomplete and full of spoilers.
We wanted to identify geographical references across every chapter and build an interactive map that reveals the world progressively. A reader on Volume 3 should see only the locations mentioned through Volume 3.
The subject is recreational, but the problem shape also appears in federal modernization, enterprise data migration, research, and product development:
- Massive volumes of unstructured text that need structured data extracted
- No existing database: the knowledge lives only in documents
- Progressive disclosure requirements: different users need different levels of access
- Quality at scale: extraction must be accurate across hundreds of documents
What We Built
A five-stage automated pipeline takes raw text through to an interactive map.
- Scrape: Download 807 chapters from the web (rate-limited, resumable)
- Extract: Send each chapter to Claude AI for structured location extraction
- Aggregate: Deduplicate, normalize, and merge results across all chapters
- Coordinate: Assign map positions using containment hierarchies and seed data
- Serve: Present an interactive Leaflet.js map with a chapter-progress slider
The completed map application compiles to a single binary and runs without Docker, a database server, or a separately managed cloud runtime. Building the dataset called Anthropic’s hosted API; serving the finished map does not. Build it with go build, then run the executable.
Implementation depthSee the technology, dependencies, licenses, and map-design choices behind the result
Technology Choices
Why Go
We chose Go deliberately, and it paid off in several ways:
- Single binary deployment.
go buildproduces one executable with the web server, static assets, and templates embedded. It requires no separate runtime, node_modules directory, or virtual environment. - go:embed for static files. Go's
embeddirective bundles HTML, CSS, and JavaScript directly into the binary at compile time. The map server is entirely self-contained. - Lightweight concurrency. The scraper needs rate limiting and the extractor makes hundreds of API calls. Go's goroutines and
golang.org/x/time/ratekept the implementation compact. - Standard library HTTP server. The
net/httppackage is production-grade out of the box. Our map server is 120 lines of code including the API endpoints, static file serving, and graceful handling of the embedded filesystem. - Fast iteration with Claude Code. Go's explicit error handling, minimal abstraction, and lack of inheritance hierarchies make the code read linearly. That structure helped the AI assistant reason about the code and produce useful modifications.
- Compilation catches errors early. With a pipeline this complex, Go's type system and compiler caught classes of bugs at build time that would have been runtime surprises in Python or JavaScript.
The dependency footprint is minimal: Cobra for CLI structure, goquery for HTML parsing, go-duckdb for storage, and golang.org/x/time for rate limiting. Everything else is standard library.
Why Plain HTML, CSS, and JavaScript
The frontend is 1,000 lines of vanilla JavaScript, a single CSS file, and one HTML file. It uses no framework, bundler, transpiler, node_modules directory, or separate build step.
The application is simple enough that a framework is unnecessary. It has a single page with a map, sidebar, and control bar. It loads data from four API endpoints and renders it with Leaflet.js. The interaction model is straightforward: change a dropdown, fetch data, and redraw. Direct DOM manipulation handles the problem without an added build pipeline, dependency tree, or abstraction layer.
The result:
- Zero build step. Edit a
.jsfile, rebuild the Go binary (which embeds the static files), and reload. - No framework version churn. Changes such as React 18 to 19, Vue 2 to 3, or Angular's yearly breaking releases do not apply. The browser API is stable.
- Readable by anyone. A developer who knows JavaScript can read the entire frontend in one sitting.
- Reviewable generated code. Familiar browser APIs supported reviewable generated code. In this project, the assistant produced vanilla JavaScript that the engineer reviewed and tested.
For problems of this shape, plain HTML, CSS, and JavaScript can be faster to write, easier to maintain, cheaper to deploy, and simpler to audit than a framework-based alternative.
Open Source Licensing
Every dependency in this project uses a permissive open source license. We care about this because licensing is an engineering decision with legal and operational consequences:
| Dependency | License | Type |
|---|---|---|
| Go standard library | BSD 3-Clause | Permissive |
| Cobra (CLI framework) | Apache 2.0 | Permissive |
| goquery (HTML parsing) | BSD 3-Clause | Permissive |
| DuckDB Go driver | MIT | Permissive |
| golang.org/x/time | BSD 3-Clause | Permissive |
| Leaflet.js (map rendering) | BSD 2-Clause | Permissive |
| TWI Map itself | MIT | Permissive |
Every dependency is permissively licensed, with no GPL, AGPL, or SSPL components. Each component can be used, modified, and distributed without viral licensing concerns. This matters for government procurement, enterprise adoption, and open-source distribution because license review and incompatibilities can delay deployment.
Coordinate Assignment
Innworld has no canonical coordinate system. We invented one using a hybrid approach:
- Seed coordinates. We manually placed ~80 major landmarks in a [-512, 512] coordinate space.
- Containment-based inheritance. The remaining 170+ locations inherit coordinates from their parents in the containment hierarchy. The system walks up to 10 levels of containment to find a positioned ancestor.
- Keyword-based traceability. Some locations have containment data that doesn't chain to a seed. If a location's name contains a known geographic keyword, it's considered traceable even without explicit containment.
Dynamic Landmass Rendering
Continents aren't drawn from a static image. They're generated dynamically from the locations visible at the current chapter position: locations are grouped by continent via containment chains and proximity, a convex-hull-like algorithm with organic noise generates coastlines, and each continent gets a deterministic color derived from its name. Landmasses grow and reshape as more locations are discovered through reading.
The Numbers
| Metric | Value |
|---|---|
| Total words processed | ~12,000,000 |
| Chapters analyzed | 807 |
| Locations extracted | 600 (after quality filtering) |
| Containment rules | 1,555 |
| Development time | 2 days |
| Team size | 1 engineer |
| Hand-written code | 0 lines; 100% AI-generated |
| Commits to completion | 5 |
How AI Made This Possible
AI handled extraction and accelerated implementation; a named senior engineer directed the architecture, reviewed evidence, tested behavior, and owned the release.
AI workflowSee how extraction guardrails and engineer-directed development worked
The Extraction
Each of the 807 chapters was sent to Claude as a complete document with a structured extraction prompt. The AI returned JSON for the named locations it identified, including type, description, spatial relationships, and direct quotes from the source text.
Later volumes of the serial have individual chapters exceeding 300,000 characters, roughly the length of a full novel. The AI processed these without issue once we applied a technique called "assistant prefill" that mechanically anchors the output format (more on this below).
The extraction prompt uses a system message defining location types and relationship types with examples drawn from the source material. Key design decisions:
- No series knowledge: the prompt instructs the model to extract only from the provided text, preventing hallucinated locations from training data.
- Quote requirements: every extracted location and relationship must include a supporting quote from the chapter text, providing end-to-end traceability.
- Visual descriptions: separate from functional descriptions, these capture terrain, architecture, climate, and atmosphere.
The Development
The codebase itself was built interactively with Claude Code, an AI coding assistant. We described what we wanted, reviewed the generated code, and iterated. The AI wrote the scraper, database layer, aggregation logic, coordinate assignment algorithm, and frontend map. We directed architecture, reviewed outputs, and made judgment calls.
This is the capacity shift behind Intelligrit's delivery model: AI accelerates execution, while a named senior engineer still directs the architecture, reviews the output, tests the system, and owns the result.
Technical Findings
Ten observed results from this build, with the limits that matter before applying them elsewhere.
Finding 1 · Output reliabilityMechanical guardrails made long-document extraction reliable. JSON anchoring eliminated the observed parse failures in this run.
On very large documents (200K+ characters), the AI would occasionally ignore extraction instructions and produce a narrative summary instead of structured JSON. This happened on roughly 5% of the longest chapters.
The fix was a single line of code. The Anthropic API supports "assistant prefill," which lets a caller include a partial assistant message that the model must continue from. By prefilling with {, we force the model to begin its response as JSON:
{
"messages": [
{"role": "user", "content": "Extract all geographical data... [chapter text]"},
{"role": "assistant", "content": "{"}
]
}This eliminated the observed parse failures after the change. The model did not produce invalid output again during this project run.
What happened here: The reliable setup combined the extraction prompt with mechanical JSON anchoring and verification. Another corpus would need its own failure tests.
Finding 2 · Dependency reviewHuman review caught a deprecated DuckDB driver and a persistence defect before release.
The AI initially chose a deprecated database driver (marcboeker/go-duckdb v1.8.5) instead of the current official driver (duckdb/duckdb-go v2.5.5). The old driver had a real bug: large transactions silently failed to persist data.
What human review caught: The generated implementation used an outdated dependency that failed on large transactions. A maintainer still has to verify dependencies, security assumptions, and architectural choices.
Finding 3 · Deployment sizeThe 4,200-line system processed the 12-million-word corpus as one binary.
3,200 lines of Go and 1,000 lines of JavaScript process 12 million words, extract structured data via AI, store it in an embedded database, and serve an interactive map with spoiler controls. The compiled binary is a single executable with all assets embedded.
This corpus did not require a large service stack. The result is specific to this workload; another system would need its own architecture, security, performance, and operating tests.
Finding 4 · Prototype infrastructureDuckDB let this prototype run without a database server while retaining a standard SQL interface.
We used DuckDB, an embedded analytical database that stores everything in a single file. After the hosted model calls produced the extraction records, aggregation and the compiled map runtime ran on a laptop without a database server or container.
The schema and queries use standard SQL through Go's database/sql interface. A future move to another database would still require testing dialect differences, concurrency, migration, and operating behavior.
Boundary: Removing infrastructure barriers can make a bounded feasibility experiment faster. That does not make a laptop prototype production-ready or remove the acquisition, security, accessibility, deployment, and operating work required for a customer solution.
Finding 5 · Source traceabilityEvery map relationship links to its source quote and chapter.
Every spatial relationship on the map is clickable. When a reader clicks the dashed line connecting two locations, a popup shows the relationship type, the extracted detail, the exact quote from the source text that established the connection, and the chapter where it first appeared.
Source quotes stay attached through the extraction prompt, aggregation, database, and frontend popup, so every claim on the map can be checked against the original text.
Design rule used here: Each extracted relationship carries the source sentence needed to check it. That trace remains attached from extraction through the map popup.
Finding 6 · Accessibility workApply accessibility throughout map delivery. Manual review plus repeated axe scans ended with zero violations across 43 automated rule checks.
Interactive maps are inherently visual, which makes them one of the harder interfaces to make accessible. We audited the TWI Map against WCAG guidelines, first manually and then with axe-core automated scanning, and iteratively fixed every issue until the scanner reported zero violations across 43 rule checks.
What we built:
- Aggressive label scaling: Map text labels scale 4x between minimum and maximum zoom
- Tabbable map markers: Every marker receives
tabindex="0",role="button", and anaria-label - Full keyboard navigation: Sidebar supports arrow keys, Enter, and Space
- ARIA semantics throughout: Descriptive labels, navigation landmarks, skip links
- WCAG AA contrast: All text meets 4.5:1 contrast ratio
- Screen reader popup announcements: An
aria-live="assertive"region announces popup content - Proximity click: A 40-pixel snap radius supports motor accessibility
Limit: The manual review and automated scans document work performed on this map. An automated scan result alone does not establish Section 508 conformance.
Finding 7 · Filter interactionSupporting web, audiobook, and ebook progress turned one spoiler filter into a three-part mapping problem.
The spoiler-free slider began with a simple rule: filter locations by chapter. Readers consume the story in different formats, however. The Wandering Inn is available as a web serial (807 chapters), audiobooks (17 books covering chapters 1 to 429), and ebooks (17 books covering the same range). A reader on Audiobook Book 7 needs to see a different slice of the world than a web serial reader on Volume 7.
This created cascading requirements:
- Multi-format chapter mapping: Three-dropdown navigation (format, section, chapter)
- Coherent relationship filtering: Two filters that compose correctly
- Persistent spatial context: Continent outlines persist regardless of location visibility
- Searchable, toggleable sidebar: Search, bulk controls, and per-location toggles
The narrower lesson is that two simple filters can interact in unexpected ways. Another system would need its own access-control, security, and test design.
Finding 8 · Browser testingPlaywright reproduced bugs and recorded interface behavior for engineer review.
We used the Playwright browser automation framework so the AI assistant could interact directly with the running map during development. It navigated the map, manipulated controls, toggled filters, and took screenshots to reproduce bugs and verify behavior programmatically.
This shortened debugging loops: the AI could operate the UI, inspect results, read console logs, and propose a root cause. The engineer still directed the work, reviewed the evidence, and remained accountable for the release.
In this project, Playwright made the reported behavior repeatable and left scripts and screenshots for review. It did not replace engineer judgment or any independent verification a customer engagement might require.
Finding 9 · Filtered-map contextGhost lines preserved spatial context in filtered views without revealing hidden markers.
When a reader hides most locations to focus on just two or three, every relationship line disappears because both endpoints must be visible. The map becomes a handful of dots floating in empty space.
We solved this with "provenance lines," which draw a ghost relationship from a visible location to the coordinates of a hidden related location. Key decisions:
- Exactly one visible endpoint: Lines draw only when one location is visible and the other is hidden
- Coordinates without markers: The hidden endpoint's position comes from the coordinate dataset
- Distinct visual treatment: Low opacity, thinner dash patterns, and faded endpoint markers
- Discoverable interaction: 12-pixel-wide invisible hit areas with hover highlights
- Full popup on click: The same relationship details as normal lines
- Off by default: A separate toggle whose setting persists to localStorage
For this map, the faded references preserve orientation while marking information outside the current filter. That interface choice is not an access-control mechanism and would need separate review in a protected system.
Finding 10 · Accessibility iterationAI assistance made several small accessibility fixes practical in one weekend; the engineer reviewed and owned the release.
The TWI Map includes proximity click, three-dropdown navigation, ghost lines with larger hit areas, tabbable map markers, screen-reader announcements, and tested text contrast. Each change is small; together they make the map more usable.
That polish is often cut when every small enhancement must compete for scarce engineering capacity. Accessibility checks, regression testing, and operational details remain real work even when each individual change is straightforward.
AI assistance changed that tradeoff here. Under the engineer's review, the accessibility scan-fix-rescan loop ran three times in a single session until axe-core reported zero violations. Adding tabbable markers to Leaflet was a focused change to the render loop plus a few ARIA attributes.
AI assistance shortened several implementation loops in this project. The engineer still reviewed the behavior, ran the tests, and owned the release.
What We Would Reuse
These practices worked in this project; customer work would have to test them again under its own constraints.
Practices and limitsSee what worked in this weekend build and what remains future work
This was a weekend R&D project, not client work. It tested unfamiliar approaches within a two-day limit and produced a public result that can be reviewed directly.
- One engineer, two days. AI accelerated the volume work; the engineer remained accountable for the architecture, review, tests, and result.
- Keep source links attached. Five commits produced a working interactive map whose extracted relationships remain linked to source text.
- Build for the real constraints. The spoiler-free slider is a progressive-disclosure mechanism. The pattern can inform role-based or segmented dashboards; classified use would require its own approved security architecture and controls.
- Retain the quote. Every AI-extracted relationship links back to the exact source text.
- AI used throughout the workflow. AI is in the extraction pipeline, development workflow, and dependency management. In this project, that leverage expanded what one senior engineer could test and ship over a weekend. The evidence is specific to this project and cannot establish a universal productivity multiplier.
- Pragmatic technology choices. Go produced a single binary, plain HTML, CSS, and JavaScript fit the limited interface, and DuckDB removed server infrastructure. Each choice supported fast delivery while preserving a reasonable transition path.
- Open source by default. Every dependency is permissively licensed. We audit dependencies deliberately because AI assistants don't check licenses.
- Accessibility throughout the build. The interactive map includes tested text contrast, keyboard navigation, ARIA semantics, skip links, screen-reader announcements, and proximity click support.
Future Work
- Improved coordinate inference: using directional relationships and distance mentions to algorithmically position locations rather than hand-seeding.
- Visual rendering: the extraction captures visual descriptions that could drive AI image generation for location portraits or stylized map tiles.
- Incremental updates: as new chapters publish, run only the new chapter through extraction and re-aggregate.
- Deep search: full-text search across location descriptions and relationship quotes.
Where This Pattern May Apply
The same approach could be tested on a bounded set of regulations, correspondence, case files, research papers, or procurement documents when each extracted fact can retain its source.
The reusable pieces are concrete: structured output, a source quote for every relationship, automated filtering, and a single-binary deployment. Another corpus would need its own quality thresholds, controls, and review process.
In this demonstration, one engineer processed 12 million words in two days.
CreditsReview tools, libraries, and source acknowledgments
Acknowledgments
Built with Claude (Anthropic) for both the extraction pipeline and development assistance via Claude Code. Map rendering powered by Leaflet.js. Storage by DuckDB. The Wandering Inn is written by pirateaba and published at wanderinginn.com.