machud 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +314 -0
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/machud.mjs +1859 -0
- package/package.json +54 -8
- package/index.js +0 -1
package/DESIGN.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
---
|
|
2
|
+
# machud DESIGN.md — the visual identity, as a hands-off anchor.
|
|
3
|
+
# Format inspired by google-labs-code/design.md, adapted for a terminal (TUI):
|
|
4
|
+
# machine-readable tokens up top, human rationale below. This file is the thing the
|
|
5
|
+
# autonomous loop optimizes visual choices AGAINST. It is a product decision, not a
|
|
6
|
+
# preference — see CONTRIBUTING.md and .agents/docs/decisions.md (D9).
|
|
7
|
+
#
|
|
8
|
+
# STATUS: most of this is TARGET, not yet shipped. The code does NOT implement it yet
|
|
9
|
+
# (src/theme.ts is still Tokyo Night; the layout is still the flat 3-row grid). Build
|
|
10
|
+
# toward this via the staged RD0–RD5 backlog. Do NOT treat an unbuilt section here as a
|
|
11
|
+
# passing invariant — a "panel renders" grep is not "matches DESIGN.md". Each section is
|
|
12
|
+
# tagged (TARGET) or (SHIPPED).
|
|
13
|
+
meta:
|
|
14
|
+
name: machud
|
|
15
|
+
mood: "cool but refined — a calm, green-forward instrument; striking, never harsh"
|
|
16
|
+
basis: "Everforest — a low-strain, muted, eye-friendly scheme; green-forward, using Everforest's own green"
|
|
17
|
+
appearance: "follows macOS system light/dark automatically (D8); no user theme switch"
|
|
18
|
+
|
|
19
|
+
# --- COLORS (TARGET) — the source of truth. src/theme.ts MUST be rewritten to these
|
|
20
|
+
# tokens (it is still Tokyo Night today — backlog RD1); verify.mjs pins the hex so
|
|
21
|
+
# doc and code can never silently desync again. ---
|
|
22
|
+
colors:
|
|
23
|
+
dark:
|
|
24
|
+
bg: "#2d353b" # soft black, never #000
|
|
25
|
+
bg_lift: "#343f44" # one step up = panel depth
|
|
26
|
+
frame: "#4f5b58" # muted border
|
|
27
|
+
title: "#d3c6aa" # warm off-white, never #fff
|
|
28
|
+
text: "#9da9a0"
|
|
29
|
+
dim: "#7a8478" # labels, tracks (Everforest grey0; was a #5c6a72 typo — Q2, owner-ruled)
|
|
30
|
+
accent: "#a7c080" # PRIMARY accent — Everforest's own green
|
|
31
|
+
silver: "#c4c9cf" # Apple aluminium — the "mac" half of the mac|hud wordmark [VOUCHED @hyf0, D15]
|
|
32
|
+
module:
|
|
33
|
+
cpu: "#a7c080" # green (hero)
|
|
34
|
+
mem: "#d699b6" # purple
|
|
35
|
+
gpu: "#7fbbb3" # blue
|
|
36
|
+
disk: "#dbbc7f" # yellow
|
|
37
|
+
net: "#83c092" # aqua
|
|
38
|
+
battery: "#e69875" # orange
|
|
39
|
+
sensor: "#e67e80" # red
|
|
40
|
+
status:
|
|
41
|
+
good: "#a7c080"
|
|
42
|
+
warn: "#dbbc7f"
|
|
43
|
+
bad: "#e67e80"
|
|
44
|
+
light:
|
|
45
|
+
bg: "#fdf6e3"
|
|
46
|
+
bg_lift: "#f4f0d9"
|
|
47
|
+
frame: "#ddd8be"
|
|
48
|
+
title: "#5c6a72"
|
|
49
|
+
text: "#5c6a72"
|
|
50
|
+
dim: "#939f91"
|
|
51
|
+
accent: "#8da101"
|
|
52
|
+
silver: "#8d939a" # Apple aluminium — "mac" half of the mac|hud wordmark [VOUCHED @hyf0, D15]
|
|
53
|
+
module:
|
|
54
|
+
cpu: "#8da101"
|
|
55
|
+
mem: "#df69ba"
|
|
56
|
+
gpu: "#3a94c5"
|
|
57
|
+
disk: "#dfa000"
|
|
58
|
+
net: "#35a77c"
|
|
59
|
+
battery: "#f57d26"
|
|
60
|
+
sensor: "#f85552"
|
|
61
|
+
status:
|
|
62
|
+
good: "#8da101"
|
|
63
|
+
warn: "#dfa000"
|
|
64
|
+
bad: "#f85552"
|
|
65
|
+
|
|
66
|
+
color_tier: # D11 — truecolor is an ENHANCEMENT, not a guarantee
|
|
67
|
+
truecolor: "full same-hue luminance gradients (24-bit)"
|
|
68
|
+
ansi256: "drop gradients to a single solid accent (degrade like light mode)"
|
|
69
|
+
ansi16: "prefer muted NAMED ansi; never let arbitrary hex snap to saturated basic colors"
|
|
70
|
+
detect: "chalk level at startup; macOS Terminal.app (the OS default) is 256-color, no truecolor"
|
|
71
|
+
|
|
72
|
+
# --- GLYPHS (a terminal's "typography": fixed-width, so the character IS the type) ---
|
|
73
|
+
glyphs:
|
|
74
|
+
border: "round ╭ ╮ ╰ ╯ │ ─" # round = calm; never heavy/double as default
|
|
75
|
+
bar_fill: "█"
|
|
76
|
+
bar_track: "─" # dim, low-contrast
|
|
77
|
+
graph: "braille ⠀-⣿ area chart, 2×4 subpixels per cell"
|
|
78
|
+
big_digit: "5-row block figures for the one hero number per panel"
|
|
79
|
+
spark: "▁▂▃▄▅▆▇█"
|
|
80
|
+
sep: "·"
|
|
81
|
+
charge: "⇡ charging · ⇣ discharging" # width-1, NOT the ⚡ emoji (double-width)
|
|
82
|
+
absent: "—" # honest placeholder for sudo-only / unavailable
|
|
83
|
+
|
|
84
|
+
# --- SPACE & WEIGHT ---
|
|
85
|
+
space:
|
|
86
|
+
layout: "(TARGET) wide curated default = 3-tier hierarchy; + ONE narrow/watch-face fallback (responsive, D4 reopened). NOT the old flat 3-row grid; NOT a 5-breakpoint ladder."
|
|
87
|
+
gutter: 1 # 1 cell padding inside every panel border
|
|
88
|
+
panel_gap: 1
|
|
89
|
+
bar_align: "within a panel, ALL bars share one label-column width + one bar width; left edges, bar ends, and value columns form clean vertical rules. Guaranteed in the WIDE layout where bars render (not at watch-face XS)."
|
|
90
|
+
weight:
|
|
91
|
+
hierarchy: "size > position > weight > color — primary metric is BIG + top-left + accent"
|
|
92
|
+
gradients: "meters & graphs use SAME-HUE luminance ramps (no complementary hue clash)"
|
|
93
|
+
|
|
94
|
+
# --- COMPONENTS ---
|
|
95
|
+
components:
|
|
96
|
+
Panel: { border: frame, title: title, body: bg }
|
|
97
|
+
BigNumber: { color: "module accent, gentle 2-tone same-hue gradient" }
|
|
98
|
+
Meter: { fill: "module accent → warn/bad as value enters danger (levelColor)", track: dim }
|
|
99
|
+
Sparkline: { ramp: "module accent luminance" }
|
|
100
|
+
Graph: { type: braille_area, ramp: "same-hue luminance, dim bottom → accent top" }
|
|
101
|
+
Status: { color: "good/warn/bad", escalation: "intensity + bar bleeds to warn/bad + a text label where it helps" }
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
# machud — Visual Identity
|
|
105
|
+
|
|
106
|
+
What machud should look and feel like, written down so it can be built and judged
|
|
107
|
+
**without re-litigating taste every time.** Correctness is machine-checked by `pnpm verify`;
|
|
108
|
+
this document is the anchor for the part a gate can't fully check — the *beautiful* in
|
|
109
|
+
"beautiful, zero-config." Changing anything here is a [VOUCHED]-level decision: ship nothing
|
|
110
|
+
that contradicts this file without the owner's say-so.
|
|
111
|
+
|
|
112
|
+
> **This is a TARGET.** The current code has not implemented it (theme.ts is Tokyo Night; the
|
|
113
|
+
> layout is the old flat 3-row grid). The loop builds toward it via the staged RD0–RD5 backlog,
|
|
114
|
+
> safety-net first. Until a section is shipped, do not treat its prose as a passing invariant.
|
|
115
|
+
|
|
116
|
+
## Overview — the one-line thesis
|
|
117
|
+
|
|
118
|
+
**A calm, green-forward instrument that is cool, not loud.** machud takes over the terminal
|
|
119
|
+
like btop, but its visual language is *refined maximalism*: rich, alive, and striking —
|
|
120
|
+
through gradient meters, high-resolution braille graphs, and big hero numbers — yet **muted,
|
|
121
|
+
low-contrast, and easy on the eyes**. Cool is the goal; harsh is the failure mode.
|
|
122
|
+
|
|
123
|
+
**Drama comes from FORM, never from saturation.** When a frame feels flat, add data density,
|
|
124
|
+
hierarchy, or resolution — *never* raise chroma or contrast. machud's identity is its
|
|
125
|
+
**composition** (hero block number + gradient meter + braille graph + P/E grid), not its
|
|
126
|
+
palette; Everforest is a proven low-strain base, not a brand statement.
|
|
127
|
+
|
|
128
|
+
The seven principles are the whole spec in miniature.
|
|
129
|
+
|
|
130
|
+
1. **Glanceable.** Every panel answers its core question in under a second — one hero metric,
|
|
131
|
+
BIG, top-left, in a preattentive channel (size + position + accent). *(Few, "5-second rule";
|
|
132
|
+
Ware, preattentive processing.)*
|
|
133
|
+
2. **Color = identity + state, on DIFFERENT channels.** Hue marks *which module*. **Status is
|
|
134
|
+
carried by colour + intensity** (good/warn/bad green/amber/red; a bar bleeding toward warn-red),
|
|
135
|
+
plus a text label where it helps (e.g. disk "FULL"). **No accessibility / colour-independence
|
|
136
|
+
layer** — machud is a passive full-screen TUI (not screen-reader territory), and the owner ruled
|
|
137
|
+
a11y out of scope (D14). *(Few; Ware, preattentive attributes.)*
|
|
138
|
+
3. **Cool by default, dramatic on alarm.** Baseline is already handsome (Everforest muted +
|
|
139
|
+
gradient meters + braille graphs + easing on value change). Healthy = quiet. Only an
|
|
140
|
+
**event** (near-full, thermal, on-battery) earns escalation: brightness, the bar bleeding to
|
|
141
|
+
warn/bad, and — only here — motion. **Motion is alarm/transition-only, never
|
|
142
|
+
a routine-state carrier** (and it is invisible to a single-frame gate, so it is not a
|
|
143
|
+
load-bearing accessibility channel). *(Weiser, Calm Technology; Tufte, "smallest effective difference".)*
|
|
144
|
+
4. **Space by value.** Real estate ∝ worth, not democratic. **CPU and Memory get the most room
|
|
145
|
+
(tier-1 hero); Network leads the medium tier; Disk and Sensors compress into a status strip.**
|
|
146
|
+
*(Few.)*
|
|
147
|
+
5. **Small multiples + sparklines.** Per-core load is a P/E-grouped grid the eye compares at a
|
|
148
|
+
glance; history is a braille area graph. Maximize data-ink; delete chartjunk. *(Tufte.)*
|
|
149
|
+
6. **Consistency.** Every panel's hero number lives in the same spot, same weight ramp; panels
|
|
150
|
+
and bars align. Same things look the same. *(Gestalt: similarity, alignment.)*
|
|
151
|
+
8. **Stable & dense (owner feedback 2026-06-20).** A panel's **row structure is FIXED** — an
|
|
152
|
+
optional value fills its slot with `—`/`on AC`, it never appears/disappears (a value popping in
|
|
153
|
+
or out must NOT change a panel's height or shift the row below it). Numeric columns **right-align
|
|
154
|
+
to a fixed width** so a value's length never moves the column. And a large/hero panel must **earn
|
|
155
|
+
its space with real, dynamic, comparative data** (history graphs, per-core grids, breakdowns) — a
|
|
156
|
+
big box holding three numbers is a failure, not minimalism.
|
|
157
|
+
7. **Mac-native, honest data.** Show the zero-sudo Apple-Silicon signals others can't (P/E
|
|
158
|
+
cores, adapter PD wattage, memory pressure, thermal pressure). What needs `sudo` is `—`,
|
|
159
|
+
never faked, never prompted. *(Tufte "show the data"; decisions D2/D3.)*
|
|
160
|
+
|
|
161
|
+
## Colors
|
|
162
|
+
|
|
163
|
+
The palette is **Everforest** — muted, low-contrast, eye-strain-conscious. The **primary accent
|
|
164
|
+
is Everforest's own green (`#a7c080`)**; green-forward is the identity. (A nice fit for a
|
|
165
|
+
vue-tui project, but the color is Everforest's, not bent to match Vue.) The `colors` tokens
|
|
166
|
+
above are the source of truth; **`src/theme.ts` must be rewritten to mirror them (it is still
|
|
167
|
+
Tokyo Night — RD1)**, and verify.mjs pins the hex so they can't silently diverge.
|
|
168
|
+
|
|
169
|
+
Rules (*Refactoring UI*, Few, Tufte's *smallest effective difference*):
|
|
170
|
+
- **Never pure black or pure white.** Base `#2d353b`, text warm off-white.
|
|
171
|
+
- **Per-module hue is confined to small ink** — the panel's title / border / hero number only.
|
|
172
|
+
Panel **bodies** (bars, tracks, secondary text) stay neutral grey + the shared green accent,
|
|
173
|
+
so **green is the only hue across panels** and the 7 module hues never become a rainbow. The
|
|
174
|
+
"loud 10%" of 60-30-10 is this per-panel accent, nothing more.
|
|
175
|
+
- **Low contrast on purpose.** Use the *weakest* distinction that still reads.
|
|
176
|
+
- **No high-saturation complementary pairs on dark** (they vibrate — chromostereopsis). Gradients
|
|
177
|
+
ramp within one hue's luminance.
|
|
178
|
+
- **Truecolor is an ENHANCEMENT, not a guarantee (D11).** The gradient look needs 24-bit color;
|
|
179
|
+
macOS's default Terminal.app is 256-color. Detect chalk level and degrade: 256 → solid accent
|
|
180
|
+
(no gradient), 16 → muted named ANSI. Never let a muted hex snap to a saturated basic color
|
|
181
|
+
(the neon the Don'ts forbid). Judge "cool but refined" through the real chalk path at level 2/1,
|
|
182
|
+
not the raw-truecolor prototype.
|
|
183
|
+
- **Light/dark follows macOS** automatically (D8); no theme switch (D1). Light is a **faithful,
|
|
184
|
+
lower-drama daylight mode**: gradients compress, it cannot glow, and that is acceptable by
|
|
185
|
+
physics — but hero, alignment, and status colours must read as **deliberate** on the cream base.
|
|
186
|
+
Light is not a downgrade; it has the same quality bar minus glow.
|
|
187
|
+
|
|
188
|
+
## Glyphs & weight (the terminal's typography)
|
|
189
|
+
|
|
190
|
+
A fixed-width grid has no fonts, so the **character set and ANSI weight are the typography.**
|
|
191
|
+
- **Round borders** (`╭─╮`) — calm; heavy/double frames read as loud, not the default.
|
|
192
|
+
- **Hierarchy by size → position → weight → color.** Hero number is a 5-row block figure;
|
|
193
|
+
secondary values are normal weight and `dim`.
|
|
194
|
+
- **Gradients are same-hue luminance ramps** — gentle, never a hue clash.
|
|
195
|
+
- **`⇡ / ⇣`** for charge direction (width-1; **never `⚡`**, a double-width emoji that breaks
|
|
196
|
+
alignment and tofus on glyph-poor terminals). **`—`** = unavailable.
|
|
197
|
+
|
|
198
|
+
## Layout (SHIPPED — RD4)
|
|
199
|
+
|
|
200
|
+
A **single curated wide layout** (D1: no config, no focus/expand) arranged as a **3-tier
|
|
201
|
+
hierarchy** — important up top, minor compressed below:
|
|
202
|
+
|
|
203
|
+
- **Tier 1 — hero (big, with history graph):** **CPU**, **Memory**.
|
|
204
|
+
- **Tier 2 — medium:** **Network** (lead — owner-ranked above battery), **Battery**, **GPU**.
|
|
205
|
+
Ordered so **GPU** (with its history graph) fills the aligned right-hand column while **Battery**
|
|
206
|
+
stays compact in the middle — a wide-but-empty Battery was the alternative. Battery is here, NOT in
|
|
207
|
+
tier-1: its differentiation is its **data** (live PD wattage), not its real estate.
|
|
208
|
+
- **Tier 3 — status strip (compact, one line):** **Disk**, **Sensors**, uptime, load.
|
|
209
|
+
|
|
210
|
+
- **1-cell gutter** inside every panel; **1-cell gap** between panels.
|
|
211
|
+
- **Cross-tier alignment:** all three tiers share one **~60% vertical divider** — the right-hand panels
|
|
212
|
+
(MEM / GPU / SENSORS) left-align to the same column, and the left panels (CPU / Network / Disk) share
|
|
213
|
+
the left edge. Achieved with `flexBasis:0` + tuned flexGrow ratios so content can't bloat a column;
|
|
214
|
+
**pinned by a verify assertion** (right-edge cols within 2) so it can't silently regress. The lone
|
|
215
|
+
exception is tier-2's inner Network|Battery seam (3 panels vs 2 — unavoidable).
|
|
216
|
+
- **Alignment is non-negotiable** (in the wide layout, where bars render): every bar in a panel
|
|
217
|
+
shares **one** label-column width and **one** bar width, so left edges, bar ends, and value
|
|
218
|
+
columns form clean vertical rules. Pad labels to a fixed column; never let a label's length
|
|
219
|
+
decide where its bar starts. (Machine-checked by verify.mjs RD0b.)
|
|
220
|
+
- **Depth from value, not borders alone** — a lifted panel background (`bg_lift`) + a dim frame
|
|
221
|
+
separate a panel from the field without shouting.
|
|
222
|
+
|
|
223
|
+
## Responsive (TARGET — last to build, D4 reopened by @hyf0)
|
|
224
|
+
|
|
225
|
+
**Scoped to TWO tiers**, not a 5-breakpoint ladder (that is a scope bomb for an unattended loop):
|
|
226
|
+
- **Wide** (default): the full 3-tier hierarchy above.
|
|
227
|
+
- **Narrow / watch-face:** a single-column fallback; at the smallest size, just the hero numbers
|
|
228
|
+
(CPU% / MEM% / BAT%). The hierarchy IS the degradation order — the least-important tier drops
|
|
229
|
+
first, hero last. *(Marcotte responsive grids; Wroblewski mobile-first; Walton content choreography.)*
|
|
230
|
+
- **Auto-adapt to viewport, like D8 adapts to appearance** — not user config, still zero-config (D1).
|
|
231
|
+
- **Width-seam caveat:** `useWindowSize()` is reactive (reads `stdout.columns`, then a
|
|
232
|
+
terminal-size probe, falling back to 80 only as a last resort), and `App.vue` already binds it as the width. The catch is the
|
|
233
|
+
`--once`/verify path has no TTY width, so the gate drives width via `COLUMNS` →
|
|
234
|
+
`renderToString({columns})` (main.ts already does this). RD5 must make the responsive `v-if` read
|
|
235
|
+
that **same** width (thread `columns` as a prop), so the breakpoint asserted at COLUMNS=40/120 is
|
|
236
|
+
the one the code branches on.
|
|
237
|
+
- **What the gate must assert (RD0b):** widest visible line ≤ COLUMNS at each width (catches the
|
|
238
|
+
existing wide layout already overflowing to ~72 at COLUMNS=60); hero present at wide / absent
|
|
239
|
+
at watch-face (proves the seam works); alignment holds where bars render.
|
|
240
|
+
|
|
241
|
+
## Per-module specification (TARGET)
|
|
242
|
+
|
|
243
|
+
- **CPU — tier-1 hero (the showpiece — must be DENSE, not boring).** Fill the hero space with: the
|
|
244
|
+
**`BigNumber` overall %**; a **tall braille area history graph** (flowing, the btop look); the
|
|
245
|
+
**per-core grid** — each of the 12 cores its own mini-bar, **P and E clusters grouped + labelled,
|
|
246
|
+
coloured by load** (the small-multiples + the per-core data); **per-cluster averages**; and a
|
|
247
|
+
supporting line (top CPU process / load avg). **Apple-Silicon only** for the P/E split: detect
|
|
248
|
+
cluster count via `hw.nperflevels` (Intel = 1) — `cpu.ts` reads `hw.perflevel0/1.logicalcpu` and
|
|
249
|
+
treats a missing `perflevel1` as `eCount=0`; on a single cluster render ONE unlabelled cluster,
|
|
250
|
+
never `0P+0E` or all-P. Frequency needs `sudo` → `—`. (Two short bars + a number in a big box is
|
|
251
|
+
the failure mode Principle 8 forbids.)
|
|
252
|
+
|
|
253
|
+
**Same lens for the others (owner: 举一反三):** MEM → a wired/compressed/app/cache **breakdown bar**
|
|
254
|
+
+ history graph + a fixed-height top-process list; GPU → util + a **history graph** (half-empty
|
|
255
|
+
today); DISK → R/W **I/O history** sparkline; BATTERY → the `power` row **always present** (`—`/`on
|
|
256
|
+
AC` off-discharge — this fixes the height jump) + optional charge history; SENSORS → compress (sudo
|
|
257
|
+
took its content) or add a thermal trend. Every panel: fixed rows, fixed-width numeric columns.
|
|
258
|
+
- **MEM — tier-1 hero.** Used % + swap, **plus the real macOS memory-pressure level** from
|
|
259
|
+
`sysctl kern.memorystatus_vm_pressure_level` (1→Normal / 2→Elevated / 4→High) — the Mac-native
|
|
260
|
+
truth Activity Monitor leads with. (The current usedPct heuristic is only a fallback when the
|
|
261
|
+
sysctl is empty.) Top processes by RSS as support.
|
|
262
|
+
- **NETWORK — tier-2 lead.** Adaptive human units (B/KB/MB/GB·s); ▼ down / ▲ up rates with
|
|
263
|
+
sparklines; interface name. **No IP address** — recorded waiver (D12): a LAN IP is low-value
|
|
264
|
+
*and* leaks in the screenshots machud is built to be; show interface + rates instead.
|
|
265
|
+
- **GPU — tier-2.** Utilization % + VRAM + sparkline.
|
|
266
|
+
- **BATTERY — tier-2 (Mac-exclusive data highlight).** Charge % + `⇡/⇣` charge-state glyph +
|
|
267
|
+
health % + cycles. The differentiator: **adapter max wattage, detected LIVE, never hardcoded**
|
|
268
|
+
(`AdapterDetails.Watts`; varies by cable; show only when `ExternalConnected`, else `—`) **+
|
|
269
|
+
real-time charge power** = `Voltage(mV) × Amperage(mA) / 1e6` W. **Unsigned-int trap:** ioreg
|
|
270
|
+
returns `Amperage` as an **unsigned 64-bit** value, so reinterpret as signed
|
|
271
|
+
(`a = raw >= 2**63 ? raw - 2**64 : raw`) **before** the sign test — only then `a < 0` =
|
|
272
|
+
discharging. (`battery.ts`'s `(-?\d+)` parse does NOT handle this — **RD2** fixes it and injects
|
|
273
|
+
the wraparound value e.g. `18446744073709551179` = −437 mA, via RD0c's injection mechanism, so the
|
|
274
|
+
gate proves the reinterpretation.)
|
|
275
|
+
When `|a| ≈ 0` while charged, show **"charged"**, not "0W". This is battery
|
|
276
|
+
charge wattage, NOT total system draw (that needs `sudo` → omitted). Verify can't see
|
|
277
|
+
on-battery/charging transitions on one host → fixture-tested in **RD2** (via RD0c's mechanism) + manual review of the sign path.
|
|
278
|
+
- **DISK — tier-3 strip.** Used % + free, compact. A **state signifier** that is *earned*:
|
|
279
|
+
neutral when roomy; `levelColor`-driven bar + a `NEAR FULL`/`FULL` text token at ≥85% / ≥95%.
|
|
280
|
+
(Today DiskPanel hardcodes the disk hue and wires no levelColor — RD3 fix.)
|
|
281
|
+
- **SENSORS — tier-3 strip.** `pmset` thermal pressure (coloured good/warn/bad by severity) +
|
|
282
|
+
battery pack temp. Die temps / fan RPM need `sudo` → `—`.
|
|
283
|
+
|
|
284
|
+
## Do's & Don'ts
|
|
285
|
+
|
|
286
|
+
**Do**
|
|
287
|
+
- Make one number the obvious hero of each panel.
|
|
288
|
+
- Align every bar in a panel to a shared label column + bar width (clean vertical rules).
|
|
289
|
+
- Use gradient meters / braille graphs that *encode data*; degrade gradients to a solid accent
|
|
290
|
+
below truecolor.
|
|
291
|
+
- Detect adapter wattage, units, core counts, terminal color level, and viewport width **live**.
|
|
292
|
+
- Show `—` when data honestly isn't available zero-sudo; record an explicit waiver before
|
|
293
|
+
dropping a previously-live metric (e.g. the LAN IP, D12).
|
|
294
|
+
|
|
295
|
+
**Don't**
|
|
296
|
+
- Don't fix "flat" with saturation or contrast — add form/data/hierarchy instead.
|
|
297
|
+
- Don't use the `⚡` emoji, pure black/white, or complementary hue clashes.
|
|
298
|
+
- Don't spend per-module hue on panel bodies — confine it to title/border/hero number.
|
|
299
|
+
- Don't treat motion as a routine-state channel (alarm/transition only).
|
|
300
|
+
- Don't ask for `sudo`, ever — not even opt-in (D2). Don't give Disk/Sensors hero space.
|
|
301
|
+
- Don't ship light mode as an afterthought — it has the full quality bar minus glow.
|
|
302
|
+
|
|
303
|
+
## Methodology — what this is built on
|
|
304
|
+
|
|
305
|
+
- **Tufte**, *Visual Display* / *Envisioning Information* — data-ink, sparklines, small multiples,
|
|
306
|
+
**smallest effective difference**.
|
|
307
|
+
- **Few**, *Information Dashboard Design* — glanceability, muted-by-default, color as scarce.
|
|
308
|
+
- **Ware**, *Information Visualization* — preattentive attributes; chromostereopsis; redundant encoding.
|
|
309
|
+
- **Wathan & Schoger**, *Refactoring UI* — no pure black/white, reduce saturation, accent sparingly.
|
|
310
|
+
- **Rams**, *Ten Principles* — "Less, but better"; design is unobtrusive.
|
|
311
|
+
- **Weiser**, *Calm Technology* — inform from the periphery; demand attention only on events.
|
|
312
|
+
- **Marcotte** *Responsive Web Design* / **Wroblewski** *Mobile First* / **Walton** *Content Choreography* — the responsive model.
|
|
313
|
+
- **Everforest / Nord / Solarized** palette methodologies — engineered low-eye-strain color.
|
|
314
|
+
- **60-30-10** — keep the loud 10% actually 10%.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yunfei He
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="machud" src="https://raw.githubusercontent.com/hyf0/machud/main/.github/assets/banner.png" width="640">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
A zero-config system monitor for the macOS terminal.
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**machud is opinionated — that's the whole point.** Where [btop](https://github.com/aristocratos/btop) wins on deep configurability, machud wins on *beautiful + zero-config*: no settings, no theme switcher, no layout knobs. The single curated wide-screen dashboard — Apple-Silicon-aware, system-following light/dark — **is** the product. Want to tune everything yourself? Use btop. machud is the considered default that looks right out of the box and never asks for your password.
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img alt="machud dashboard" src="https://raw.githubusercontent.com/hyf0/machud/main/.github/assets/screenshot.png" width="860">
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Requires macOS and Node ≥ 22.18. No install, no config, no password:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx machud@latest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
> **Using [Vite+](https://viteplus.dev)?** Try it with:
|
|
26
|
+
>
|
|
27
|
+
> ```bash
|
|
28
|
+
> vpx machud@latest
|
|
29
|
+
> ```
|
|
30
|
+
|
|
31
|
+
### From source
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pnpm install
|
|
35
|
+
pnpm build # bundle to dist/machud.mjs
|
|
36
|
+
pnpm start # run the live dashboard (needs a real TTY)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Other entry points:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pnpm dev # dev mode with HMR
|
|
43
|
+
node dist/machud.mjs --once # render ONE real-data frame to stdout and exit
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`--once` needs no TTY — it prints a single frame with live readings and doubles as a pipe-friendly snapshot.
|
|
47
|
+
|
|
48
|
+
## Design
|
|
49
|
+
|
|
50
|
+
- **Zero-sudo first.** Every reading comes from unprivileged commands (`sysctl`, `vm_stat`, `ioreg`, `pmset`, `netstat`, `df`, `ps`) plus Node's `os`. Metrics that would need `sudo` — precise per-cluster frequency, GPU watts, fan RPM, die temperatures — render as `—`. They never block startup, and machud never asks for your password.
|
|
51
|
+
- **Never crash, just degrade.** Each collector returns safe nulls on failure, and any throwing collector is swapped for its empty default. A missing metric is a dash, not a stack trace.
|
|
52
|
+
- **Apple-Silicon-aware.** P/E-core clusters, unified-memory pressure, and live battery wattage are first-class — with graceful single-cluster fallback on Intel.
|
|
53
|
+
|
|
54
|
+
## Contributing
|
|
55
|
+
|
|
56
|
+
machud is opinionated by design. **Bug reports are welcome; feature PRs opened without a prior, agreed-upon issue are closed directly**, and theming / feature / aesthetic changes are generally not accepted. See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
57
|
+
|
|
58
|
+
## Credits
|
|
59
|
+
|
|
60
|
+
machud was inspired by [Stats](https://github.com/exelban/stats) by [@exelban](https://github.com/exelban) — its idea, brought to the terminal.
|