asciify-engine 4.13.0 → 4.14.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/README.md +7 -0
- package/dist/characters-BgG9AZQl.d.cts +72 -0
- package/dist/characters-BgG9AZQl.d.ts +72 -0
- package/dist/core.d.cts +2 -1
- package/dist/core.d.ts +2 -1
- package/dist/field.cjs +1 -1
- package/dist/field.d.cts +6 -0
- package/dist/field.d.ts +6 -0
- package/dist/field.js +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/kit.cjs +1 -1
- package/dist/kit.d.cts +270 -7
- package/dist/kit.d.ts +270 -7
- package/dist/kit.js +1 -1
- package/dist/{model-B0jK31nS.d.cts → model-9SbRVqqI.d.cts} +1 -72
- package/dist/{model-BARiWJks.d.ts → model-DXHhQhxP.d.ts} +1 -72
- package/dist/studio.d.cts +3 -2
- package/dist/studio.d.ts +3 -2
- package/package.json +1 -1
- package/skills/asciify-engine/SKILL.md +74 -48
- package/skills/asciify-engine/references/applying-asciify.md +234 -0
- package/skills/asciify-engine/references/components.md +1 -1
- package/skills/asciify-engine/references/design-matching.md +10 -7
- package/skills/asciify-engine/references/glyph-field.md +3 -0
- package/skills/asciify-engine/references/kit.md +112 -26
- package/skills/asciify-engine/references/media-api.md +2 -2
- package/skills/asciify-engine/references/project-integration.md +1 -1
- package/skills/asciify-engine/references/scenario-prompts.md +1 -1
- package/skills/asciify-engine/references/upgrading.md +1 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Applying Asciify: the house design
|
|
2
|
+
|
|
3
|
+
How asciify.org puts characters into a real interface. Read this before choosing a component or a background, then take the call from [components.md](components.md) and its options from [kit.md](kit.md). Every rule here is one you can check in the browser.
|
|
4
|
+
|
|
5
|
+
The site's claim is the brief: ASCII that belongs in your interface. Characters are a material the interface uses for a job (showing work, confirming an outcome, moving between states, setting one ground for a page), drawn in the page's own ink, inside its own shapes, at its own pace.
|
|
6
|
+
|
|
7
|
+
## 1. Give the characters a job
|
|
8
|
+
|
|
9
|
+
Pick by what the field does for the person, not by how it looks.
|
|
10
|
+
|
|
11
|
+
| Job | Use |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Show that work is running | `buttonLoading`, `statusOrb`, `thinking`, `streamText`, `skeleton`, `imageGenerate`, `pullRefresh` |
|
|
14
|
+
| Confirm or refuse an outcome | `statusOrb` success, warning or error; `slideToConfirm`; `codeInput` `verify()`; `beam` `success()` or `error()` |
|
|
15
|
+
| Show a value changing | `odometer`, `pill` counts, `blockChart` |
|
|
16
|
+
| Move between states or views | `tabs`, `pageDissolve`, `commandPalette`, `toastStack`, `disintegrate` |
|
|
17
|
+
| Answer a gesture | `likeBurst`, `swipeDeck`, `compare`, `accordion`, `dropzone` |
|
|
18
|
+
| Carry a brand moment or media | `decode`, `wordmark`, `asciiVideo`, `artPanel`, `pricingGlow`, `fieldBackground` `notFound` |
|
|
19
|
+
| Set the page's one ground | `fieldBackground` `hero`, or `background()` with a preset (section 9) |
|
|
20
|
+
|
|
21
|
+
Do not use characters:
|
|
22
|
+
|
|
23
|
+
- behind body copy, forms, tables, code, docs pages or navigation;
|
|
24
|
+
- on every card in a grid, or as a second ground on a page that has one;
|
|
25
|
+
- as the only carrier of a state: the label, the live region or the HTML still says it;
|
|
26
|
+
- for a loader with no real work behind it, or for decoration that never answers an event.
|
|
27
|
+
|
|
28
|
+
Test: hide the canvas. If the interface loses no feedback and the field was not the page's one ground, remove it. A ground earns its place by answering the interface. On asciify.org the hero field pulses when the command is copied:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { fieldBackground } from 'asciify-engine/kit';
|
|
32
|
+
|
|
33
|
+
const bg = fieldBackground(hero, { preset: 'hero', clear: heroCopy });
|
|
34
|
+
copyButton.addEventListener('click', () => bg.pulse(copyButton));
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 2. Ink: quiet by default, colour only for meaning
|
|
38
|
+
|
|
39
|
+
Inks come from theme tokens, defined for both schemes. The kit re-reads them when `prefers-color-scheme` changes and when `class` or `data-theme` changes on `<html>` or `<body>`, so define the dark values under both selectors. These are the engine's own fallbacks and the site's graphite:
|
|
40
|
+
|
|
41
|
+
```css
|
|
42
|
+
:root {
|
|
43
|
+
--ascii-ink: #76746e; /* grounds, rings, quiet strokes */
|
|
44
|
+
--ascii-ink-strong: #1d1d1b; /* a component that is the focus */
|
|
45
|
+
--ascii-success: #17844a; --ascii-warning: #9a6700; --ascii-error: #c93636;
|
|
46
|
+
}
|
|
47
|
+
@media (prefers-color-scheme: dark) {
|
|
48
|
+
:root:not([data-theme="light"]) { --ascii-ink: #7a7872; --ascii-ink-strong: #d8d6cf; --ascii-success: #3ccf7e; --ascii-warning: #f5b83d; --ascii-error: #ff6b6b; }
|
|
49
|
+
}
|
|
50
|
+
:root[data-theme="dark"] { --ascii-ink: #7a7872; --ascii-ink-strong: #d8d6cf; --ascii-success: #3ccf7e; --ascii-warning: #f5b83d; --ascii-error: #ff6b6b; }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Rules:
|
|
54
|
+
|
|
55
|
+
- **Default to graphite.** Leave `ink` unset: components pick `--ascii-ink` or `--ascii-ink-strong` and background presets use their graphite. On another brand, map these tokens to its muted text colour, never to its accent.
|
|
56
|
+
- **Colour means something.** Green, amber and red are for outcomes only, and come from `--ascii-success`, `--ascii-warning` and `--ascii-error`. The site's phosphor marks live states only and is never a button or text.
|
|
57
|
+
- **Palettes are deliberate.** `beam` `colorful`, `voiceOrb` `aurora` and `fieldBackground` `brand` are chosen palettes for one moment the user asked for, not a page default.
|
|
58
|
+
- **Never a new colour.** No hex that is not a token, no black canvas on a light page, no white glow on a coloured image.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { background, halftone, statusOrb, beam } from 'asciify-engine/kit';
|
|
62
|
+
|
|
63
|
+
background(pricing, { preset: halftone, clear: pricingCopy, ink: '--ascii-ink' }); // the token, re-read per theme
|
|
64
|
+
const orb = statusOrb(orbSlot); // strong ink at rest; outcomes read --ascii-success, --ascii-warning, --ascii-error
|
|
65
|
+
beam(planCard, { palette: 'mono', mode: 'pulse' }); // the quiet beam; 'colorful' only when asked for
|
|
66
|
+
orb.loading();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 3. Text over a field: clear zone plus frosted veil
|
|
70
|
+
|
|
71
|
+
Text never sits on raw characters, and never in a box. Two layers do the work:
|
|
72
|
+
|
|
73
|
+
1. **The clear zone.** Pass the text block as `clear`; the field fades out around it (`fieldBackground` in a soft ellipse, the GPU background presets in a feathered rectangle 32px out, canvas presets in a soft ellipse).
|
|
74
|
+
2. **The veil.** A frosted, radially masked wash of the ground behind the text, so characters blur and fade toward the words instead of stopping at an edge. This is asciify.org's CSS:
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
.hero-copy { position: relative; isolation: isolate; }
|
|
78
|
+
.hero-copy::before {
|
|
79
|
+
content: ""; position: absolute; z-index: -1; inset: -36px -64px; pointer-events: none;
|
|
80
|
+
background: color-mix(in oklab, var(--bg) 62%, transparent);
|
|
81
|
+
-webkit-backdrop-filter: blur(9px) saturate(1.1); backdrop-filter: blur(9px) saturate(1.1);
|
|
82
|
+
-webkit-mask-image: radial-gradient(closest-side, #000 52%, rgb(0 0 0 / .6) 74%, transparent);
|
|
83
|
+
mask-image: radial-gradient(closest-side, #000 52%, rgb(0 0 0 / .6) 74%, transparent);
|
|
84
|
+
}
|
|
85
|
+
/* A smaller block, such as a card's title and button: a tighter veil from the surface it sits on. */
|
|
86
|
+
.card-copy::before { inset: -24px -40px; background: color-mix(in oklab, var(--surface-2) 58%, transparent); }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- No solid panels, cards or hard-edged scrims behind headline copy. Buttons keep their own opaque fill.
|
|
90
|
+
- A header over a field: mask the field to about a quarter strength under the header strip, as the site does: `mask-image: linear-gradient(to bottom, rgb(0 0 0 / .26), rgb(0 0 0 / .26) 56px, #000 152px, #000 80%, transparent)`.
|
|
91
|
+
- **Contrast.** Body and lede text 4.5:1, display text of 24px and up 3:1, measured against the busiest frame under the text, in both themes. Fix a failure with the clear zone, the veil, a lower `opacity` or larger cells. Never dim, recolour or shadow the text to fix it.
|
|
92
|
+
|
|
93
|
+
## 4. Density and cell size by surface
|
|
94
|
+
|
|
95
|
+
| Surface | Cell size | Characters | Site reference |
|
|
96
|
+
| --- | --- | --- | --- |
|
|
97
|
+
| Page hero ground | 10–12px, broad shapes | Sparse: `' .:+*#'` in the mono face | `fieldBackground` `hero` (10px), `drift` (11px), `halftone` (14px dot spacing) |
|
|
98
|
+
| Section band or card stage | 7–10px | Fuller ramp for images (`' .:-=+*#%@'`), quiet ramp for grounds | images 7px, character fields 10px, halftone 9px |
|
|
99
|
+
| Control: button, pill, tabs, code input, odometer | Leave it to the kit | The kit fits cells to the element's text | Use a monospaced label for `buttonLoading` |
|
|
100
|
+
|
|
101
|
+
- One density per surface: a stage does not mix a 7px image and a 12px ground.
|
|
102
|
+
- Nothing under 6px on a phone; the GPU grounds already enlarge their shapes under 760px.
|
|
103
|
+
- Tune with `look: { cellSize }` on a component or `cellSize` on `background()`, and only after looking at it at 1x and 2x.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { background, drift } from 'asciify-engine/kit';
|
|
107
|
+
|
|
108
|
+
const band = background(featureBand, { preset: drift, cellSize: 12, clear: bandCopy }); // a touch quieter than the default 11
|
|
109
|
+
band.update({ charset: ' .:+*#' }); // the hero's sparse ramp
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 5. Radii and containment
|
|
113
|
+
|
|
114
|
+
The kit clips every field to its host's computed corner radii, so the shape must be on the host.
|
|
115
|
+
|
|
116
|
+
- Put `border-radius` on the element you pass, from the project's tokens, never a literal. asciify.org: `--r-xs` 8px, `--r-inner` 18px, `--r-panel` 24px, `--r-dialog` 28px, and every control a pill (`--r-control: 999px`).
|
|
117
|
+
- Nest radii: an inner frame inset by `p` takes `calc(var(--r-panel) - p)`, as the site's video frame does (`calc(var(--r-panel) - 8px)` inside an 8px padding).
|
|
118
|
+
- Give `overflow: hidden` and a background to hosts the kit draws inside: `artPanel`, `imageGenerate`, `compare`, `accordion`, `dropzone`.
|
|
119
|
+
- Some components draw past their host on purpose: `voiceOrb` 8%, `codeInput` 16px, `toastStack` 24px, `likeBurst` 40px (`outset`), `swipeDeck` 56px (`outset`). Their container must have that much room, or bound them:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { likeBurst, swipeDeck } from 'asciify-engine/kit';
|
|
123
|
+
|
|
124
|
+
likeBurst(likeButton, { limit: postBody, outset: 24 }); // nothing above the post body, sparks inside the card's padding
|
|
125
|
+
swipeDeck(stack, { outset: 32 }); // the stage's own padding, so a fling thins out before its edge
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Check: with the page zoomed to 200%, no character lands outside a rounded corner or past a container edge.
|
|
129
|
+
|
|
130
|
+
## 6. Motion
|
|
131
|
+
|
|
132
|
+
- **Interface: 280ms or less.** Anything a person waits on: tab indicator (`tabs` defaults to 280), panel open (`accordion` 280), tone change (`pill` 240), poster fade (280), view swap (`pageDissolve` 140 + 160).
|
|
133
|
+
- **Decorative: 800ms or less.** One-shot flourishes: `disintegrate` 620, `dropzone` develop 720, the like burst. `decode` defaults to 900, so pass `duration: 800` or less.
|
|
134
|
+
- **Ambient loops: slow.** Keep `speed` at or below the preset's own. Motion should be noticed on the second look, not the first.
|
|
135
|
+
- **Easing.** CSS around the field uses the house ease-out, `--ease: cubic-bezier(.23, 1, .32, 1)`, with 140ms for control colour changes. The kit's own motion runs on `cubic-bezier(.16, 1, .3, 1)`. No linear or ease-in entries; a spring only where the material earns a settle (a like, a badge).
|
|
136
|
+
- **Reduced motion.** The kit draws each state settled in one frame and each background as one still; poster fades become instant. Drop your own transitions too, and never hide a playing canvas with CSS instead.
|
|
137
|
+
- **Off screen.** The kit pauses fields off screen and in hidden tabs. Call `pause()` on fields inside closed overlays. Give video and any field that is the content, not a texture, a visible pause control.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { tabs, decode } from 'asciify-engine/kit';
|
|
141
|
+
|
|
142
|
+
tabs(tablist, { duration: 280, panels: 'attribute' }); // interface
|
|
143
|
+
decode(headline, { duration: 800, settle: 'text' }); // decorative, under the 800ms ceiling
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```css
|
|
147
|
+
:root { --ease: cubic-bezier(.23, 1, .32, 1); --fast: 140ms; }
|
|
148
|
+
@media (prefers-reduced-motion: reduce) { .tab, .panel, .btn { transition: none; animation: none; } }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 7. Performance
|
|
152
|
+
|
|
153
|
+
- **About 12 fields per page.** At most 12 kit fields hold a WebGL context at once (`setFieldBudget` changes it). asciify.org's home page runs 12. Past that, share: one `pill()` call over a list draws every pill with one field.
|
|
154
|
+
- **Lazy by default.** Fields mount within half a viewport and release beyond one. Use `lazy: false` only for the hero in the first viewport.
|
|
155
|
+
- **Posters.** Give every field above the fold, and every field that matters without WebGL, a still per theme, and swap it on theme change with `update({ poster })` rather than remounting.
|
|
156
|
+
- **Canvas presets cost CPU, not contexts.** Count them toward the page anyway; one animated ground per viewport.
|
|
157
|
+
- **Import by name.** Presets are separate exports, so import only those you mount.
|
|
158
|
+
- **Destroy on unmount.** In React, create the handle in an effect and return its `destroy`.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { fieldBackground, setFieldBudget } from 'asciify-engine/kit';
|
|
162
|
+
|
|
163
|
+
setFieldBudget(10); // a page with heavy media of its own
|
|
164
|
+
const dark = matchMedia('(prefers-color-scheme: dark)');
|
|
165
|
+
const still = (isDark: boolean) => `/stills/hero-${isDark ? 'dark' : 'light'}.webp`;
|
|
166
|
+
const ground = fieldBackground(hero, { preset: 'hero', clear: heroCopy, lazy: false, poster: still(dark.matches) });
|
|
167
|
+
dark.addEventListener('change', event => ground.update({ poster: still(event.matches) }));
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 8. Accessibility
|
|
171
|
+
|
|
172
|
+
- **Canvases are decoration.** Kit fields are `aria-hidden` and ignore the pointer. Only the canvases that are the content take a `label`: `fieldBackground` `notFound`, `asciiVideo`, `artPanel`.
|
|
173
|
+
- **Real text stays in the DOM.** `decode`, `wordmark` and `streamText` keep the actual words selectable and readable; `odometer` and `pill` counts add a hidden copy; `blockChart` adds a hidden table. Do not replace text with a field.
|
|
174
|
+
- **Status is announced.** Pass a live region to `buttonLoading` (`announce`) and `thinking` (`label`), write `statusOrb` outcomes to one yourself, and give `pullRefresh` its `messages`. `toastStack` adds its own `role="status"` region.
|
|
175
|
+
- **Keyboard and focus.** The kit wires keys for `tabs`, `commandPalette`, `slideToConfirm`, `compare`, `accordion`, `swipeDeck` and `codeInput`; keep them (`manage` stays true). Keep a Refresh button beside pull to refresh. A field never covers a focus ring: `beam` draws inside the border, so a 2px outline at 3px offset stays clear.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { statusOrb, buttonLoading } from 'asciify-engine/kit';
|
|
179
|
+
|
|
180
|
+
// <p id="publish-status" role="status" aria-live="polite"></p>
|
|
181
|
+
const orb = statusOrb(orbSlot, { ring: true });
|
|
182
|
+
const button = buttonLoading(publishButton, { announce: publishStatus });
|
|
183
|
+
publishButton.addEventListener('click', async () => {
|
|
184
|
+
orb.loading(); button.start('Publishing');
|
|
185
|
+
await save().then(() => { orb.success(); button.succeed('Published'); }, () => { orb.error(); button.fail('Retry'); });
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 9. Backgrounds
|
|
190
|
+
|
|
191
|
+
`background(element, { preset })` draws any of the 26 presets from asciify.org/backgrounds under the element's content. Choose by surface:
|
|
192
|
+
|
|
193
|
+
| Surface | Presets | Notes |
|
|
194
|
+
| --- | --- | --- |
|
|
195
|
+
| Product hero, pricing, docs landing, behind copy | `drift`, `halftone`, or `fieldBackground` `hero` | GPU grounds that clear around `clear`. `halftone` is the calmest; `fieldBackground` `hero` is asciify.org's own hero, with ripples and `pulse()`. |
|
|
196
|
+
| A brand or name moment | `wordField` (id `field`), `fieldBackground` `brand` | Your word in the field; keep copy off its centre. |
|
|
197
|
+
| Art-first hero with little copy | `fluid` | The original Asciify hero, 7px cells at 0.7 opacity. Not behind reading text. |
|
|
198
|
+
| Quiet texture: section bands, footers, empty states, side panels | `caustics`, `contour`, `facet`, `etch`, `moire`, `weave`, `veil`, `dune`, `silk` | Canvas, no cursor, slow. The safest behind text after `halftone`. |
|
|
199
|
+
| An interactive moment the visitor plays with | `wave`, `aurora`, `noise`, `stars`, `pulse`, `voidWell` | They answer the cursor. Keep them away from forms and body copy. |
|
|
200
|
+
| A themed subject the page is about | `rain`, `grid`, `morph`, `fire`, `dna`, `terrain`, `circuit` | Loud. Use only when the subject matches (DNA for a biotech page), with low opacity and copy beside, not over. |
|
|
201
|
+
|
|
202
|
+
Keep them calm:
|
|
203
|
+
|
|
204
|
+
- `speed` at or below the preset's default; `cursor: false` near forms and copy.
|
|
205
|
+
- On canvas presets behind text, `opacity` 0.5–0.8; GPU grounds already draw quietly.
|
|
206
|
+
- Always `clear` the copy and add the veil from section 3; on the /backgrounds page the copy also sits on the side the field fades toward.
|
|
207
|
+
- One background per page section, under one `isolation: isolate` host with its own background colour.
|
|
208
|
+
- `setPreset()` cross-fades in place for a picker; do not mount a second background.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import { background, contour, caustics } from 'asciify-engine/kit';
|
|
212
|
+
|
|
213
|
+
const section = background(features, { preset: contour, clear: featuresCopy, opacity: 0.6, cursor: false });
|
|
214
|
+
themePicker.addEventListener('change', () => section.setPreset(caustics)); // keeps clear, opacity and cursor
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { background, drift } from 'asciify-engine/kit';
|
|
219
|
+
|
|
220
|
+
const bg = background(hero, { preset: drift, clear: heroCopy, poster: '/stills/drift-light.webp' });
|
|
221
|
+
signUpButton.addEventListener('click', () => bg.field?.pulse({ element: signUpButton, strength: 1.2 })); // GPU presets expose the field
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 10. Checklist before you finish
|
|
225
|
+
|
|
226
|
+
- [ ] Every field has a job from section 1; hiding it loses feedback, or it is the page's one ground.
|
|
227
|
+
- [ ] Ink comes from tokens in both themes; colour appears only for outcomes or a requested palette.
|
|
228
|
+
- [ ] Text over a field has `clear` plus the veil; 4.5:1 for body, 3:1 for display, at the busiest frame, light and dark.
|
|
229
|
+
- [ ] Cell size matches the surface; nothing under 6px on a 390px-wide phone.
|
|
230
|
+
- [ ] Every host carries its radius from tokens; nothing draws past a corner or container edge at 200% zoom.
|
|
231
|
+
- [ ] Interface motion ≤ 280ms, decorative ≤ 800ms, on the house ease-out; reduced motion shows settled stills.
|
|
232
|
+
- [ ] No more than about 12 fields per page; first-viewport fields have posters per theme; everything else is lazy.
|
|
233
|
+
- [ ] Canvases are `aria-hidden` unless labelled content; real text is in the DOM; status reaches a live region.
|
|
234
|
+
- [ ] Every handle is destroyed on unmount, and the page still works with WebGL off.
|
|
@@ -10,7 +10,7 @@ Every snippet uses `asciify-engine/kit`, one call per component. Start there by
|
|
|
10
10
|
- falls back without WebGL2 to an inert handle that leaves your HTML working as it was;
|
|
11
11
|
- cleans up on `destroy()`.
|
|
12
12
|
|
|
13
|
-
Build them in the project's own framework, design tokens and lifecycle
|
|
13
|
+
Before choosing one, read [applying Asciify](applying-asciify.md): when characters earn a place, ink from theme tokens, the clear zone and frosted veil for text, density, radii, motion limits, the field budget and accessibility. Build them in the project's own framework, design tokens and lifecycle. Free names in the snippets, such as `card`, `button` or `deployButton`, are the project's own DOM elements and functions. In React, create the handle in an effect and return its `destroy`:
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
16
|
useEffect(() => { const b = beam(ref.current!); return () => b.destroy(); }, []);
|
|
@@ -33,14 +33,16 @@ Never introduce a new brand color, a black canvas on a light site, or a second a
|
|
|
33
33
|
|
|
34
34
|
## 3. Pick the tool
|
|
35
35
|
|
|
36
|
+
For an interface component or a background, use `asciify-engine/kit` and follow [applying-asciify.md](applying-asciify.md); the rows below are for media looks and the lower-level APIs.
|
|
37
|
+
|
|
36
38
|
| The user wants | Use | Notes |
|
|
37
39
|
| --- | --- | --- |
|
|
38
40
|
| A photo, video or GIF converted on their page, with optional hover | `asciify`, `asciifyVideo`, `asciifyGif` (+ `mountHover` from `/hover`) | Lightest path. Disable core hover and motion when `/hover` owns them. |
|
|
39
41
|
| A full-bleed hero or brand field that must feel smooth under the cursor, their name or word as the characters, an Unseen-style look | `mountGlyphField` from `/field` | WebGL2 on a GPU, 120 fps class. Glyph ramps only. Keep a poster and a fallback. See [glyph-field.md](glyph-field.md). |
|
|
40
|
-
| A calm background for a product page, docs, pricing or SaaS hero, in light or dark | `
|
|
42
|
+
| A calm background for a product page, docs, pricing or SaaS hero, in light or dark | Kit `background(el, { preset: halftone, clear })` or `fieldBackground(el, { preset: 'hero', clear })` | Graphite ink, clear zone plus veil. See [applying-asciify.md](applying-asciify.md#9-backgrounds). Raw `mountGlyphField` with `mark: 'dot'` only for a look the kit lacks ([glyph-field.md](glyph-field.md#halftone-for-interfaces-412)). |
|
|
41
43
|
| Art styles (halftone, dither, braille, print, mosaic, LED…), saved looks, backdrops, masks, effects, PNG/MP4/GIF export | `mountStudio` from `/studio` | Studio owns motion, hover and finish. Start from `studioLook(id)` when one of the 12 looks matches the mood. |
|
|
42
44
|
| Several media and text layers in one artwork | `mountStudioProject` from `/studio` | One loop and budget for up to eight layers. See [layered-projects.md](layered-projects.md). |
|
|
43
|
-
| An ambient animated background with no media (rain, stars, waves, aurora…) |
|
|
45
|
+
| An ambient animated background with no media (rain, stars, waves, aurora…) | Kit `background(el, { preset })` with one of the 26 presets | Import presets by name from `asciify-engine/kit`. See [applying-asciify.md](applying-asciify.md#9-backgrounds) for which suits which surface. |
|
|
44
46
|
| A text banner or lettering | `asciifyText` / `renderTextToCanvas` | Plain text output works anywhere; canvas for color. |
|
|
45
47
|
| Headline text visible through the art | Layered HTML, see [layered-hero.md](layered-hero.md) | Real text stays in the DOM. |
|
|
46
48
|
|
|
@@ -86,7 +88,7 @@ Autonomous motion that lasts longer than five seconds needs a visible pause cont
|
|
|
86
88
|
|
|
87
89
|
## 5. Derive concrete values from the tokens
|
|
88
90
|
|
|
89
|
-
- **Ink.**
|
|
91
|
+
- **Ink.** Interface fields and grounds use a quiet graphite mapped to the muted text token, never the accent; colour is for outcomes only ([applying-asciify.md](applying-asciify.md#2-ink-quiet-by-default-colour-only-for-meaning)). A one-ink brand or media artwork the user asked for may use the accent. Photo looks keep source color unless the brand is strictly monochrome.
|
|
90
92
|
- **Ground.** Use the page background token exactly, or a transparent canvas over it. On light themes draw dark ink on the light ground: core `invert: true` or `'auto'`, field `background: <page color>` with a dark `ink` and `invert: true`, studio dark `ink` with a light `backdrop.color`.
|
|
91
93
|
- **Backdrop.** `backdrop` puts a blurred copy of the source under the characters. It enriches a photo but reads as a pale photographic wash on light subjects. Leave it at 0 when the user wants pure ASCII, and never use it behind text.
|
|
92
94
|
- **Wake color.** Keep the field's default `highlight: 'auto'`, which brightens each character's own color. Only set a hex highlight when the brand asks for a second color; never default to white on a colored artwork.
|
|
@@ -134,11 +136,12 @@ const field = mountGlyphField(canvas, {
|
|
|
134
136
|
|
|
135
137
|
For a quieter product page, add `hover: 'lantern'` (a soft light, no distortion) and keep `drift: 0` so the photo stays still until touched. Use `/studio` instead when they also want halftone, dither or an export button.
|
|
136
138
|
|
|
137
|
-
**"A subtle animated background behind our pricing section."**
|
|
139
|
+
**"A subtle animated background behind our pricing section."** Use a quiet kit preset with the page's muted ink, the cursor off and the copy kept clear:
|
|
138
140
|
|
|
139
|
-
```
|
|
140
|
-
import {
|
|
141
|
-
const
|
|
141
|
+
```ts
|
|
142
|
+
import { background, silk } from 'asciify-engine/kit';
|
|
143
|
+
const bg = background(pricing, { preset: silk, ink: '--ascii-ink', opacity: 0.6, cursor: false, clear: pricingCopy });
|
|
144
|
+
// On unmount: bg.destroy();
|
|
142
145
|
```
|
|
143
146
|
|
|
144
147
|
**"Retro terminal look for our launch video."**
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# GPU glyph fields (4.11)
|
|
2
2
|
|
|
3
|
+
For interface components and backgrounds, use `asciify-engine/kit` first ([applying-asciify.md](applying-asciify.md), [kit.md](kit.md)); it is built on this field and adds theme ink, posters, lazy mounting, the context budget and fallbacks. Mount the field directly only for a look the kit has no option for.
|
|
4
|
+
|
|
3
5
|
`asciify-engine/field` draws an image, a video or generated motion as characters entirely on the GPU, with a fluid wake under the cursor. Use it for full-bleed heroes, section backgrounds and brand fields where the frame must stay smooth while people move over it. It is a separate, optional entry; importing the root, `/core`, `/hover` or `/studio` never loads it.
|
|
4
6
|
|
|
5
7
|
Use `/studio` instead when you need the 24 render styles, dither, print styles, masks, effects or exports. The field draws glyph ramps only: characters, braille, block shading, dots, or your own letters.
|
|
@@ -38,6 +40,7 @@ Size the canvas with CSS (for example `position:absolute; inset:0; width:100%; h
|
|
|
38
40
|
| `clear` | `false` | Keeps the field quiet around content so text stays readable: an element, `{ element, padding, feather, shape }` (followed through layout changes), or a zone in field fractions. (4.12) |
|
|
39
41
|
| `charset` | `' .,:-=+*#%@'` | Ordered from empty to dense. Graphemes, so emoji, braille and block shading each take one cell. Up to 256. |
|
|
40
42
|
| `cellSize`, `cellAspect` | `12`, `1` | Cell height in CSS px; width ÷ height. Monospaced ramps look best near `0.6`. Cells are whole device pixels, and glyphs are sampled texel for texel. |
|
|
43
|
+
| `cellFit` | `'pixel'` | `'pixel'` snaps each cell to whole device pixels, so a fractional `cellSize` rounds and rows drift from a renderer that does not. `'fill'` fits a whole number of cells of at least `cellSize` × `cellAspect` and stretches them to fill the canvas exactly, as the core renderer lays out a frame; each glyph stays texel for texel, centred in its cell. |
|
|
41
44
|
| `font`, `fontWeight`, `glyphScale` | monospace, `500`, `0.8` | Any loaded CSS font. The atlas is redrawn when the font finishes loading. |
|
|
42
45
|
| `color` | `'ink'` | `'ink'` uses `ink`; `'source'` takes each cell's hue from the media. |
|
|
43
46
|
| `ink`, `highlight` | `#f3ba32`, `'auto'` | Hex colors. The wake lifts characters toward `highlight`; `'auto'` brightens each character's own color so the wake keeps the artwork's hue. |
|