1. Design personality
The interface should feel precise, fast, scientific, and composed.
It should not feel chatty, gamified, noisy, or overly decorative.
2. Visual hierarchy
Primary task line
The main operation currently underway.
⠸ Building spatial index 12.4M / 97.2M rows 00:41 elapsed
Progress task line
Use only when the denominator is known.
▰▰▰▰▰▰▱▱▱▱ 62% Crossmatching partitions 18,432 / 29,716
Secondary detail line
Current partition, worker, cache status, or local detail.
hpix=12481 rows=83,204 cache=warm worker=07
Completed task line
Compact, aligned, and stable.
✓ Built spatial index 97.2M rows in 02:18 ✓ Crossmatched catalogs 14.8M matches, 3.2GB written
3. Status symbols
Use a small, consistent symbol grammar. Do not assign a unique glyph to every concept.
| State | Unicode | ASCII fallback | Meaning |
|---|---|---|---|
| Running | ⠋ | * | Active indeterminate work |
| Progress complete segment | ▰ | # | Completed fraction |
| Progress remaining segment | ▱ | - | Remaining fraction |
| Success | ✓ | OK | Completed successfully |
| Warning | ! | ! | Recoverable issue or degraded mode |
| Error | ✗ | X | Failure |
| Transition | → | -> | Next action, output path, or movement |
| Detail | · | - | Sub-item or quiet detail |
4. Color semantics
Use color semantically, not decoratively. The output must still be understandable in monochrome.
| Role | Use |
|---|---|
| Default text | Ordinary information |
| Dim text | Secondary details, paths, debug-adjacent context |
| Green | Success |
| Yellow / amber | Warning, fallback, degraded mode |
| Red | Error |
| Blue / cyan | Active operation, object names, paths |
Good
✓ Wrote results /data/run42/xmatch.parquet ! Missing metadata assuming epoch=J2000 ✗ Schema mismatch column "ra" is float32, expected float64
Avoid
🌈✨ DONE!!! ✨🌈
5. Layout and spacing
Use alignment to make repeated output scannable.
✓ Read objects.parquet 104.2M rows 8.4 GB ✓ Read sources.parquet 97.8M rows 7.9 GB ✓ Wrote matches.parquet 14.8M rows 1.2 GB
Recommended column order
[state] [verb] [object] [quantity] [rate/time/detail]
Example
✓ Indexed gaia-dr3 1.82B rows 11m42s ✓ Cached margin tiles 19.4M rows 4.1GB ✓ Wrote xmatch.parquet 87.2M rows 2m08s
6. Spinners
A spinner means: work is happening, but the fraction complete is not known.
Recommended spinner
⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏
ASCII fallback
- \ | /
Good spinner use
⠦ Opening dataset metadata ⠏ Planning query ⠴ Waiting for workers
With details
⠸ Planning query 14 tables, 3 XMATCH joins ⠸ Building index 00:18 elapsed
Rule
Do not show a fake ETA for indeterminate work. If the denominator exists, use a progress bar.
7. Progress bars
Use progress bars only when the denominator is known.
Preferred compact style
▰▰▰▰▰▰▱▱▱▱ 62% Crossmatching partitions 18,432 / 29,716
ASCII fallback
[######----] 62% Crossmatching partitions 18,432 / 29,716
Wide terminal
Crossmatching partitions ▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱ 62% 18,432/29,716 41k rows/s
Narrow terminal
▰▰▰▰▰▰▱▱▱▱ 62% Crossmatching
Progress fields
[label] [bar] [percent] [count] [rate] [eta]
8. Multi-level progress
For nested work, show one primary progress indicator and one changing detail line. Avoid one bar per worker.
Crossmatching ▰▰▰▰▰▰▱▱▱▱ 62% 18,432/29,716 partitions current: hpix=12481 rows L/R=83,204/71,992 cache=warm worker=07
Pipeline form
✓ Read catalogs ✓ Build margin cache ⠸ Crossmatch partitions ▰▰▰▰▰▰▱▱▱▱ 62% 18,432/29,716 · Write output · Validate result
Completed form
✓ Read catalogs ✓ Build margin cache ✓ Crossmatch partitions 14.8M matches ✓ Write output /data/run42/xmatch.parquet ✓ Validate result no duplicate left rows
9. Interactive UI versus logs
Interactive TTY mode
Use spinners, progress bars, line updates, color, and compact status.
⠸ Crossmatching partitions 18,432 / 29,716
Non-TTY / log mode
No animation. Emit durable, parseable events.
[2026-06-11 09:41:02] INFO started crossmatching partitions total=29716 [2026-06-11 09:41:42] INFO progress crossmatching done=18432 total=29716 rate=128/s [2026-06-11 09:43:10] INFO finished crossmatching matches=14802391 elapsed=128.4s
10. Verbosity levels
Quiet
✓ Wrote /data/run42/xmatch.parquet
Normal
✓ Loaded catalogs Crossmatching ▰▰▰▰▰▰▱▱▱▱ 62% 18,432/29,716 ✓ Wrote /data/run42/xmatch.parquet
Verbose
✓ Loaded left catalog 104.2M rows ✓ Loaded right catalog 97.8M rows ✓ Using HEALPix order 12 ✓ Match radius 1.0 arcsec ✓ Margin cache warm, 19.4M rows Crossmatching ▰▰▰▰▰▰▱▱▱▱ 62% 18,432/29,716 128/s
11. Message style
Use short, direct technical phrases.
Prefer
Building spatial index Reading Parquet metadata Crossmatching partitions Writing result catalog Validating row counts
Avoid
Please wait while we build your spatial index... Now doing a crossmatch, this could take a while... Almost there...
12. Units and formatting
Use compact engineering-style formatting during progress, and exact counts in summaries when needed.
1,204 rows 83,204 rows 14.8M rows 1.82B rows 842 MB 7.3 GB 128/s 41k rows/s 02:18
Scientific parameters
radius=1.0 arcsec area=9.6 deg² order=12 hpix=1849231 epoch=J2000
13. Error design
Errors should explain the failed object, reason, and next action.
✗ Crossmatch failed reason: schema mismatch column: ra found: float32 expected: float64 Fix the schema or pass --ra-column explicitly.
14. Recommended ACID-style run
▣ ▣ ▣ ACID ▣ ▢ ▣ Astronomical Catalog Inference Driver ▣ ▣ ▣ ✓ Loaded registry 4 catalogs ✓ Planned query 3 joins, 1 XMATCH ✓ Opened left catalog 104.2M rows ✓ Opened right catalog 97.8M rows ✓ Prepared margin cache 19.4M rows Crossmatching ▰▰▰▰▰▰▱▱▱▱ 62% 18,432/29,716 partitions 128/s ETA 01:28 hpix=12481 L=83,204 R=71,992 cache=warm worker=07
Final output
✓ Crossmatched catalogs 14.8M matches ✓ Wrote result catalog /data/run42/xmatch.parquet ✓ Validated output no duplicate left rows Summary elapsed: 02:18 throughput: 706k rows/s output size: 1.2 GB
15. Style guide rules
16. Default implementation constants
Symbols: running ⠋ success ✓ warning ! error ✗ progress ▰▱ Progress: ▰▰▰▰▰▰▱▱▱▱ 62% label done/total rate ETA Layout: [state] [verb/object aligned to ~28 chars] [main metric] [secondary metric] Tone: concise technical verbs, no chatter Modes: --quiet default interactive --verbose --debug --no-color --plain / auto for non-TTY