Foundations

The rule sets every language, chart, and page builds on. Numbered, permanent, cited where perception research backs a law.

FN-01 . Token contract  |  FN-02 . Canvas and spacing grid  |  FN-03 . Type scale  |  FN-04 . Contrast and color use  |  FN-05 . Numbers, units, and scales  |  FN-06 . Perceptual foundations  |  <!-- Generated by tools/build_blocks.py from decision/voice.json. Do not hand-edit. -->

FN-01 . Token contract

The rule that makes the whole catalogue themeable and deterministic:

Chart and component specs reference color ROLES, never hex values. Design languages (DL files) bind roles to hex. Rebranding = swapping the DL token file. No spec changes, no re-authoring.

Required roles (every DL must bind all of these)

RoleMeaning
backgroundpage/canvas fill
inkheadings, key numbers, strongest text
bodysupporting text, labels, sources
primarythe one accent; highlights, key series
mutedcontext series, de-emphasized marks
gridlinechart gridlines
hairlinerules, baselines, separators
positivegood deltas (always paired with a word, never alone)
negativebad deltas (same)

Optional roles a DL may add: panel, benchmark, warning, primaryDark, and others. Specs that want an optional role declare a fallback chain, for example "context": ["benchmark", "muted"]: first role present in the palette wins. The renderer resolves the chain, so a spec never breaks on a DL that lacks an optional role.

Rules

  1. Hex values live in tokens/DL-xx.json only. A hex value inside a chart spec or component spec fails validation on sight.
  2. All hex is #RRGGBB uppercase. Enforced by schema/dl.schema.json and tools/validate.py.
  3. ink and body must reach 4.5:1 contrast on background (WCAG AA). Enforced by tools/validate.py.
  4. Fonts follow the same contract: specs reference display or body, the DL binds each to a family stack whose last entries are installed-everywhere fallbacks.

FN-02 . Canvas and spacing grid

Canvases

TargetSizeUse
Chart entry golden render960 x 540 pxevery CH-xx golden
Full slide (16:9)1280 x 720 pxrecipes (DL/CH/CP combinations)

All positions and sizes in specs are exact pixels on these canvases. Adjectives ("comfortable margin", "medium bar") are banned in specs; a value the renderer cannot consume is not a spec.

The 8px grid

Every structural distance is a multiple of 8: margins, offsets, bar heights, gaps, plot bounds.

DistanceValue
Canvas edge to content32 px
Title block to plot area>= 40 px
Bar height / bar gap (CH-01)32 / 16 px
Label offset from mark8 or 16 px

Text sizes are exempt from the 8-multiple (they follow FN-03) but their anchor positions are not.

Fixed furniture on every chart canvas


FN-03 . Type scale

Sizes are fixed per text role on the 960x540 chart canvas. A DL changes the family and weight, never the size or position (those belong to the chart spec).

Text roleSizeFont slotNotes
Title24 pxdisplayfull sentence, states the finding with a number
Eyebrow11 pxbody, weight 600CAPS, letter-spacing 2, only if DL chrome
Category / series label13 pxbodyweight 600 only on the highlighted item
Value label13 pxbodyweight 600 only on the highlighted item
Tick label11 pxbody
X-axis label11 pxbody
Annotation12 pxbody, italic
Source line11 pxbody

Rules

  1. Two font slots only: display (titles) and body (everything else). A third slot (mono for IDs and timestamps) is reserved for DLs that declare it; no spec may require it.
  2. Every DL family stack ends in an installed-everywhere fallback (Segoe UI, Arial, Georgia, Consolas). Silent substitution with a different metric font is the failure mode this prevents.
  3. Nothing below 11 px on the 960x540 canvas. On the 1280x720 slide canvas the floor is 12 px.
  4. Emphasis is weight (400 to 600), never a size bump, never underline.

FN-04 . Contrast and color use

Hard limits (validated, not advisory)

  1. ink and body reach 4.5:1 on background (WCAG AA body text). tools/validate.py computes this from the DL token file and blocks on failure.
  2. Meaning is never carried by color alone. Status, deltas, and exceptions always pair color with a word or a number.
  3. One saturated highlight per chart. The primary role appears on the one mark the title talks about; everything else uses muted or benchmark.

Discipline

The banned list (applies to every DL, every chart)


FN-05 . Numbers, units, and scales

Numbers

  1. Tabular (monospaced-figure) rendering wherever numbers stack in columns; right-aligned in tables.
  2. Units appear ONCE per chart, not per value: - bar charts: on the first (largest) value label ("34 items", then "28", "21", ...) - line charts: on the top y tick label ("80%", then "60", "40", ...)
  3. Missing value = "-" (hyphen nil marker), never zero, never a guess.
  4. Titles state the finding with a number. "Backlog overview" fails QA; "Electrical holds 34 of 109 open items" passes.

Scales (deterministic by construction)

Bars start at zero, always, no exceptions. Line charts start at zero by default; a non-zero baseline requires a written justification in the entry that uses it.

Tick generation is an algorithm, not taste, so two renders can never disagree:

raw  = max_value / target_ticks        (target_ticks = 5)
mag  = 10 ^ floor(log10(raw))
step = first of {1, 2, 5, 10} * mag that is >= raw
top  = ceil(max_value / step) * step
ticks = 0, step, 2*step, ... top

Direct-label bar charts skip the axis entirely and scale bars to the max value; the labels carry the numbers.

Float formatting in renders

All coordinates format as max-2-decimal, trailing zeros stripped, "-0" normalized to "0". This is what makes byte-identical re-renders possible across machines.


FN-06 . Perceptual foundations

Every OVP rule traces to a named finding in visual perception research, not to taste. This entry is the trace, one line per rule family. It is deliberately one page: OVP cites the science, it does not rewrite it.

OVP rulePerceptual basis
One primary highlight per chart (FN-04)Preattentive pop-out: one distinct hue is found in constant time; two or more force serial search (Treisman; Ware)
Bars and positions over pies and areas (CH family design)Graphical perception hierarchy: position and length are decoded far more accurately than angle and area (Cleveland & McGill)
Pie capped at 3 slices, warn status (CH-PTW-03/04)Angle judgment error grows with slice count; under ~15% differences angles are unreadable (Cleveland & McGill)
Max 4 stacked segments, max 5 KPI cardsWorking-memory span: ~4 chunks held reliably (Cowan; Miller)
Direct labels and line-end labels, never legendsEvery legend lookup is a saccade round-trip that reloads working memory (Ware; Few)
Annotation anchored at the data (CH-TIM rules)Attention follows pointers; unanchored commentary is ignored under load (Ware)
8px grid, gaps group related elements (FN-02)Gestalt proximity and common region: spacing IS structure
Status word + color, never color alone (FN-04)~8% of men have deficient color vision; hue is not a channel you can require (accessibility canon)
Zero baselines on bars and areas (FN-05)Length encoding lies when truncated; the lie compounds with fill (Tufte's lie factor)
Muted context + one saturated seriesContrast drives salience; salience should follow the message, not the palette (Ware; Few)
Action titles stating the finding (CORE rule 1)Assertion-evidence structure improves recall and decision agreement versus topic titles (presentation research canon)
Tabular figures, right-aligned numbers (FN-05)Digit alignment enables column scanning as a single visual object

Canon referenced: Bertin (Semiologie graphique), Cleveland & McGill (graphical perception experiments), Ware (Information Visualization), Munzner (Visualization Analysis and Design), Tufte (VDQI), Few (Show Me the Numbers), Treisman (preattentive processing), Cowan/Miller (working memory), Kahneman (attention and effort).

Rule for extending OVP: a new rule that cannot cite a row here, or add one, is a preference, and preferences do not enter the protocol.


<!-- Generated by tools/build_blocks.py from decision/voice.json. Do not hand-edit. -->

FN-07 . Voice and prose

Design languages control how a page looks. This contract controls how it reads. It bans the patterns that make machine-written prose identical everywhere, and each design language layers its own register on top.

A design language that controls the palette but leaves the words to chance ships half an identity. Every generated word now resolves the same way a color does: the universal laws below first, then the voice block of the design language in use.

The universal laws

#LawWhyHow it is checked
V1No em-dashes.The single strongest machine-writing tell. A comma, a period, a colon, or a parenthesis always fits.no U+2014 or U+2013 in any generated prose
V2Numbers replace intensity adjectives.An intensity word without a quantity is an opinion wearing a fact's clothes. If it cannot be quantified, it cannot be claimed.a vague_words hit with no digit in the same sentence fails
V3The banned phrase list is closed and greppable.These phrases carry no information and appear in every model's output. Deleting them costs nothing and removes the accent.no banned_phrases substring, case-insensitive
V4Active voice with a named subject.Hollow constructions hide who acts. Someone decides, ships, blocks, approves. The exception is legal register, where the document is the actor.no hollow_patterns substring, case-insensitive
V5One idea per sentence, under the language's cap.Stacked clauses are how a model pads. Each design language sets its own sentence_max_words.every sentence within the design language's sentence_max_words
V6No throat-clearing.The first sentence of a block carries content. An opener that restates the context is deleted, not shortened.human review; the banned list covers the common openers
V7No decorative triads.Three adjectives in a row are rhythm, not information. A list exists when the items differ in content.human review
V8No exclamation marks.Emphasis comes from the fact, not the punctuation. This holds in every design language.no exclamation mark outside quoted material

Exemptions

The closed lists

Machine-checkable, case-insensitive, substring match. Canonical source: decision/voice.json.

Banned phrases (33): it's worth noting, it is worth noting, worth noting that, delve, dive into, in today's, fast-paced, seamless, holistic, cutting-edge, game-changer, unlock the, elevate your, streamline, navigate the complexities, at the end of the day, when it comes to, plays a crucial role, not just, but rather, the landscape of, leveraging, leverage the, testament to, a myriad of, in conclusion, furthermore, moreover, interesting, notably, importantly, clearly, obviously.

Words that need a number in the same sentence (23): significant, major, substantial, considerable, dramatic, notable, remarkable, robust, various, several, properly, appropriately, as needed, efficiently, effectively, potential, potentially, carefully, stunning, exceptional, finest, world-class, passion.

Hollow constructions (14): is being made, are being made, progress is being, it was decided, there are several, there is a need, we believe, we would like to, we are pleased to, it might be, may need to, going forward, a good idea, in order to.

Per-language voice

Each design language carries a voice block in its token file: stance, register, mood, hedging policy, a sentence cap, a title cap, the title grammar, three precepts to follow, three to avoid, and one contrast pair. The validator checks that the block's own prose obeys the laws above, that the examples fit the declared caps, and that the generic counter-example trips at least one law.

LanguageRegisterSentence capTitle capTitle example
DL-01 AGRAWmeasured, formal-plain18 words12 wordsCapex holds at plan; the schedule does not.
DL-02 KATAclipped, telegraphic12 words12 wordsClearance: 82% complete, up 5 points on last week.
DL-03 LOGOSanalytic prose25 words14 wordsFreight cost peaked in March because the joints shipped by air
DL-04 SHILPAtechnical, impersonal16 words12 wordsJB-4102 termination sequence, revision C
DL-05 OBEYAspoken, direct8 words8 wordsWho unblocks the north loops this week?
DL-06 LEXlegal-neutral22 words14 wordsContractor notified of differing site conditions on 14 March 2025 (Letter C-1042)
DL-07 SAGAjournalistic22 words12 wordsFirst joint clears customs after a three-week hold
DL-08 SENTINELlabel vocabulary, closed set10 words10 wordsSTATION 4 PRESSURE: WATCH. TRENDING +2%/H SINCE 06:00.
DL-09 ATLASpositional, kinetic18 words12 wordsKP 812 to 840: three crossings pending, corridor clear
DL-10 BASIRAspare, documentary20 words14 wordsStation 7, 28 July. First permanent power, eleven weeks early.
DL-11 SUTRAformal, dense20 words12 wordsRecommendation to defer the station tie-in to Q2
DL-12 NOROSHIurgent-terse12 words10 wordsDiesel stock: 6 days left. Decision needed Thursday.
DL-13 MIZANwarm, literary-plain24 words12 wordsCedar, brass, and forty years of the same hands
DL-14 EVIDENTIAquantified, footnoted20 words14 wordsLogistics drives 62% of the overrun; three orders carry half
DL-15 ABRIDstructural, relational20 words12 wordsThree levers, one constraint: clearance capacity gates them all
DL-16 TELOSdirect, conclusive18 words12 wordsYes: the Q4 target holds if trenching restarts by 1 October

Runtime cost

The prose above is the handbook surface and never enters an agent context. The runtime payload is the voice block inside the one design language a request resolves to, plus the laws above in compact form. Section 2.1 of PROTOCOL.md governs: an agent loads one language, not the catalogue.