create-halation 0.1.1 → 0.2.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/package.json
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "sh \"${CLAUDE_PROJECT_DIR:-.}/.halation/hooks.sh\" guard || exit 2"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
3
14
|
"PostToolUse": [
|
|
4
15
|
{
|
|
5
16
|
"matcher": "Edit|Write|MultiEdit",
|
|
6
17
|
"hooks": [
|
|
7
18
|
{
|
|
8
19
|
"type": "command",
|
|
9
|
-
"command": "
|
|
20
|
+
"command": "sh \"${CLAUDE_PROJECT_DIR:-.}/.halation/hooks.sh\" lint || exit 2"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"Stop": [
|
|
26
|
+
{
|
|
27
|
+
"hooks": [
|
|
28
|
+
{
|
|
29
|
+
"type": "command",
|
|
30
|
+
"command": "sh \"${CLAUDE_PROJECT_DIR:-.}/.halation/hooks.sh\" stop || exit 2"
|
|
10
31
|
}
|
|
11
32
|
]
|
|
12
33
|
}
|
|
@@ -5,7 +5,7 @@ description: The Halation design system's rules and React components for this pr
|
|
|
5
5
|
|
|
6
6
|
# Halation
|
|
7
7
|
|
|
8
|
-
This project's look is a set of rules, enforced in code. Build with the components, the
|
|
8
|
+
This project's look is a set of rules, enforced in code. Build with the components, the eleven text styles and the color roles, and the result stays on brand without guessing. `halation lint` and a hook check source as you edit; `halation check` measures the rendered page.
|
|
9
9
|
|
|
10
10
|
## Set up
|
|
11
11
|
|
|
@@ -28,7 +28,7 @@ export function App({ children }) {
|
|
|
28
28
|
- Ink, not color. One accent, spent only where it means something; the main action is ink (R1, R2).
|
|
29
29
|
- Light, not paint. Depth comes from an atmosphere, lit edges and shadows, never decorative gradients (R3, R15).
|
|
30
30
|
- Structure, not strings. Facts get their own lines, states get a word and a shape (R9, R10).
|
|
31
|
-
- Few sizes, plain case.
|
|
31
|
+
- Few sizes, plain case. Eleven text styles, sentence case, no added tracking (R5, R6, R7).
|
|
32
32
|
- Lines before boxes. A hairline or space first; a box only for an object, never a box in a box (R13).
|
|
33
33
|
- Motion explains a change. Under 300 ms, exits faster than enters, nothing moving while idle (R14).
|
|
34
34
|
- Plain words. Sentence case, short labels; errors say what's wrong and how to fix it.
|
|
@@ -81,11 +81,11 @@ export function App({ children }) {
|
|
|
81
81
|
- Do: The text style alone; each one sets its own tracking.
|
|
82
82
|
- Why: Tracking is tuned per size already; extra spacing is how eyebrows get made.
|
|
83
83
|
- Instead: The text style for that size.
|
|
84
|
-
- Caught by: Theme.
|
|
84
|
+
- Caught by: Theme, lint.
|
|
85
85
|
|
|
86
|
-
### R7:
|
|
86
|
+
### R7: Eleven named text styles; no other sizes.
|
|
87
87
|
|
|
88
|
-
- Don't: `text-sm`, `text-2xl`, `text-[13px]`, `font-size:
|
|
88
|
+
- Don't: `text-sm`, `text-2xl`, `text-[13px]`, `font-size: 17px`.
|
|
89
89
|
- Do: `<Text size="body-sm">`, `className="text-body-sm"` (Tailwind) or `hl-text-body-sm`.
|
|
90
90
|
- Why: A small scale is what makes pages feel composed.
|
|
91
91
|
- Instead: The nearest style.
|
|
@@ -179,6 +179,46 @@ export function App({ children }) {
|
|
|
179
179
|
- Instead: The Keys component.
|
|
180
180
|
- Caught by: Lint.
|
|
181
181
|
|
|
182
|
+
### R19: Tailwind comes through Halation's theme.
|
|
183
|
+
|
|
184
|
+
- Don't: `@import "tailwindcss"` in your CSS, which brings back Tailwind's whole palette and type scale.
|
|
185
|
+
- Do: `@import "@halation/core/tailwind.css"`, which loads Tailwind with only the system's values.
|
|
186
|
+
- Why: Tailwind's own entry brings back its whole palette, type scale and radii, so off-system classes quietly work again.
|
|
187
|
+
- Instead: @import "@halation/core/tailwind.css", which loads Tailwind with only the system's values.
|
|
188
|
+
- Caught by: Lint.
|
|
189
|
+
|
|
190
|
+
### R20: Pages look the same to the checker as to people.
|
|
191
|
+
|
|
192
|
+
- Don't: `if (navigator.webdriver)` or a user-agent test that shows a checker something different.
|
|
193
|
+
- Do: One page for everyone. If a check fails, fix the page.
|
|
194
|
+
- Why: A page that spots the checker and shows it something else hides every problem the check would find.
|
|
195
|
+
- Instead: One page for everyone; fix what the check reports.
|
|
196
|
+
- Caught by: Lint.
|
|
197
|
+
|
|
198
|
+
### R21: An exception names the rule it breaks.
|
|
199
|
+
|
|
200
|
+
- Don't: A bare `halation-ignore` comment, or one that names no rule.
|
|
201
|
+
- Do: `/* halation-ignore R9: a real product name uses the dot */`: the rule id, and why.
|
|
202
|
+
- Why: A blanket exception silences every rule on its line, including the ones nobody meant to allow.
|
|
203
|
+
- Instead: An exception needs the rule id it's for, like halation-ignore R9, and a reason.
|
|
204
|
+
- Caught by: Lint.
|
|
205
|
+
|
|
206
|
+
### R22: No glow on text.
|
|
207
|
+
|
|
208
|
+
- Don't: `text-shadow: 0 0 24px var(--color-accent)` to make a headline glow.
|
|
209
|
+
- Do: Light behind the text: a `<Stage>` phenomenon with the headline marked `data-quiet`.
|
|
210
|
+
- Why: Glowing text is a generated-design cliché, and it hurts legibility.
|
|
211
|
+
- Instead: Plain text. Light belongs to surfaces and phenomena. The one bloom text may take is the halation phenomenon's, in dark mode, once per page.
|
|
212
|
+
- Caught by: Lint, page check.
|
|
213
|
+
|
|
214
|
+
### R23: Pages fit a phone: nothing scrolls sideways.
|
|
215
|
+
|
|
216
|
+
- Don't: A fixed-width row, table or code line that makes a phone scroll sideways.
|
|
217
|
+
- Do: Let rows wrap, give tables and code their own scroll container, and check at 375 px.
|
|
218
|
+
- Why: Most visitors arrive on a phone, and a page that scrolls sideways there feels broken.
|
|
219
|
+
- Instead: Widths that give way: rows that wrap, fluid text styles, a max-width instead of a width.
|
|
220
|
+
- Caught by: Page check.
|
|
221
|
+
|
|
182
222
|
## What to use for what
|
|
183
223
|
|
|
184
224
|
| Need | Use |
|
|
@@ -211,13 +251,19 @@ export function App({ children }) {
|
|
|
211
251
|
| A person | `<Avatar name="..." src={...} />` |
|
|
212
252
|
| An icon | `<icons.CheckIcon />` and the rest, never emoji |
|
|
213
253
|
| The project's mark, credits, share image | `<Seal>`, `<Colophon>`, `<ShareCard>` |
|
|
254
|
+
| Search and jump anywhere (⌘K) | `<Lens>` with `useLensShortcut` |
|
|
255
|
+
| Let people set a keyboard shortcut | `<ShortcutRecorder>` |
|
|
256
|
+
| Pick a time of day | `<Sundial>` |
|
|
257
|
+
| Tune a value by feel | `<Dial>` |
|
|
258
|
+
| Let people pick an accent | `<AccentForge>` |
|
|
259
|
+
| Upload photos or files | `<LightTable>` |
|
|
214
260
|
|
|
215
261
|
## Components
|
|
216
262
|
|
|
217
263
|
All from `@halation/react`.
|
|
218
264
|
|
|
219
265
|
- **HalationProvider**: Wrap the app once. Sets accent, tempo and theme, hosts tooltips and toasts, and puts on the project's signature. `<HalationProvider name="Lumen" accent="vermilion">{children}</HalationProvider>`
|
|
220
|
-
- **Text**: Any running text, in one of the
|
|
266
|
+
- **Text**: Any running text, in one of the eleven styles (size) with an optional tone: muted, subtle, accent or critical. `<Text size="body-sm" tone="muted">Synced a minute ago</Text>`
|
|
221
267
|
- **Heading**: Headlines. level sets the element and its default style (1 is display-xl, 3 is title-1); size overrides the style. `<Heading level={3}>Storage</Heading>`
|
|
222
268
|
- **Serif**: The one italic serif phrase inside a headline, at title sizes and up (R8). `<Heading level={1}>Every app, <Serif>twice</Serif></Heading>`
|
|
223
269
|
- **Value**: A number with tabular figures and a quieter unit. `<Value unit="MB">412</Value>`
|
|
@@ -262,9 +308,18 @@ All from `@halation/react`.
|
|
|
262
308
|
- **useDevelop**: Develops an element like a print, once per visitor. For a landing hero. `const hero = useRef(null); useDevelop(hero)`
|
|
263
309
|
- **darkroom**: Opens or closes the darkroom inspector from code. `darkroom.enter()`
|
|
264
310
|
- **useDarkroom**: Whether the darkroom is open, for a button that enters and leaves it. `const open = useDarkroom()`
|
|
311
|
+
- **Lens**: A command palette that pulls focus: a lit carriage on the chosen row, the rest softening with distance. For any app with more than a handful of places to go. `<Lens open={open} onOpenChange={setOpen} groups={[{ name: "Copies", items: [{ id: "work", title: "Claude Work", onSelect: openWork }] }]} />`
|
|
312
|
+
- **useLensShortcut**: Opens Lens on ⌘K (Ctrl+K elsewhere). `useLensShortcut(() => setOpen(true))`
|
|
313
|
+
- **ShortcutRecorder**: Records a key combination with keycaps that go down while held. Refuses taken shortcuts and keys with no modifier, in words. Label it with what the shortcut does. `<ShortcutRecorder value={keys} onValueChange={setKeys} label="Switches to Claude Work" onMessage={setNote} />`
|
|
314
|
+
- **TAKEN_SHORTCUTS**: The shortcuts macOS keeps for itself, with the reason for each. Spread it into your own list of taken shortcuts. `taken={{ ...TAKEN_SHORTCUTS, "⌘N": "⌘N makes a new copy." }}`
|
|
315
|
+
- **Sundial**: A time-of-day picker set by moving the sun, showing the real sky for that minute. For schedules and quiet hours; value is minutes after midnight. `<Sundial value={minutes} onValueChange={setMinutes} label="Quiet hours begin at" />`
|
|
316
|
+
- **LitTabs**: Tabs whose selection is a carriage of light; labels gain weight as it passes. Use for a page's main sections. `<LitTabs aria-label="Sections" items={[{ value: "all", label: "Overview", content: <Overview /> }]} />`
|
|
317
|
+
- **Dial**: A rotary knob with detents that click, lit ticks and a rolling number. For intensity, volume, zoom: a value tuned by feel. `<Dial value={level} onValueChange={setLevel} label="Intensity" />`
|
|
318
|
+
- **AccentForge**: An accent picker that derives every accent role from a hue and shows each pair's contrast in both modes. Purple hues are closed. `<AccentForge hue={hue} onHueChange={setHue} />`
|
|
319
|
+
- **LightTable**: A file drop zone that backlights under the dragged file; dropped photos land as prints that develop. For uploads, avatars and imports. `<LightTable onFiles={upload} />`
|
|
265
320
|
- **icons**: The system's glyphs: CheckIcon, PlayIcon, WrenchIcon, StopIcon, PencilIcon, InfoIcon, AlertIcon, ChevronIcon, CloseIcon. Use these or a real icon set, never emoji. `<icons.CheckIcon />`
|
|
266
321
|
|
|
267
|
-
## The
|
|
322
|
+
## The eleven text styles
|
|
268
323
|
|
|
269
324
|
Use `<Text size>`, `<Heading size>`, `hl-text-<name>`, or `text-<name>` in Tailwind. No other sizes.
|
|
270
325
|
|
|
@@ -277,6 +332,7 @@ Use `<Text size>`, `<Heading size>`, `hl-text-<name>`, or `text-<name>` in Tailw
|
|
|
277
332
|
| title-3 | 20 px | Card and group titles. |
|
|
278
333
|
| body-lg | 18 px | Lead paragraphs under a headline. |
|
|
279
334
|
| body | 16 px | Reading text. |
|
|
335
|
+
| control | 15 px | Labels on tabs, keycaps and segmented controls. |
|
|
280
336
|
| body-sm | 14 px | Interface text: controls, lists, tables. |
|
|
281
337
|
| caption | 13 px | Metadata, helper text, footnotes. |
|
|
282
338
|
| micro | 12 px | Badges, keyboard keys, counters. Never sentences. |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Halation's hooks for Claude Code, written by halation init. Takes guard, lint or stop.
|
|
3
|
+
cd "${CLAUDE_PROJECT_DIR:-.}" || exit 2
|
|
4
|
+
input=$(cat)
|
|
5
|
+
run() {
|
|
6
|
+
if [ -x node_modules/.bin/halation ]; then printf '%s' "$input" | node_modules/.bin/halation "$@"; return $?; fi
|
|
7
|
+
if npx --no-install halation --version </dev/null >/dev/null 2>&1; then printf '%s' "$input" | npx --no-install halation "$@"; return $?; fi
|
|
8
|
+
return 127
|
|
9
|
+
}
|
|
10
|
+
case "$1" in
|
|
11
|
+
guard) run guard --hook ;;
|
|
12
|
+
lint) run lint --hook ;;
|
|
13
|
+
stop) run lint --stop ;;
|
|
14
|
+
*) echo "hooks.sh takes guard, lint or stop." >&2; exit 2 ;;
|
|
15
|
+
esac
|
|
16
|
+
status=$?
|
|
17
|
+
[ "$status" -eq 0 ] && exit 0
|
|
18
|
+
[ "$status" -ne 127 ] && exit 2
|
|
19
|
+
case "$1" in
|
|
20
|
+
guard)
|
|
21
|
+
printf '%s' "$input" | grep -Eq '"command"[[:space:]]*:[[:space:]]*"(npm|pnpm|yarn|bun)[[:space:]]+(install|i|ci|add)([[:space:]"]|$)' && exit 0
|
|
22
|
+
echo "Halation isn't installed in this project yet, so changes are blocked until it is. Install the project's dependencies first, with npm install or your package manager's install." >&2
|
|
23
|
+
exit 2 ;;
|
|
24
|
+
stop)
|
|
25
|
+
if printf '%s' "$input" | grep -Eq '"stop_hook_active"[[:space:]]*:[[:space:]]*true'; then
|
|
26
|
+
echo '{"systemMessage": "Halation is not installed, so the design rules were not checked before this turn ended."}'
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
echo "Halation isn't installed, so the design rules can't be checked. Install the project's dependencies, then finish." >&2
|
|
30
|
+
exit 2 ;;
|
|
31
|
+
*)
|
|
32
|
+
echo "Halation isn't installed, so this change wasn't linted. Install the project's dependencies." >&2
|
|
33
|
+
exit 2 ;;
|
|
34
|
+
esac
|
package/template/AGENTS.md
CHANGED
|
@@ -21,7 +21,7 @@ Run `pnpm build` before you call a change done. TypeScript must pass with no err
|
|
|
21
21
|
- Sentence case everywhere. No uppercase labels and no letter-spaced eyebrows.
|
|
22
22
|
- Facts go in `Facts` or on separate lines. Never join them with `·`, `•` or a bar.
|
|
23
23
|
- Show a state with `State`, never a colored dot.
|
|
24
|
-
- Text comes in
|
|
24
|
+
- Text comes in eleven styles: `display-xl`, `display`, `title-1`, `title-2`, `title-3`, `body-lg`, `body`, `control`, `body-sm`, `caption` and `micro`. `control` is for labels on tabs, keycaps and segmented controls. Use `Text`, `Heading` or the `hl-text-*` classes, not other sizes.
|
|
25
25
|
- Colors come from the tokens (`var(--color-fg)`, `var(--color-accent)` and the rest), never from literal values.
|
|
26
26
|
- No gradients as decoration. Depth comes from the phenomenon on the `Stage`, lit edges and shadows.
|
|
27
27
|
- One ink button per view: the main action. Everything else is secondary or ghost.
|
package/template/package.json
CHANGED
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
"check": "halation check http://localhost:5173"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@halation/react": "^0.
|
|
14
|
+
"@halation/react": "^0.2.1",
|
|
15
15
|
"react": "^19.3.0",
|
|
16
16
|
"react-dom": "^19.3.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@halation/cli": "^0.
|
|
19
|
+
"@halation/cli": "^0.2.1",
|
|
20
20
|
"@types/react": "^19.2.18",
|
|
21
21
|
"@types/react-dom": "^19.2.7",
|
|
22
22
|
"@vitejs/plugin-react": "^6.1.1",
|