Voice & Style
A working agreement on how this book sounds. Living document. Updated as the rewrite teaches us things.
1. Who’s talking, and to whom
Section titled “1. Who’s talking, and to whom”The narrator. Someone who has built frontend systems for a long time, has scars from each era, and is now sitting next to you with a coffee, walking through what they’ve come to believe. Not a lecturer. Not a documentation page. Not an objective historian — someone with a thesis they earned the hard way and want to hand you cleanly.
The reader. Plural. A junior engineer who’s only ever known React; a senior backend engineer who treats the frontend as a hostile foreign country; a designer who codes; a tech lead deciding what the next system should look like. The voice has to land for all of them. That means: never condescend, never assume. Explain enough that the React-only reader doesn’t get lost. Trust enough that the experienced reader doesn’t feel slowed down. The shared respect is for the architecture — and the assumption that everyone in the room cares about getting it right.
Stance. The book is an argument, not a survey. We’re claiming the browser is an OS, web standards are its API, and the industry has spent twenty years building cathedrals on top of a platform that quietly grew into one underneath us. Kitsune is what falls out when you take that claim seriously. Every chapter has to push that argument forward, even the historical ones.
Reverence for the masters. The book honors the people who built the frontend stack. Brendan Eich, Håkon Wium Lie, John Resig, Jordan Walke, Ryan Dahl, Justin Fagnani, Brad Frost, Marc Andreessen, Tim Berners-Lee, Anders Hejlsberg, Evan You, Ryan Carniato, Rich Harris, and the many others — these were often the absolute best at what they did, doing world-class engineering at the edge of what was possible with the platform of their day. The tone when introducing them is reverent. The tone when discussing patterns they shipped is reverent. Critique, when it comes, comes from a position of gratitude that the work existed in the first place — not from the cheap altitude of hindsight. This isn’t hagiography; it’s accuracy. Most of the inherited assumptions we now want to revisit weren’t accidents. They were craft.
The reader as next-generation master. The reader isn’t being instructed. They’re being invited. The frontend has always been a field of invention — every generation of the platform has been shaped by people who looked at what existed and asked whether something better was possible. Bootcamps, hobbyists, and AI-assisted developers haven’t gotten the contextual depth that the previous generation took for granted, and that depth is what makes invention possible. The book is a transmission of that depth and an invitation to use it. The closing voice should make this explicit: we are not at the end of frontend evolution. The platform is still growing. The patterns are still being discovered. The next generation of masters will be the people who, with AI as a collaborator, invent things that don’t exist yet. The book is an invitation to join a long conversation about invention.
2. Voice rules
Section titled “2. Voice rules”Plain over clever (the governing rule)
Section titled “Plain over clever (the governing rule)”This is the rule that overrides the others when they conflict. Write plainly. State things directly. Trust the reader to find the argument compelling without rhetorical packaging.
The current draft is stiff and abstract. It’s tempting to fix that by reaching the other direction — punchy openers, em-dash asides, setup-and-payoff sentences, mic-drop closers. Don’t. That’s the same problem in a different costume. Both are the prose performing instead of communicating, and a thoughtful reader can feel it.
The right register is closer to a clear technical essay than a TED talk. Sentences should land because they’re true and concrete, not because they have shape. If a paragraph would survive being read out loud at half speed without sounding overworked, it’s probably right.
No “wasn’t X, but Y” inversions
Section titled “No “wasn’t X, but Y” inversions”The negation-then-correction pattern is a tic the draft (and the early rewrites) lean on heavily:
- “It was not a weak version of React. It was a coherent system.”
- “What changed wasn’t that the model was wrong. It was that the web was asked to do more.”
- “Calling that model primitive is easy. It’s also misleading.”
Almost every use is a reach for rhetorical effect. State what something is. Don’t define it by what it isn’t, then correct the reader. If the contrast is genuinely necessary, one well-chosen “but” is enough — but most of the time the corrected version isn’t necessary at all, because the reader didn’t need the wrong version first.
Don’t narrate the prose
Section titled “Don’t narrate the prose”Stay out of the writing as a presence. Don’t comment on what you just wrote, signal that you’re about to rephrase, or tell the reader where to focus their attention. The argument should land because the prose puts it in front of the reader, not because the writer points at it.
Common forms of the tic:
- Meta-commentary on the writing itself. “That sentence is true and it can sound dismissive. It’s worth saying differently.” “Let me put that another way.” “Or, more accurately…”
- Signaling where to look. “What’s worth pausing on, though, is…” “The point here is just that…” “For now, just notice…” “Notice that…”
- Self-impressed reframes. “What’s striking is…” “Interestingly…” “Worth noting…” “It bears mentioning…”
All three do the same thing: the writer steps outside the prose to make themselves visible. They look like intimacy with the reader and feel like cleverness to the writer; they read as distance to anyone else. The reader has to follow the writer in and out of the writing instead of just following the argument.
The fix is almost always to cut the meta beat. If the rephrase or refocus is necessary, do it. If it isn’t, drop it. “What’s striking is how much…” becomes “How much… is striking” — or, better, just the substantive claim with no judgment word at all. “The point here is just that X” becomes “X.”
Related to the “wasn’t X, but Y” rule and the “this chapter will” scaffolding rule — all three are versions of the writer being a tour guide instead of letting the prose do the work.
Use contractions
Section titled “Use contractions”The single biggest source of the current draft’s stiltedness. Default to contractions everywhere they’d appear in spoken English.
- “did not” → “didn’t”
- “is not” → “isn’t”
- “we have” → “we’ve”
- “it is” → “it’s”
Exceptions: when the uncontracted form carries weight. “We did not build this” hits harder than “we didn’t build this” — but only if you’re earning that emphasis. If you’re not, contract.
Address the reader — but stay out of the first person
Section titled “Address the reader — but stay out of the first person”Use “you” when walking the reader through something. Use “we” when reasoning together about the field. Don’t use “I”. No personal anecdotes, no “I worked on a codebase that…”, no “in my experience”. The book is built on personal observations about the field, not personal experience in it. Reaching for a fake war story is worse than no war story at all.
When the current draft over-uses abstract dodge-words (“developers”, “teams”, “applications”) to avoid claiming anything, replace with a more honest collective:
- “Developers may reach for a custom modal…” → “You’ll reach for a custom modal…”
- “Teams often build a JavaScript layout system…” → “Plenty of us have built a JavaScript layout system where CSS grid would’ve worked — usually because the grid spec wasn’t quite there yet when we started, and the code outlived the constraint.”
- “Some applications still…” → “Some codebases still…” (concrete object, not personified abstraction)
The voice is we, here together, looking at the field — not me, telling you what I’ve seen. Hypermedia Systems uses “we” the same way and it works.
Vary sentence length, ruthlessly
Section titled “Vary sentence length, ruthlessly”The current draft loves the parallel triplet:
Some of those lessons are still valid. Some are only partially valid. Some are no longer good defaults.
Three sentences, identical shape, no information gradient. Either compress or differentiate:
Some of those lessons still hold. Some have decayed into half-truths. Others are now actively bad advice — and we’ll see a few by name.
A short sentence after a long one is one of prose’s strongest tools. Use it.
Kill the anaphora tic
Section titled “Kill the anaphora tic”The draft leans hard on “It was X. It was Y. It was Z.” This is a fine rhetorical move once or twice a chapter when you’re earning a crescendo. The current draft uses it as a default rhythm, which makes it stop landing.
Rule of thumb: if you’ve used a parallel-sentence ladder once in a section, the next paragraph must use a different shape.
Ground every abstract claim
Section titled “Ground every abstract claim”Every assertion needs at least one of: a named system or framework, a code snippet, a concrete pattern the reader will recognize, or a number. The draft is full of true statements that float:
“Habits outlive constraints.”
That’s a great line. It’s earned in this chapter only if the next sentence is something like:
Plenty of codebases still wrap every native
<button>in a<Button>component because, somewhere around 2016, a design system needed a hover state the target browser didn’t render correctly. The browser was fixed years ago. The wrapper is still there, in every page, in every product.
Concrete moments are how the reader builds belief — the moment is recognizable from the field, not from the narrator’s memoir. Without grounding, the prose reads as opinion.
Don’t render lists as txt code blocks
Section titled “Don’t render lists as txt code blocks”Current draft, Ch 11:
```txtES modulesfetchPromises and async/awaitCustom Elements...```This is a rendering tic that defeats prose. Either:
- Weave the list into a sentence (“ES modules, fetch, custom elements, shadow DOM, slots, observers for mutation and intersection and resize, the History API, FormData, constraint validation, ElementInternals, native dialog, popover, custom properties, cascade layers, container queries,
:has(), view transitions…”) — the wall of comma-separated capability is itself the rhetorical move, - or use a real markdown list with one short clause per item explaining why it matters,
- or pick the five that matter most and prose them with a sentence each.
Reserve code blocks for code.
Pull quotes belong on their own lines
Section titled “Pull quotes belong on their own lines”Buried right now: “The browser is no longer the browser that jQuery was built to survive.” That’s the chapter in one sentence. Lift it. Either make it a section header, a blockquote, or the opening line of the section it belongs to.
Each chapter should have one or two of these — the lines a reader would underline. Plant them deliberately.
Earn your jargon
Section titled “Earn your jargon”Every term of art (boundary, runtime, capability, protocol surface, context tree) gets defined on first use, even if it’ll be defined more rigorously later. The reader should never have to wait three chapters to figure out what we mean. A one-clause aside is enough: “a boundary — the explicit edge around a piece of UI that owns its own context.”
Cut the “this chapter will” / “we will see in the next chapter” scaffolding when it’s filler
Section titled “Cut the “this chapter will” / “we will see in the next chapter” scaffolding when it’s filler”Some throat-clearing earns its keep — orienting transitions between parts, signaling a pivot. But the current draft uses it constantly:
“Later, when we talk about forms as transactions, this idea will return.”
Most of the time, the reader doesn’t need the trail map. Trust the structure. When you do flag a forward link, make it a promise with content: “We’ll come back to forms when we build the runtime — by then you’ll see why a <form> is the smallest possible boundary.”
3. Structural conventions
Section titled “3. Structural conventions”Chapter shape
Section titled “Chapter shape”The preface already names a five-part chapter pattern (problem → primitive → principle → exercise → bridge). Keep it, but loosen it. Not every chapter needs all five. Don’t telegraph the structure with section headers like “The Principle”. Let the shape be felt, not announced.
Section length
Section titled “Section length”Sections should be 200–600 words. Shorter than 200 means it’s a beat, not a section — fold it into the section before or after. Longer than 600 means there’s a sub-argument hiding inside that wants its own header.
Chapter length
Section titled “Chapter length”Rough target: 2,500–5,000 words per chapter. The current draft averages much less — Ch 35 is ~400 words for what should be the marquee “Kitsune arrives” chapter. The expansion isn’t about padding; it’s about giving each idea room to land, ground itself in examples, and breathe.
Code-to-prose ratio
Section titled “Code-to-prose ratio”The early chapters get this roughly right (Ch 1 has good code examples). The middle and late chapters either drown in code or replace prose with code-blocks-as-lists. Aim for: every code snippet introduced by a prose claim it illustrates, followed by prose unpacking what just happened. Code is evidence, not exposition.
Exercises
Section titled “Exercises”Keep them. They’re one of the strongest pieces of the existing draft — concrete, trust the reader, ask hard questions. Voice them in second person (“Build a tiny…”), and where relevant, give the reader a hint about what the surprising finding will be — not the answer, but a pointer toward what’s worth noticing.
4. The cross-discipline playbook
Section titled “4. The cross-discipline playbook”The thesis is that the browser is an OS and web standards are its API. That metaphor must show up frequently and concretely, not as garnish. Three discipline lenses to draw on:
A note on naming names
Section titled “A note on naming names”When we credit or critique specific frameworks, libraries, or eras (jQuery, Backbone, Angular 1.x, React, Next.js, Remix, htmx, Lit…), name them. Don’t hide behind “some libraries” when the reader knows exactly which one we mean.
The tone of the naming matters: most of these were incredible engineering, solving the real problems of their day. The book’s argument isn’t that any of them were wrong — it’s that the day has changed underneath them, and many of the constraints they were built to survive no longer exist. Credit before critique. “jQuery’s selector ergonomics were the right answer to a real problem” sets up “and querySelector made that answer optional” much better than a sneering version of the same point would.
This rule applies to the historical chapters most loudly, but it carries through the rest of the book. We’re standing on shoulders, even when arguing for stepping off them.
Backend / distributed systems
Section titled “Backend / distributed systems”- The DOM as a hierarchical service registry.
- Custom events as a pub/sub bus.
- Forms as transactions (commit, rollback, idempotency, retry).
- Service workers as edge proxies.
- Modules as capabilities behind a boundary, like services behind an API gateway.
- Routing as routing — the same problem backend frameworks solved twenty years ago.
Native / OS
Section titled “Native / OS”- The browser is a process supervisor: tabs are processes, the event loop is the kernel scheduler, the DOM is the window manager.
- Permissions APIs are syscalls.
- Storage tiers (memory, sessionStorage, localStorage, IndexedDB, Cache, OPFS) are exactly the storage hierarchy of an OS.
- Custom elements are the equivalent of a native widget toolkit — Cocoa, GTK, Win32 — finally arriving on the web.
DDD / architecture
Section titled “DDD / architecture”- Boundaries (Evans’s bounded contexts) map directly onto the book’s “boundary” concept. Lean on it explicitly.
- Ubiquitous language: every chapter should be quietly building the reader’s vocabulary — boundary, capability, protocol surface, context tree, runtime, shell. Use the same words consistently.
- Aggregates → form-associated custom elements: a coherent unit with its own invariants and a single transactional commit point.
The rule: every chapter should land at least one cross-discipline analogy that lights up the page for a reader from that other world. Sometimes the analogy is the chapter (e.g., “Forms are transactions”). Other times it’s a single paragraph that gives the senior backend engineer a rope into the room.
5. Before / after
Section titled “5. Before / after”Drawn from the current draft. These are the test cases — if a rewrite passes the smell test on these, it’s on the right track.
Example A — opening of Chapter 1
Section titled “Example A — opening of Chapter 1”Before:
The web did not begin as an application platform in the way we now use that phrase.
It began as a way to connect documents.
That sounds almost too obvious to bother saying, but it matters because nearly every argument about modern frontend development starts in the wrong place. We often talk as if the browser was born as a failed app runtime, as if the history of frontend architecture is the story of developers slowly repairing a platform that was never quite good enough.
After:
The web started as a way to share documents.
That’s worth taking seriously. The first browsers were document viewers. The first servers were document stores. Hypertext was a way to connect one document to another. Forms were a way to send some text from a reader back to a server. The whole system was designed around the idea that you’d request a document, read it, follow a link to another one, and occasionally submit information through a form.
This was a smaller idea than “application platform,” and the smallness is part of what made it work.
What changed: contractions; opening sentence is a plain statement of fact, not a negation of a thesis the reader hasn’t heard yet; concrete enumeration of what the early system actually was, instead of an abstract description of what it wasn’t; the closing sentence of the third paragraph is a quiet thesis claim, not a rhetorical flourish.
Example B — list-as-codeblock from Chapter 11
Section titled “Example B — list-as-codeblock from Chapter 11”Before:
```txtES modulesfetchPromises and async/awaitCustom ElementsShadow DOMslotstemplatesMutationObserver[...20+ more lines]```After (sketch):
Between 2015 and today, browsers shipped a lot. Native modules, so code can be organized without a bundler.
fetch, promises, and async/await, so HTTP no longer needs a wrapper. Custom elements, shadow DOM, slots, and templates — a real component model, in the platform, with no framework required. Three flavors of observer (mutation, intersection, resize) so the DOM can be reacted to without polling. The History API and URL APIs, so routing isn’t something the page has to invent.FormData, constraint validation, andElementInternals, so forms are programmable in a serious way. Native<dialog>and the popover API. CSS custom properties, cascade layers, container queries,:has(), view transitions. Service workers and web workers. A storage tier fromsessionStoragethrough IndexedDB to the Cache API. Cross-tab messaging viaBroadcastChannel.AbortController, so async work is cancellable.Most of the defaults we still teach were formed when none of this existed.
What changed: prose carries the cumulative weight the bare list was trying to express; each item gets a half-clause about why it matters; the closing line is a plain fact about how the field’s defaults were formed, not a rhetorical move.
Example C — Chapter 35’s stub
Section titled “Example C — Chapter 35’s stub”The whole chapter is the example. 85 lines, mostly more list-as-codeblock. Currently it reads like a README for the package. The “Kitsune arrives” chapter should:
- Open with a scene — what does it feel like to start a Kitsune app? A 30-second tour, in prose, of a real example.
- Show one small but complete application, end-to-end, with the prose pointing out where each architectural idea from the previous chapters is now load-bearing.
- Walk the reader through what’s not there — what Kitsune deliberately doesn’t do, and why those gaps are the point.
- Close with the framing that re-anchors the rest of Part VI: the next chapters will build five real applications, and here’s the thread that ties them together.
Target: 3,000–4,000 words. The stub becomes one section out of seven.
6. Quick checks before you ship a paragraph
Section titled “6. Quick checks before you ship a paragraph”Read the paragraph back to yourself out loud. Then ask:
- Does any sentence read as if it’s trying to be impressive? (Cut or replace it.)
- Did I use a “wasn’t X, but Y” formulation? (Almost always remove.)
- Did I lean on em-dash asides for color? (Use commas or full sentences instead.)
- Did I close with a stinger when a plain sentence would do? (Use the plain sentence.)
- Are the abstract claims grounded in a recognizable system, pattern, or example? (If not, ground them.)
- Could a tired engineer reading this at the end of the day follow it without effort? (That’s the bar.)
Two writing references for register, used the same way: would Carson Gross (Hypermedia Systems) have written this? Would Eric Evans (DDD) have written this? Both are plain, both are confident, both trust the reader to find the substance compelling without rhetorical packaging. That’s the target.
7. Open questions
Section titled “7. Open questions”To resolve as we encounter them in the rewrite, not before:
- Diagrams? Several chapters would benefit from architecture diagrams (DOM-as-context-tree, the runtime topology, the boundary model). Do we commit to a diagram style now, or pick it up the first time a chapter cries out for one?
- Sidebars / margin notes? Many O’Reilly books use sidebars for tangents that would otherwise break flow. Starlight supports custom asides. Worth using?
- Voice in code comments and exercise text? Same voice as prose, or terser? The current draft is consistent (formal everywhere); the rewrite should pick a deliberate stance.
Resolved
Section titled “Resolved”- First person? No “I”. Voice is generic “we” / “you” / “some codebases”. The book argues from observation of the field, not from the narrator’s CV.
- Naming names? Yes. Specific frameworks, libraries, and eras get named — credited generously for solving the problems of their day, even when arguing those problems no longer exist.
v1 — drafted from a reading of preface, Ch 1, Ch 11, and Ch 35. Will revise as we work through actual rewrites.