Tooling
This commit is contained in:
@@ -0,0 +1,486 @@
|
||||
---
|
||||
name: terrain studio
|
||||
description: A dark instrument panel for painting a planet's geology and reading back the ground it makes.
|
||||
colors:
|
||||
hot: "#d6a03a"
|
||||
hot-ink: "#17181a"
|
||||
ok: "#6fbf73"
|
||||
ok-ink: "#bfe6c1"
|
||||
warn: "#b4553f"
|
||||
warn-ink: "#f0b4a4"
|
||||
void: "#0b0e11"
|
||||
well: "#11151a"
|
||||
bg: "#14181d"
|
||||
panel: "#1b2027"
|
||||
row-hover: "#222831"
|
||||
row-live: "#252b34"
|
||||
raised: "#262d36"
|
||||
line: "#2b323b"
|
||||
ink: "#d8dee6"
|
||||
dim: "#8b95a1"
|
||||
scrim: "#0d1014ee"
|
||||
scrim-hud: "#0d1014dd"
|
||||
chip-edge: "#0006"
|
||||
typography:
|
||||
body:
|
||||
fontFamily: "ui-monospace, \"Cascadia Mono\", Menlo, Consolas, monospace"
|
||||
fontSize: "13px"
|
||||
fontWeight: 400
|
||||
lineHeight: 1.45
|
||||
letterSpacing: "normal"
|
||||
data:
|
||||
fontFamily: "ui-monospace, \"Cascadia Mono\", Menlo, Consolas, monospace"
|
||||
fontSize: "11.5px"
|
||||
fontWeight: 400
|
||||
lineHeight: 1.45
|
||||
letterSpacing: "normal"
|
||||
note:
|
||||
fontFamily: "ui-monospace, \"Cascadia Mono\", Menlo, Consolas, monospace"
|
||||
fontSize: "11px"
|
||||
fontWeight: 400
|
||||
lineHeight: 1.45
|
||||
letterSpacing: "normal"
|
||||
label:
|
||||
fontFamily: "ui-monospace, \"Cascadia Mono\", Menlo, Consolas, monospace"
|
||||
fontSize: "11px"
|
||||
fontWeight: 600
|
||||
lineHeight: 1.45
|
||||
letterSpacing: "0.09em"
|
||||
rounded:
|
||||
sm: "2px"
|
||||
md: "3px"
|
||||
lg: "4px"
|
||||
spacing:
|
||||
xs: "4px"
|
||||
sm: "6px"
|
||||
md: "8px"
|
||||
lg: "10px"
|
||||
xl: "16px"
|
||||
components:
|
||||
button:
|
||||
backgroundColor: "{colors.raised}"
|
||||
textColor: "{colors.ink}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "6px 10px"
|
||||
button-hover:
|
||||
backgroundColor: "{colors.raised}"
|
||||
textColor: "{colors.ink}"
|
||||
button-disabled:
|
||||
backgroundColor: "{colors.raised}"
|
||||
textColor: "{colors.dim}"
|
||||
button-primary:
|
||||
backgroundColor: "{colors.hot}"
|
||||
textColor: "{colors.hot-ink}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "6px 10px"
|
||||
button-warn:
|
||||
backgroundColor: "{colors.raised}"
|
||||
textColor: "{colors.warn-ink}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "6px 10px"
|
||||
button-toggle-on:
|
||||
backgroundColor: "{colors.raised}"
|
||||
textColor: "{colors.hot}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "6px 10px"
|
||||
swatch-row:
|
||||
backgroundColor: "transparent"
|
||||
textColor: "{colors.ink}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "4px 6px"
|
||||
swatch-row-hover:
|
||||
backgroundColor: "{colors.row-hover}"
|
||||
textColor: "{colors.ink}"
|
||||
swatch-row-selected:
|
||||
backgroundColor: "{colors.row-live}"
|
||||
textColor: "{colors.ink}"
|
||||
chip:
|
||||
rounded: "{rounded.md}"
|
||||
size: "18px"
|
||||
chip-key:
|
||||
rounded: "{rounded.md}"
|
||||
size: "12px"
|
||||
input-number:
|
||||
backgroundColor: "{colors.well}"
|
||||
textColor: "{colors.ink}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.md}"
|
||||
padding: "2px 5px"
|
||||
width: "78px"
|
||||
toast:
|
||||
backgroundColor: "{colors.scrim}"
|
||||
textColor: "{colors.ink}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "6px 9px"
|
||||
toast-error:
|
||||
backgroundColor: "{colors.scrim}"
|
||||
textColor: "{colors.warn-ink}"
|
||||
toast-ok:
|
||||
backgroundColor: "{colors.scrim}"
|
||||
textColor: "{colors.ok-ink}"
|
||||
hud:
|
||||
backgroundColor: "{colors.scrim-hud}"
|
||||
textColor: "{colors.dim}"
|
||||
typography: "{typography.body}"
|
||||
rounded: "{rounded.lg}"
|
||||
padding: "6px 9px"
|
||||
progress-track:
|
||||
backgroundColor: "{colors.well}"
|
||||
rounded: "{rounded.md}"
|
||||
height: "6px"
|
||||
progress-fill:
|
||||
backgroundColor: "{colors.hot}"
|
||||
height: "6px"
|
||||
ramp:
|
||||
rounded: "{rounded.sm}"
|
||||
height: "12px"
|
||||
---
|
||||
|
||||
# Design System: terrain studio
|
||||
|
||||
## Overview
|
||||
|
||||
**Creative North Star: "The Instrument Panel"**
|
||||
|
||||
terrain studio is a gauge with a world in it. The left rail is calibrated measurement — a rate typed in mm/yr
|
||||
comes back as the hillslope angle it buys, a brush size comes back as metres on the ground, a bake comes back as
|
||||
minutes — and the rest of the window is the specimen those numbers describe. Everything in the chrome is either a
|
||||
reading, a control, or the hairline that separates the two. There is no third category, and nothing in the frame
|
||||
exists to be looked at.
|
||||
|
||||
The room is dark because the work is coloured. Every hue that means anything in this product belongs to the
|
||||
painting: a class colour is an uplift rate, a ramp is a field in mm/yr, a region colour is a landmass. So the
|
||||
instrument around it is made of iron and ink, with exactly one warm colour — brass — reserved for the two things
|
||||
the machine can tell you about itself: what you can act on, and what is currently live. A second hue in the
|
||||
chrome would be a colour that looks like data and isn't.
|
||||
|
||||
It is patient, and it explains itself. Under a control that takes a number nobody has an intuition for sits an
|
||||
11px note in graphite saying what that number does to the ground, and the notes say *why* rather than *what* —
|
||||
"a mark you cannot see is one you will paint over". That voice is part of the system, not commentary bolted to
|
||||
it. The tool assumes a reader who will read, and it is written for someone who opens it every few weeks rather
|
||||
than every day.
|
||||
|
||||
**Key Characteristics:**
|
||||
|
||||
- One monospace family, three sizes (13px / 11.5px / 11px), no display type anywhere.
|
||||
- A fixed 300px rail against a fluid canvas; the canvas absorbs every pixel of a resize.
|
||||
- Flat by doctrine: not one `box-shadow` in the system. Depth is tonal value plus a 1px hairline.
|
||||
- Brass (#d6a03a) is the only warm colour and never describes data.
|
||||
- State changes are instant. The single animation in the product measures something that actually takes time.
|
||||
- Monospace alignment is load-bearing — reports are `white-space: pre` and the columns are the layout.
|
||||
|
||||
## Colors
|
||||
|
||||
An iron room lit by one brass lamp, with verdigris and rust kept in reserve for the two things the machine needs
|
||||
to say out loud.
|
||||
|
||||
### Primary
|
||||
|
||||
- **Brass** (#d6a03a): The only warm colour in the product, and the only colour in the chrome that isn't data. It
|
||||
marks exactly two conditions. *Filled* (brass background, #17181a text) means "this is the action" — the Plan
|
||||
button, the Bake button. *Outlined* (brass border, brass text, surface unchanged) means "this is the one that
|
||||
is live" — the selected class swatch, the open tab, the map currently drawn over the painting, the border that
|
||||
appears under the cursor. It is also the fill of the bake progress bar, which is the same statement in a third
|
||||
grammar: this is the thing currently happening.
|
||||
- **Brass Ink** (#17181a): Text on a filled brass surface. Near-black rather than the room's own background, so
|
||||
a primary button reads as a lit plate and not as a hole.
|
||||
|
||||
### Secondary
|
||||
|
||||
- **Verdigris** (#6fbf73): Success, and only success — the border of a confirmation toast. Patina on brass: the
|
||||
same metal, cooled. It appears for four seconds and then removes itself.
|
||||
- **Verdigris Light** (#bfe6c1): Text inside a success toast, lifted so the message reads at 13px against a
|
||||
near-black scrim.
|
||||
|
||||
### Tertiary
|
||||
|
||||
- **Rust** (#b4553f): Failure and danger — the border of an error toast, and the border of the Cancel button that
|
||||
stops a running bake. Oxidised iron: the room's own material gone wrong.
|
||||
- **Rust Light** (#f0b4a4): Text on a rust-bordered surface. Warm enough to be legible at 11.5px, desaturated
|
||||
enough that it never competes with brass for "act on this".
|
||||
|
||||
### Neutral
|
||||
|
||||
The neutrals are one continuous ladder of the same cold iron, and their order *is* the depth system:
|
||||
|
||||
- **Void** (#0b0e11): The canvas clear colour, behind and around the world. The darkest value in the product,
|
||||
because it is the only surface that is genuinely nothing.
|
||||
- **Well** (#11151a): Recessed surfaces — number inputs, the progress track. Below the panel: things you put
|
||||
values into.
|
||||
- **Cold Iron** (#14181d): The page and the stage. The default ground.
|
||||
- **Panel Iron** (#1b2027): The 300px rail. One step up from the stage, which is the whole reason the rail reads
|
||||
as a separate instrument.
|
||||
- **Iron Hover** (#222831): A selectable row under the cursor.
|
||||
- **Iron Live** (#252b34): The selected row, paired with a brass border.
|
||||
- **Raised Iron** (#262d36): Buttons. Above the panel: things you press.
|
||||
- **Hairline** (#2b323b): Every border in the product, always exactly 1px.
|
||||
- **Cold Ink** (#d8dee6): Primary text and every value the user typed or chose.
|
||||
- **Graphite** (#8b95a1): Labels, notes, HUD readouts, report bodies, section headings. The voice of the
|
||||
instrument, as distinct from the values it holds.
|
||||
- **Scrim** (#0d1014ee) and **Scrim HUD** (#0d1014dd): Floating chrome over the canvas — the toast at 93% and the
|
||||
cursor readout at 87%. Darker than any inline surface and deliberately translucent, so a floating thing is
|
||||
legible without ever hiding the world underneath it.
|
||||
- **Chip Edge** (#0006): The 40%-black hairline around a colour chip, so a swatch keeps its edge against both a
|
||||
pale class colour and a dark one.
|
||||
|
||||
### Named Rules
|
||||
|
||||
**The One Warm Thing Rule.** Brass is the only warm colour on screen. It marks what you can act on (filled) or
|
||||
what is currently live (outlined), and it never describes data. If a new element needs attention and is neither
|
||||
of those two things, it does not get brass — it gets a note.
|
||||
|
||||
**The Data Owns Colour Rule.** Hue inside the canvas belongs to the painting, the legend and the map ramps. The
|
||||
chrome is iron, ink, and one accent. Nothing in the frame may be a colour that could be mistaken for something
|
||||
the solve will read.
|
||||
|
||||
**The Ladder Rule.** The neutrals are ordered by depth, not by taste. A new surface picks its value by answering
|
||||
whether it sits below the panel (a well), on it (a row), or above it (a control). There is no free choice of grey.
|
||||
|
||||
## Typography
|
||||
|
||||
**Display Font:** none. This system has no display role and does not want one.
|
||||
**Body Font:** ui-monospace, with "Cascadia Mono", Menlo and Consolas behind it
|
||||
**Label/Mono Font:** the same family, at 11px and weight 600
|
||||
|
||||
**Character:** One monospace family does every job in the product, because half of what the interface shows is a
|
||||
column-aligned report and the other half is numbers that must line up under each other while you edit them. The
|
||||
result reads as instrument labelling rather than as prose: terse, evenly coloured, and impossible to mistake for
|
||||
a document. There is no font loading at all — the stack is the platform's own, which is also what keeps the tool
|
||||
a single offline binary.
|
||||
|
||||
### Hierarchy
|
||||
|
||||
- **Body** (400, 13px, 1.45): Everything the user typed or chose. Class names, button labels, input values, toast
|
||||
messages. `font: inherit` on every control, so a number in a field is the same size as the same number in a
|
||||
sentence.
|
||||
- **Data** (400, 11.5px, 1.45, `white-space: pre`): Plan reports, bake status, map-key items. Set in graphite,
|
||||
with `<b>` in cold ink for the one word that matters (`**baking**`, `**done**`).
|
||||
- **Note** (400, 11px, 1.45): Annotations under a control, in graphite. This is where the system explains itself,
|
||||
and it is a first-class role rather than a caption.
|
||||
- **Label** (600, 11px, 0.09em, uppercase): Section headings in the rail — `brush`, `this class`, `planet`,
|
||||
`bake` — and map-key titles. Uppercase and tracked at 11px so a heading reads as a divider without needing a
|
||||
rule above it. 16px of space above, 6px below; 2px above when it is first in the rail.
|
||||
|
||||
### Named Rules
|
||||
|
||||
**The Alignment Is Layout Rule.** Reports are `white-space: pre`, and their columns come from `padEnd`/`padStart`
|
||||
in the code that generates them. Never rebuild one as a table, a grid, or flex rows. The monospace font is
|
||||
structural here, and switching families would silently break every report in the product.
|
||||
|
||||
**The Lowercase Rule.** Headings are lowercase in the source and uppercased by CSS; labels and buttons are
|
||||
sentence case at most. Nothing in this interface is Title Case. The one exception is a proper noun the domain
|
||||
already capitalises.
|
||||
|
||||
## Layout
|
||||
|
||||
A two-column grid at full viewport height: a **300px fixed rail** and a fluid stage (`grid-template-columns:
|
||||
300px 1fr; height: 100%`). The rail scrolls on overflow and owns a 1px right hairline; the stage clips and holds
|
||||
the canvas at 100% × 100% with a `crosshair` cursor. There are no breakpoints and no media queries — this is a
|
||||
desktop instrument, and PRODUCT.md records that as deliberate rather than unfinished.
|
||||
|
||||
**Rail padding** is 10px on every side. Floating chrome is inset 10px from the stage edges: the message toast
|
||||
top-left at `max-width: 70%`, the cursor readout bottom-left with `pointer-events: none` so it can never
|
||||
intercept a brush stroke.
|
||||
|
||||
**Rhythm.** The spacing scale is 4 / 6 / 8 / 10 / 16px. 6px is the workhorse — the gap in a label/value row, the
|
||||
gap in a button bar, the vertical padding of a button, the space under a section heading. 4px separates tabs and
|
||||
map buttons; 8px separates a colour chip from its name; 10px is panel padding and overlay inset; 16px opens a new
|
||||
section. Two values sit off the scale and are load-bearing anyway: rows carry `margin: 3px 0` so a stack of eight
|
||||
number fields stays dense, and `<hr>` carries `margin: 14px 0 0` so a rule sits closer to what follows it than to
|
||||
what precedes it.
|
||||
|
||||
**Row grammar.** Every parameter is one `.row`: a graphite label at `flex: 1` on the left, its control on the
|
||||
right. Labels for nested parameters are indented with leading spaces in the label text itself (`" floor mm/yr"`,
|
||||
`" fraction"`), which is a monospace trick and entirely in keeping — the indent is exactly two characters
|
||||
because the font makes that a reliable measurement.
|
||||
|
||||
### Named Rules
|
||||
|
||||
**The Rail Is Fixed Rule.** 300px, never a percentage, and number inputs are 78px. A label and its value must not
|
||||
reflow when the window changes size; the canvas absorbs the entire delta. An author resizing the window is
|
||||
looking at the world, not at the panel.
|
||||
|
||||
**The Canvas Is Never Chrome Rule.** Nothing in the stage has a background, a border or a panel of its own except
|
||||
the two floating readouts, and both are translucent. The world goes edge to edge.
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
**There is no `box-shadow` in this system, and there will not be one.** Depth is carried entirely by tonal value
|
||||
and a single 1px hairline, and this is doctrine rather than an accident of the first implementation.
|
||||
|
||||
The ladder runs in both directions off the panel. Inputs and the progress track sink below it to **Well**
|
||||
(#11151a). Rows lift to **Iron Hover** (#222831) and then **Iron Live** (#252b34). Buttons sit above it at
|
||||
**Raised Iron** (#262d36). Every one of those surfaces carries the same 1px **Hairline** (#2b323b) border, so
|
||||
edges are declared rather than implied. Things that genuinely float over the canvas — the toast, the cursor
|
||||
readout — do not rise in value at all; they go *darker* than anything inline, to a translucent near-black scrim
|
||||
with the same hairline. Floating is expressed as separation from the world, not as height above it.
|
||||
|
||||
This is the right answer for this product specifically. The canvas is a data image whose values the author is
|
||||
trying to read honestly, and a drop shadow spilling onto it would imply a physical stack that does not exist. The
|
||||
one surface allowed to sit over the painting does so by dimming it, which is what a real instrument overlay does.
|
||||
|
||||
### Named Rules
|
||||
|
||||
**The No-Shadow Rule.** No `box-shadow`, no `filter: drop-shadow`, no glow. If something needs to separate, it
|
||||
changes value or gains a hairline.
|
||||
|
||||
**The Two-Direction Rule.** A surface declares its role by which way it moves off the panel: down means you type
|
||||
into it, up means you press it, level means you select it. A new surface that is the same value as the panel is
|
||||
undecided, and undecided is a bug.
|
||||
|
||||
**The Scrim Rule.** Anything floating over the canvas is darker than the panel and translucent (#0d1014dd–ee).
|
||||
It never becomes opaque and it never gets lighter, because the point of a floating readout is that you can still
|
||||
see what it is describing.
|
||||
|
||||
## Shapes
|
||||
|
||||
Three radii, each with a job. **2px** (`{rounded.sm}`) is for a gradient strip — the map-key ramp, which is
|
||||
almost a rectangle because it represents a continuous scale and a rounded end would misdescribe it. **3px**
|
||||
(`{rounded.md}`) is for small inlaid things: colour chips, number inputs, the progress track. **4px**
|
||||
(`{rounded.lg}`) is for anything you press or that can become selected: buttons, swatch rows, the floating
|
||||
readouts. Nothing in the product is more rounded than 4px and nothing is a pill.
|
||||
|
||||
Every edge is a 1px hairline. Colour chips carry a 40%-black edge (#0006) instead so the chip reads against both
|
||||
a pale class colour and a dark one. Chips are 18px in the rail and 12px in a map key — the same square at two
|
||||
scales, never a circle.
|
||||
|
||||
The one deliberately hard-edged form in the product is the brush disc, which is written straight into `ImageData`
|
||||
with no antialiasing because a blended pixel would classify as a third class. It is worth stating here as form
|
||||
language: this system does not soften an edge that carries meaning.
|
||||
|
||||
### Named Rules
|
||||
|
||||
**The Reserved Border Rule.** Anything that can become selected carries `border: 1px solid transparent` at rest,
|
||||
so selection changes colour and never geometry. Nothing in this rail is allowed to shift, grow or reflow when you
|
||||
click it.
|
||||
|
||||
**The Square Chip Rule.** A colour sample is a 3px-radius square with its own dark edge, at 18px in the rail and
|
||||
12px in a key. Never a circle, never borderless, never a swatch of the class colour used as a background behind
|
||||
text.
|
||||
|
||||
## Components
|
||||
|
||||
### Buttons
|
||||
|
||||
- **Shape:** Barely rounded plates (4px radius), 1px hairline, `padding: 6px 10px`, `font: inherit` so a button
|
||||
label is the same 13px as everything else.
|
||||
- **Default:** Raised Iron surface (#262d36), cold ink text, hairline border. Used for everything that saves,
|
||||
toggles or opens — `Save legend`, `Save painting`, `Re-roll`.
|
||||
- **Primary:** Filled brass (#d6a03a) with near-black text (#17181a) and `font-weight: 600`. There is at most one
|
||||
of these visible per group: `Plan (4 s)` in the main bar, `Bake` in the bake block.
|
||||
- **Hover:** The border alone turns brass. The surface does not change and nothing moves. Instant, no transition.
|
||||
- **Disabled:** `opacity: .5` and `cursor: default`, applied to whatever variant it already was — a disabled
|
||||
primary is a dimmed brass plate, not a grey one.
|
||||
- **Toggle (on):** Brass border *and* brass text on the unchanged Raised Iron surface. This is how tabs and map
|
||||
buttons show which one is showing. **Filled means act; outlined means live** — the distinction is the whole
|
||||
button system.
|
||||
- **Danger:** Rust border (#b4553f) and rust-light text (#f0b4a4) on Raised Iron. Exactly one exists — `Cancel`
|
||||
on a running bake — and it appears only while there is something to cancel.
|
||||
|
||||
### Swatch rows
|
||||
|
||||
The signature control of the rail, and a gauge as much as a picker. One row is: an 18px colour chip, the class
|
||||
name at `flex: 1`, and a right-aligned graphite reading that says what the class *does* — `3.4° rolling`,
|
||||
`120 m deep`, `coast pinned`. Selecting a class and reading its consequence are the same glance.
|
||||
|
||||
- **Rest:** transparent background, `border: 1px solid transparent`, `padding: 4px 6px`, 4px radius, 8px gap.
|
||||
- **Hover:** Iron Hover background (#222831). No border change.
|
||||
- **Selected:** Iron Live background (#252b34) *and* a brass border.
|
||||
- **Erase variant:** the chip becomes a 45° hatch (`repeating-linear-gradient(45deg, #3a424c 0 4px, #232931
|
||||
4px 8px)`). Absence is drawn, never left blank — a blank chip would read as a colour.
|
||||
|
||||
### Inputs / Fields
|
||||
|
||||
- **Number:** Well background (#11151a), cold ink text, hairline border, 3px radius, `padding: 2px 5px`, fixed
|
||||
78px width. Recessed against the panel, which is how you can tell at a glance which things in the rail accept
|
||||
a value.
|
||||
- **Range:** the native control at `width: 100%`, unstyled. Used once, for brush size, directly under its own
|
||||
readout.
|
||||
- **Checkbox:** native, right-aligned in its row like any other control.
|
||||
- **Focus:** *not currently styled.* The browser default is doing this job, which is the one hole in the hairline
|
||||
system — see Do's and Don'ts.
|
||||
|
||||
### Navigation
|
||||
|
||||
Two full-width tabs at the top of the rail (`flex: 1` each, 4px gap, `padding: 4px 6px`) switching the brush
|
||||
between the class painting and the overlay. The active tab uses the toggle-on treatment — brass border, brass
|
||||
text, `font-weight: 600`. A tab that cannot apply (a planet with no overlay legend) is `disabled` rather than
|
||||
hidden, and carries a `title` explaining what would enable it. Duplicated on the `o` key.
|
||||
|
||||
### Message toast
|
||||
|
||||
Floating at the stage's top-left, 10px inset, Scrim background (#0d1014ee), hairline border, 4px radius,
|
||||
`padding: 6px 9px`, `max-width: 70%`. Three states: neutral (hairline border, cold ink), **error** (rust border,
|
||||
rust-light text) and **ok** (verdigris border, verdigris-light text). Success auto-dismisses after 4 seconds and
|
||||
only if the message is still the one that was posted; errors stay until replaced. Preserves newlines, because
|
||||
this is where multi-line guidance appears — including the `file://` rescue message that explains why every
|
||||
request failed.
|
||||
|
||||
### Cursor readout
|
||||
|
||||
Bottom-left, 10px inset, Scrim HUD (#0d1014dd), graphite, `white-space: pre`, `pointer-events: none`. Three
|
||||
facts, continuously: pixel position and the same position in kilometres east, then zoom percentage and the
|
||||
current brush name. The one piece of chrome that never waits to be asked.
|
||||
|
||||
### Bake progress
|
||||
|
||||
A 6px Well track (#11151a, 3px radius, `overflow: hidden`) with a brass fill whose width carries
|
||||
`transition: width .3s` — **the only animation in the product**. Below it, the status block in Data type with the
|
||||
state word bolded to cold ink, then the last few landed regions and a dimmed tail of the last four log lines at
|
||||
`opacity: .65`.
|
||||
|
||||
### Map key (signature)
|
||||
|
||||
A key is published with every map view and generated by the code that drew that map. Two shapes: a **ramp** (12px
|
||||
gradient strip, 2px radius, chip-edge border, with its two end values in graphite beneath at `space-between`) for
|
||||
continuous fields, and a **two-column grid** (`gap: 1px 8px`) of 12px chips with names for categorical ones.
|
||||
Under either, a `note` paragraph in graphite explaining what the map means and what it does *not* mean.
|
||||
|
||||
### Monospace report (signature)
|
||||
|
||||
A `white-space: pre` block in Data type, graphite, column-aligned by `padEnd`/`padStart` at generation time. It
|
||||
mixes a table, warnings and prose in one flow — a seam warning, a per-class share table, the fault and lithology
|
||||
summary, an overlay tally, a region estimate. Its density is the point: a plan report is the four-second answer
|
||||
the whole product is built around, and it is meant to be read whole rather than scanned.
|
||||
|
||||
## Do's and Don'ts
|
||||
|
||||
### Do:
|
||||
|
||||
- **Do** use filled brass for the one action in a group and outlined brass for the one item that is live. Never
|
||||
both in the same role.
|
||||
- **Do** reserve `border: 1px solid transparent` on anything selectable, so selection never changes geometry.
|
||||
- **Do** put an 11px graphite `note` under any control whose raw value has no obvious consequence, and write it
|
||||
to say *why*. The note is part of the control.
|
||||
- **Do** report a number back in the unit the author thinks in — degrees, metres, kilometres, minutes — beside
|
||||
the field that takes it.
|
||||
- **Do** publish a key with every map, generated by the code that drew the map, so the two cannot drift apart.
|
||||
- **Do** pick a new surface's value off the ladder by asking whether it sinks, sits or rises relative to the
|
||||
panel (#11151a / #1b2027 / #262d36), and give it the 1px hairline.
|
||||
- **Do** keep reports in `white-space: pre` with their columns padded in code.
|
||||
- **Do** disable a control that cannot apply and give it a `title` saying what would enable it, rather than
|
||||
hiding it.
|
||||
|
||||
### Don't:
|
||||
|
||||
- **Don't** add a `box-shadow`, a glow or a `drop-shadow` anywhere, at any elevation.
|
||||
- **Don't** add a transition to a state change. Hover and selection are instant. The only animation in this
|
||||
system is the bake progress width (`.3s`), and it earns that because it measures a two-hour process.
|
||||
- **Don't** introduce a second font family or a fourth type size. 13px / 11.5px / 11px in one monospace stack is
|
||||
the entire scale, and a family change would break every column-aligned report.
|
||||
- **Don't** put a hue in the chrome. Colour in this product means an uplift rate, a depth, a rock type or a
|
||||
region; a decorative hue would be indistinguishable from one of those.
|
||||
- **Don't** use brass on anything that is neither actionable nor live — not on a heading, not on a value, not to
|
||||
emphasise a word in a note.
|
||||
- **Don't** let a control change size, padding or position between states.
|
||||
- **Don't** round anything past 4px, and don't make a colour sample a circle.
|
||||
- **Don't** leave a control with only the browser's default focus ring. Number inputs currently do, and it is the
|
||||
one gap in the hairline system: a keyboard user gets a focus treatment this design never specified.
|
||||
- **Don't** ship a second letter-spacing for the label role. The map-key title is at `0.08em` against the section
|
||||
heading's `0.09em`; that is drift, and `0.09em` is the value.
|
||||
Reference in New Issue
Block a user