@natjswenson/press 0.1.0 → 0.2.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ All notable changes to the **press** skill are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
6
6
  this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.0] - 2026-08-01
9
+
10
+ Everything `natejswenson.io` needed to adopt the brand without changing by a
11
+ single pixel. Surveying the site turned up four values the token set could not
12
+ express, so it could not have been migrated without either losing them or
13
+ hand-writing them locally — which is the failure mode press exists to end.
14
+
15
+ ### Added
16
+
17
+ - **Alpha tints as first-class derived tokens** — `border`, `border_hover` and
18
+ `accent_dim`, computed from `ink` and `accent` so no consumer writes an
19
+ `rgba()` by hand.
20
+
21
+ ### Changed
22
+
23
+ - **`mono_stack` gained `'JetBrains Mono'`.** The site's stack was one fallback
24
+ deeper than the token set's; emitting the shorter one would have silently
25
+ removed a face. Fallbacks are additive, so the union is canonical — the same
26
+ call made for the résumé's stacks in 0.1.0. Purely additive for every existing
27
+ consumer.
28
+
29
+ ### Known inconsistency, kept deliberately
30
+
31
+ `hair` (0.18) and `border` (0.16) are the same idea at two different strengths —
32
+ the résumé's hairline and the site's. They are recorded as separate tokens rather
33
+ than reconciled, because reconciling them would change one of two shipped
34
+ products. That is a decision to make on purpose, not a side effect of adopting
35
+ press. Documented in `tokens.json` under `derived.$comment`.
36
+
8
37
  ## [0.1.0] - 2026-07-31
9
38
 
10
39
  First release. Replaces eight hand-ported copies of the PRESS brand with one
@@ -63,4 +92,5 @@ source of truth and a CI drift gate.
63
92
  rasterised cards, whose eyebrow legitimately runs at `.16em`. Scoped rather
64
93
  than waived, and caught by linting the real shipped corpus.
65
94
 
95
+ [0.2.0]: https://github.com/natejswenson/claude-skills/releases/tag/press-v0.2.0
66
96
  [0.1.0]: https://github.com/natejswenson/claude-skills/releases/tag/press-v0.1.0
package/SKILL.md CHANGED
@@ -2,7 +2,7 @@
2
2
  name: press
3
3
  description: The one brand system for everything produced in Claude — design tokens, the visual laws, the run-presentation contract, and the universal voice core. Use when composing or restyling any artifact (report, résumé, card, cover, PDF, HTML page, chart), when asked about brand colors, fonts, the accent law or "the PRESS look", when adding a new skill that renders anything, or when a brand value needs to change everywhere at once. Also handles "check the brand is in sync", "why do my colors differ", and onboarding a new consumer repo.
4
4
  user_invocable: true
5
- version: 0.1.0
5
+ version: 0.2.0
6
6
  ---
7
7
 
8
8
  # /press — the brand system
package/brand/tokens.json CHANGED
@@ -33,14 +33,18 @@
33
33
  "ink_faint": "Decorative only — a faint element inside an illustration. Never body text, never a headline."
34
34
  },
35
35
  "derived": {
36
+ "$comment": "Alpha tints, all computed from ink or accent so no consumer writes an rgba() by hand. hair (0.18) and border (0.16) are the SAME IDEA at two different strengths — the résumé's hairline and the site's. That is a real inconsistency, kept deliberately: reconciling them would change one of two shipped products, which is a decision to make on purpose and not as a side effect of adopting press.",
36
37
  "hair_alpha": 0.18,
38
+ "border_alpha": 0.16,
39
+ "border_hover_alpha": 0.38,
40
+ "accent_dim_alpha": 0.12,
37
41
  "fill_steps": ["ink", "ink_mid", "dim"]
38
42
  },
39
43
  "fonts": {
40
44
  "$comment": "The union of every consumer's stack. Fallbacks are additive, so the richest chain is the canonical one — the résumé's print-tuned stacks were the deepest and became these. Single quotes so the same string is valid CSS and needs no escaping in a Python literal.",
41
45
  "display_stack": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto, 'Helvetica Neue', Arial, sans-serif",
42
46
  "serif_stack": "'New York', ui-serif, Georgia, 'Iowan Old Style', 'Times New Roman', serif",
43
- "mono_stack": "ui-monospace, 'SF Mono', 'Cascadia Code', Menlo, Consolas, monospace"
47
+ "mono_stack": "ui-monospace, 'SF Mono', 'Cascadia Code', 'JetBrains Mono', Menlo, Consolas, monospace"
44
48
  },
45
49
  "identity": {
46
50
  "stamp": "NS",
package/lib/emit.mjs CHANGED
@@ -291,8 +291,15 @@ function required(params, key, emitter) {
291
291
  return value;
292
292
  }
293
293
 
294
+ const DERIVED = {
295
+ hair: 'hair',
296
+ border: 'border',
297
+ border_hover: 'borderHover',
298
+ accent_dim: 'accentDim',
299
+ };
300
+
294
301
  function lookup(tokens, name) {
295
- if (name === 'hair') return tokens.derived.hair;
302
+ if (name in DERIVED) return tokens.derived[DERIVED[name]];
296
303
  for (const group of [tokens.colors, tokens.terminal, tokens.fonts, tokens.identity, tokens.marks]) {
297
304
  if (name in group) return group[name];
298
305
  }
package/lib/tokens.mjs CHANGED
@@ -41,9 +41,16 @@ function resolve(raw) {
41
41
  const colors = clean(raw.colors);
42
42
  const terminal = clean(raw.terminal);
43
43
 
44
- const hairAlpha = raw.derived?.hair_alpha ?? 0.18;
45
44
  const [r, g, b] = hexToRgb(colors.ink);
46
- const hair = `rgba(${r}, ${g}, ${b}, ${hairAlpha})`;
45
+ const [ar, ag, ab] = hexToRgb(colors.accent);
46
+ const inkAlpha = (a) => `rgba(${r}, ${g}, ${b}, ${a})`;
47
+
48
+ const hairAlpha = raw.derived?.hair_alpha ?? 0.18;
49
+ const hair = inkAlpha(hairAlpha);
50
+ // Named separately from `hair` on purpose — see derived.$comment in tokens.json.
51
+ const border = inkAlpha(raw.derived?.border_alpha ?? hairAlpha);
52
+ const borderHover = inkAlpha(raw.derived?.border_hover_alpha ?? 0.38);
53
+ const accentDim = `rgba(${ar}, ${ag}, ${ab}, ${raw.derived?.accent_dim_alpha ?? 0.12})`;
47
54
 
48
55
  const fillSteps = (raw.derived?.fill_steps ?? []).map((name) => {
49
56
  const value = colors[name];
@@ -61,7 +68,7 @@ function resolve(raw) {
61
68
  identity: clean(raw.identity),
62
69
  marks: clean(raw.marks),
63
70
  limits: clean(raw.limits),
64
- derived: { hair, hairAlpha, fillSteps },
71
+ derived: { hair, hairAlpha, border, borderHover, accentDim, fillSteps },
65
72
  /** Every literal color the brand permits, for the off-palette lint. */
66
73
  palette: [...Object.values(colors), ...Object.values(terminal)],
67
74
  };
@@ -77,6 +84,9 @@ export function hexToRgb(hex) {
77
84
  /** Look up a token by its flat name, including the derived ones. */
78
85
  export function tokenValue(tokens, name) {
79
86
  if (name === 'hair') return tokens.derived.hair;
87
+ if (name === 'border') return tokens.derived.border;
88
+ if (name === 'border_hover') return tokens.derived.borderHover;
89
+ if (name === 'accent_dim') return tokens.derived.accentDim;
80
90
  if (name in tokens.colors) return tokens.colors[name];
81
91
  if (name in tokens.terminal) return tokens.terminal[name];
82
92
  if (name in tokens.fonts) return tokens.fonts[name];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@natjswenson/press",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "One brand system — tokens, laws, run presentation and voice core — generated into every consumer with a CI drift gate",
5
5
  "license": "MIT",
6
6
  "author": "Nate Swenson",
package/targets.json CHANGED
@@ -303,12 +303,33 @@
303
303
  "token": "ink_faint",
304
304
  "name": "fg-tertiary"
305
305
  },
306
+ {
307
+ "token": "border"
308
+ },
309
+ {
310
+ "token": "border_hover"
311
+ },
306
312
  {
307
313
  "token": "accent"
308
314
  },
315
+ {
316
+ "token": "accent_dim"
317
+ },
309
318
  {
310
319
  "token": "rule"
311
320
  },
321
+ {
322
+ "token": "display_stack",
323
+ "name": "font-display"
324
+ },
325
+ {
326
+ "token": "serif_stack",
327
+ "name": "font-serif"
328
+ },
329
+ {
330
+ "token": "mono_stack",
331
+ "name": "font-mono"
332
+ },
312
333
  {
313
334
  "token": "term_bg",
314
335
  "name": "panel"
@@ -330,6 +351,10 @@
330
351
  "name": "panel-bar"
331
352
  }
332
353
  ]
354
+ },
355
+ "init": {
356
+ "replaceFrom": "^:root \\{$",
357
+ "replaceTo": "^\\}$"
333
358
  }
334
359
  }
335
360
  ]