@@ -14,23 +14,28 @@ Write accessible frontend code by default. Semantic HTML covers most needs; ARIA
1. **Semantic HTML first**: Use `<button>`, `<nav>`, `<main>`, `<form>` - not divs with roles
2. **Keyboard accessible**: Everything clickable must be focusable and operable with Enter/Space
3. **Screen reader context**: Labels, alt text, and heading hierarchy convey structure without vision
-4. **No ARIA is better than bad ARIA**: ARIA overrides native semantics and can make things *worse*
+4. **No ARIA is better than bad ARIA**: ARIA overrides native semantics and can make things _worse_
## Quick reference
### Images
+
```html
<!-- Informative: describe content -->
-<img src="chart.png" alt="Sales increased 25% from Q1 to Q2">
+<img src="chart.png" alt="Sales increased 25% from Q1 to Q2" />
<!-- Decorative: empty alt -->
-<img src="divider.png" alt="">
+<img src="divider.png" alt="" />
<!-- Complex: summarize + link to details -->
-<img src="flowchart.png" alt="User registration flow. Details in following section.">
+<img
+ src="flowchart.png"
+ alt="User registration flow. Details in following section."
+/>
```
### Interactive elements
+
```html
<!-- Correct: semantic button -->
<button onclick="save()">Save</button>
@@ -38,26 +43,40 @@ Write accessible frontend code by default. Semantic HTML covers most needs; ARIA
<!-- Wrong: div cosplaying as button -->
<div onclick="save()" role="button" tabindex="0">Save</div>
```
+
The div requires `role`, `tabindex`, `onkeydown` for Enter/Space, focus styles, and still won't work with voice control. Use `<button>`.
### Forms
+
```html
<label for="email">Email address</label>
-<input type="email" id="email" name="email" required aria-describedby="email-hint">
+<input
+ type="email"
+ id="email"
+ name="email"
+ required
+ aria-describedby="email-hint"
+/>
<span id="email-hint">We'll never share your email</span>
```
+
Every input needs a visible `<label>` with matching `for`/`id`. Use `aria-describedby` for hints, `aria-invalid` for errors.
### Headings
+
```html
-<h1>Page title</h1> <!-- One per page -->
- <h2>Section</h2> <!-- Don't skip levels -->
- <h3>Subsection</h3>
- <h2>Another section</h2>
+<!-- One per page -->
+<h1>Page title</h1>
+<!-- Don't skip levels -->
+<h2>Section</h2>
+<h3>Subsection</h3>
+<h2>Another section</h2>
```
+
Headings create navigable structure. Screen reader users jump by heading level.
### Links
+
```html
<!-- Good: describes destination -->
<a href="/pricing">View pricing plans</a>
@@ -70,14 +89,14 @@ Headings create navigable structure. Screen reader users jump by heading level.
Use ARIA only when HTML has no semantic equivalent:
-| Need | Solution |
-|------|----------|
-| Button | `<button>` not `role="button"` |
-| Navigation | `<nav>` not `role="navigation"` |
-| Live updates | `aria-live="polite"` (no HTML equivalent) |
-| Current page | `aria-current="page"` (no HTML equivalent) |
+| Need | Solution |
+| -------------- | ------------------------------------------- |
+| Button | `<button>` not `role="button"` |
+| Navigation | `<nav>` not `role="navigation"` |
+| Live updates | `aria-live="polite"` (no HTML equivalent) |
+| Current page | `aria-current="page"` (no HTML equivalent) |
| Expanded state | `aria-expanded="true"` (no HTML equivalent) |
-| Custom widget | ARIA + keyboard handling (last resort) |
+| Custom widget | ARIA + keyboard handling (last resort) |
## Common violations to avoid
@@ -98,29 +117,30 @@ Respect user preferences for reduced motion:
```css
/* Default: full animation */
.animated {
- transition: transform 0.3s ease;
+ transition: transform 0.3s ease;
}
/* Reduce or remove for users who prefer it */
@media (prefers-reduced-motion: reduce) {
- .animated {
- transition: none;
- }
+ .animated {
+ transition: none;
+ }
}
```
Or start safe and enhance:
+
```css
/* Safe default */
.animated {
- transition: none;
+ transition: none;
}
/* Only animate if user hasn't requested reduced motion */
@media (prefers-reduced-motion: no-preference) {
- .animated {
- transition: transform 0.3s ease;
- }
+ .animated {
+ transition: transform 0.3s ease;
+ }
}
```
@@ -129,17 +149,20 @@ Applies to: transitions, transforms, parallax, auto-playing video, animated illu
## Framework-specific notes
### React/JSX
+
- `htmlFor` instead of `for`
- `className` instead of `class`
- Fragments (`<>`) don't affect accessibility tree
- Manage focus with refs when content changes dynamically
### Component libraries
+
If using Radix, Headless UI, or similar - they handle ARIA. Don't add redundant attributes.
## Validation
Generated code should pass:
+
- **axe-core**: Catches ~57% of WCAG issues automatically
- **Manual keyboard test**: Tab through everything, operate with Enter/Space
- **Screen reader spot check**: VoiceOver (Mac), NVDA (Windows), Orca (Linux)
@@ -149,6 +172,7 @@ Automated tools miss context-dependent issues (alt text quality, heading hierarc
## Detailed patterns
See [patterns.md](references/patterns.md) for:
+
- Modal dialogs and focus management
- Custom select/combobox
- Tabs and tab panels
@@ -9,13 +9,14 @@ metadata:
# Humanizing Text: Quick Start
-The goal is not to make text "worse" but to make it *believably human*. Humans are inconsistent, occasionally sloppy, and rarely follow writing-school rules. LLMs are the opposite. Invert LLM defaults.
+The goal is not to make text "worse" but to make it _believably human_. Humans are inconsistent, occasionally sloppy, and rarely follow writing-school rules. LLMs are the opposite. Invert LLM defaults.
## Step 1: Strip the AI polish
Remove or replace these dead giveaways before anything else:
**Overwrought significance phrases:**
+
- "stands as a testament to" โ "is" or "shows" or just delete
- "a pivotal moment in" โ "when" or "this was"
- "marking a shift toward" โ "then" or "after that"
@@ -24,12 +25,14 @@ Remove or replace these dead giveaways before anything else:
- "in the broader landscape of" โ delete
**Canned analysis phrases:**
+
- "highlighting..." / "emphasizing..." / "underscoring..." (as sentence-ending participles) โ delete or recast as a standalone sentence
- "reflecting broader trends in" โ delete
- "contributing to the ongoing dialogue" โ delete
- "valuable insights into" โ "ideas about" or delete
**Promotional fluff:**
+
- "boasts a vibrant" โ "has"
- "nestled in the heart of" โ "in"
- "rich tapestry of" โ delete, describe the thing directly
@@ -37,11 +40,13 @@ Remove or replace these dead giveaways before anything else:
- "renowned" โ "known for [specific thing]" or just name-drop
**Media-coverage chest-beating:**
+
- "has been featured in" / "profiled in" โ "was covered in" or just name the publication inline
- "independent coverage in notable outlets" โ name the outlets or skip
- "maintains an active social media presence" โ "posts on X" or delete
**Avoidance of simple verbs:**
+
- "serves as" โ "is"
- "stands as" โ "is"
- "marks a" โ "is"
@@ -50,22 +55,27 @@ Remove or replace these dead giveaways before anything else:
- "features a diverse array of" โ "has"
**Negative parallelisms / unearned grandiosity:**
+
- "not just X, but also Y" โ "X and Y" or say what you mean directly
- "It is not ..., it is ..." โ one direct clause
- "no ..., no ..., just ..." โ one direct clause
- "More than just [category]" โ describe the thing directly without the elevation pitch
**Rule-of-three lists:**
+
- "adjective, adjective, and adjective" โ trim to one or two, or vary the structure
- "short phrase, short phrase, and short phrase" โ break the rhythm: make one longer, merge two, drop one
**AI vocabulary (high-density red flags):**
+
- Delete or replace: additionally, delve, crucial, pivotal, robust, intricate, interplay, tapestry, testament, underscore, vibrant, meticulous, fostering, enhancing, enduring, bolster, garner, align with, resonate with, exemplify, showcase
**Em dashes:**
+
- Replace with commas, parentheses, or just separate sentences. If you keep them, use `--` (two hyphens) instead of `โ`, and use them sparingly.
**Bulky structure:**
+
- Kill rigid "Challenges and Future Directions" / "Future Outlook" sections unless the user explicitly asked for them
- Kill the formulaic "Despite [positive], [subject] faces challenges..." paragraph structure
- Kill the "In conclusion" / "In summary" wrapper
@@ -73,15 +83,17 @@ Remove or replace these dead giveaways before anything else:
## Step 2: Add human irregularities
-Vary technique by desired register. Use *lightly* โ one or two touches per paragraph, not every sentence.
+Vary technique by desired register. Use _lightly_ โ one or two touches per paragraph, not every sentence.
### Sentence rhythm
+
- **Vary sentence length dramatically.** Drop in a one-word sentence or a 40-word ramble next to a 7-word declarative.
- **Start sentences with "And" or "But"** occasionally.
- **Use sentence fragments.** "Anyway." "Not really." "The usual."
- **Break a long sentence with an aside** that could have been a footnote: "the thing โ and this was back in 2019, before everything changed โ happened."
### Informal punctuation
+
- Replace some em dashes with double hyphens `--`
- Use en-dashes where a human might (sloppily) use hyphens
- Let a comma splice slip through if the tone is casual enough
@@ -90,17 +102,20 @@ Vary technique by desired register. Use *lightly* โ one or two touches per par
- End an occasional sentence with a preposition if that's how people actually talk
### Contractions and compression
+
- Expand contractions for formality. Contract them for informality. Most AI output under-uses contractions.
- Use "can't," "won't," "it's," "that's," "there's" in casual text.
- Drop auxiliary verbs in casual speech patterns: "Guess so," "Makes sense."
### Imperfections
+
- **Occasional typos or misspellings** in very informal contexts (not for anything important): "recieve," "definately," "seperate" โ no more than one per few hundred words
- **Minor grammar slips** that don't impede readability: "me and Jake went," "should of," "less people" โ only when the register is extremely casual
- **Inconsistent capitalization** of words-for-emphasis in informal writing: "it was Bad"
- **Elision:** "wanna," "gonna," "kinda," "sorta," "dunno" โ appropriate for dialogue, social posts, very casual blogging
### Vocabulary shifts
+
- Replace Latinate abstractions with Anglo-Saxon specifics.
- Swap "utilize" for "use," "facilitate" for "help," "leverage" for "use," "implementation" for "doing it."
- Swap "individuals" for "people," "purchased" for "bought," "located" for "in."
@@ -109,12 +124,14 @@ Vary technique by desired register. Use *lightly* โ one or two touches per par
- Drop a colloquialism: "whatever," "I mean," "honestly," "to be fair," "look," "like" (as filler)
### First-person and opinion
+
- AI defaults to third-person neutrality. Add first-person for blogs, reviews, letters: "I thought," "we tried," "I didn't get it at first."
- Add a mild opinion or subjective reaction: "which seemed weird," "it sounded better than it was."
- **Take a stand instead of hedging.** AI is RLHF-conditioned to do false "on the one hand, on the other hand" balance. Humans pick a side (unless they genuinely feel ambivalent). State what you think. Use hyperbole for effect โ exaggeration is human; terrified neutrality is AI.
- **If you don't know, say so.** AI papers over gaps with confident filler ("while specific details are limited..."). Humans say "I don't know" or "nobody's sure" or just skip it.
### Specificity over abstraction
+
- AI replaces specific facts with generic praise. Reverse it: "a revolutionary titan of industry" โ "the guy who invented the train coupler in 1873."
- Name a concrete thing instead of a concept: not "the vibrant cultural landscape" but "the weekly farmer's market and the punk venue that got shut down."
@@ -122,22 +139,22 @@ Vary technique by desired register. Use *lightly* โ one or two touches per par
The degree of humanization depends on context:
-| Context | Techniques |
-|---|---|
-| Blog post / newsletter | Contractions, first person, asides, varied sentence length |
-| Social media comment | Fragments, elisions, lowercase, occasional typos, emoji |
-| Business email (casual) | Contractions, lighter structure, drop promotional phrasing, one conversational aside |
-| Fiction dialogue | Elisions, interruptions, trailing thoughts, imperfect grammar |
+| Context | Techniques |
+| ----------------------- | ----------------------------------------------------------------------------------------------------- |
+| Blog post / newsletter | Contractions, first person, asides, varied sentence length |
+| Social media comment | Fragments, elisions, lowercase, occasional typos, emoji |
+| Business email (casual) | Contractions, lighter structure, drop promotional phrasing, one conversational aside |
+| Fiction dialogue | Elisions, interruptions, trailing thoughts, imperfect grammar |
| Academic-adjacent essay | Kill AI vocabulary, replace vague analysis with specific claims, vary structure, keep grammar correct |
-| Forum post | All of the above, plus lowercase aggression, sarcasm, or enthusiasm as appropriate |
+| Forum post | All of the above, plus lowercase aggression, sarcasm, or enthusiasm as appropriate |
## What NOT to do
- Don't make every sentence sloppy. Irregularity only works next to regularity.
- Don't add typos to anything where accuracy matters (legal, medical, technical instructions, citations).
- Don't overdo the "uh" and "like" verbal filler โ it reads as parody.
-- Don't strip all structure. Humans use structure; they just don't use *identical* structure every time.
-- Don't make the text *harder to read*. Make it *more natural to read*.
+- Don't strip all structure. Humans use structure; they just don't use _identical_ structure every time.
+- Don't make the text _harder to read_. Make it _more natural to read_.
## Reference
@@ -170,6 +170,7 @@ Preserve the order the feature-branch commits originally appeared in the persona
The rebase todo must be structured as: **drop โ break โ pick**. The drops remove stale feature-branch commits, the break pauses the rebase so fresh cherry-picks can be inserted, and the remaining picks replay personal-only commits on top.
Build a sed command that:
+
1. Changes `pick` to `drop` for each identified commit
2. Inserts a `break` line after the last `drop`, before the first remaining `pick`
@@ -195,16 +196,19 @@ The rebase is paused. Cherry-pick feature branches back in now, before the perso
For each feature branch, in the order confirmed in step 4:
1. Get commits oldest-first:
+
```sh
git log --oneline --reverse upstream/<canonical>..<branch>
```
2. **If the branch has a single commit**, cherry-pick it:
+
```sh
git cherry-pick <hash>
```
3. **If the branch has multiple commits**, cherry-pick the first, then fixup the rest:
+
```sh
git cherry-pick <first-hash>
git cherry-pick --no-commit <second-hash>
@@ -212,6 +216,7 @@ For each feature branch, in the order confirmed in step 4:
git cherry-pick --no-commit <third-hash>
git commit --amend --no-edit
```
+
Continue for all remaining commits.
4. **If `cherry-pick --no-commit` hits a conflict**: resolve per [Handling conflicts](#handling-conflicts), `git add` resolved files, then `git cherry-pick --quit` to clear the cherry-pick state while preserving staged changes, then `git commit --amend --no-edit`.
@@ -231,9 +236,11 @@ This replays the personal-only commits on top of the freshly cherry-picked featu
### Step 8: Final verification
1. Review the log:
+
```sh
git log --oneline upstream/<canonical>..HEAD
```
+
Confirm the expected structure: personal-only commits and one squashed commit per re-picked feature branch, in the expected order.
2. Run the full test suite.