@andersseen/skills 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/LICENSE +21 -0
- package/README.md +72 -0
- package/bin/cli.mjs +264 -0
- package/package.json +38 -0
- package/skills/andersseen/SKILL.md +93 -0
- package/skills/andersseen-headless-core/SKILL.md +178 -0
- package/skills/andersseen-icon/SKILL.md +124 -0
- package/skills/andersseen-layout/SKILL.md +198 -0
- package/skills/andersseen-motion/SKILL.md +166 -0
- package/skills/andersseen-web-components/SKILL.md +478 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: andersseen-icon
|
|
3
|
+
description:
|
|
4
|
+
'Register and render SVG icons with @andersseen/icon. Load when using
|
|
5
|
+
registerIcons / registerAllIcons / getIcon / COMPONENT_ICONS, wiring the
|
|
6
|
+
and-icon element, or resolving "icon not showing" issues. COMPONENT_ICONS must
|
|
7
|
+
be registered whenever @andersseen/web-components is used. Trigger phrases:
|
|
8
|
+
icon, svg, registerIcons, and-icon, icon registry, icon not rendering.'
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# @andersseen/icon — SVG icon registry
|
|
12
|
+
|
|
13
|
+
Framework-agnostic SVG string registry: tree-shakable icon constants + runtime
|
|
14
|
+
registration functions. Used internally by `and-icon` in
|
|
15
|
+
`@andersseen/web-components`, and consumable standalone to render SVGs in any
|
|
16
|
+
framework.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm i @andersseen/icon
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Core API
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import {
|
|
28
|
+
registerIcons,
|
|
29
|
+
registerAllIcons,
|
|
30
|
+
getIcon,
|
|
31
|
+
hasIcon,
|
|
32
|
+
getRegisteredIconNames,
|
|
33
|
+
getRegisteredIconCount,
|
|
34
|
+
} from '@andersseen/icon';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Verified behavior:
|
|
38
|
+
|
|
39
|
+
- The registry is global (`window`/`globalThis`) under `__AND_ICONS_REGISTRY__`.
|
|
40
|
+
- `registerIcons` merges entries into that global Map.
|
|
41
|
+
- `getIcon(name)` returns an SVG string or `undefined` if not registered.
|
|
42
|
+
|
|
43
|
+
## Setup options
|
|
44
|
+
|
|
45
|
+
### Option A — register all icons (prototyping / small apps)
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { registerAllIcons } from '@andersseen/icon';
|
|
49
|
+
registerAllIcons();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Option B — tree-shakable selective registration (production recommended)
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import {
|
|
56
|
+
registerIcons,
|
|
57
|
+
HOME,
|
|
58
|
+
CLOSE,
|
|
59
|
+
SEARCH,
|
|
60
|
+
COMPONENT_ICONS,
|
|
61
|
+
} from '@andersseen/icon';
|
|
62
|
+
|
|
63
|
+
// Icons required by and-* components — ALWAYS register when using web-components
|
|
64
|
+
registerIcons(COMPONENT_ICONS);
|
|
65
|
+
|
|
66
|
+
// Additional icons your app needs
|
|
67
|
+
registerIcons({ home: HOME, close: CLOSE, search: SEARCH });
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### COMPONENT_ICONS
|
|
71
|
+
|
|
72
|
+
A pre-built record containing every icon that `@andersseen/web-components` uses
|
|
73
|
+
internally (chevron, close, check, spinner, …). Always include it when using the
|
|
74
|
+
web-components package.
|
|
75
|
+
|
|
76
|
+
## Using registered icons
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const svg = getIcon('home'); // SVG string or undefined
|
|
80
|
+
|
|
81
|
+
if (!hasIcon('home')) {
|
|
82
|
+
console.warn('Icon "home" is not registered');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(getRegisteredIconNames());
|
|
86
|
+
console.log(getRegisteredIconCount());
|
|
87
|
+
|
|
88
|
+
// Render inline in a framework
|
|
89
|
+
// Angular: <span [innerHTML]="getIcon('home')"></span>
|
|
90
|
+
// Pure HTML: element.innerHTML = getIcon('home') ?? '';
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## With and-icon (web component)
|
|
94
|
+
|
|
95
|
+
After registration, use the icon by name via the `name` prop:
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<and-icon name="home" size="20"></and-icon>
|
|
99
|
+
<and-icon name="sparkles" size="16" color="hsl(var(--primary))"></and-icon>
|
|
100
|
+
<and-icon name="arrow-right" size="24" stroke-width="1.5"></and-icon>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Naming convention
|
|
104
|
+
|
|
105
|
+
Exported constants use `SCREAMING_SNAKE_CASE`; registration keys (and `name`
|
|
106
|
+
prop values) use `kebab-case`.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { ARROW_RIGHT, CHECK_CIRCLE, LOADING_SPINNER } from '@andersseen/icon';
|
|
110
|
+
registerIcons({
|
|
111
|
+
'arrow-right': ARROW_RIGHT,
|
|
112
|
+
'check-circle': CHECK_CIRCLE,
|
|
113
|
+
'loading-spinner': LOADING_SPINNER,
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Rules
|
|
118
|
+
|
|
119
|
+
- Always register icons before rendering `and-icon` or calling `getIcon`.
|
|
120
|
+
- In production prefer selective registration; avoid `registerAllIcons` outside
|
|
121
|
+
demos/prototypes.
|
|
122
|
+
- Keep `and-icon name` exactly aligned with registry keys.
|
|
123
|
+
- Do not inline random SVG literals when the registry can be used.
|
|
124
|
+
- Register `COMPONENT_ICONS` whenever `@andersseen/web-components` is used.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: andersseen-layout
|
|
3
|
+
description:
|
|
4
|
+
'Compose layout and typography with @andersseen/layout — a pure-CSS,
|
|
5
|
+
attribute-driven system using and-layout and and-text with @breakpoint
|
|
6
|
+
responsive modifiers. Load when building responsive page shells, grids, flex
|
|
7
|
+
layouts, spacing, or type scales without a utility framework. Trigger phrases:
|
|
8
|
+
and-layout, and-text, responsive grid, flex layout, spacing scale, typography,
|
|
9
|
+
cols, gap, and-layout attributes.'
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# @andersseen/layout — attribute-driven layout & typography
|
|
13
|
+
|
|
14
|
+
Pure CSS library — **no JavaScript runtime**. Attribute-driven layout
|
|
15
|
+
composition and typography, framework-agnostic and mobile-first. HTML attributes
|
|
16
|
+
are the single source of truth for layout.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm i @andersseen/layout
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import '@andersseen/layout/dist/layout.css';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Breakpoints (mobile-first, min-width)
|
|
31
|
+
|
|
32
|
+
| Name | Min-width |
|
|
33
|
+
| ---- | --------- |
|
|
34
|
+
| sm | 640px |
|
|
35
|
+
| md | 768px |
|
|
36
|
+
| lg | 1024px |
|
|
37
|
+
| xl | 1280px |
|
|
38
|
+
| 2xl | 1536px |
|
|
39
|
+
|
|
40
|
+
## Responsive syntax
|
|
41
|
+
|
|
42
|
+
Every modifier supports responsive variants using `@breakpoint`:
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<div and-layout="vertical vertical@sm horizontal@md gap:sm gap@lg:xl"></div>
|
|
46
|
+
<p and-text="p-sm align:center align@md:left"></p>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Spacing scale: `none · xxxs · xxs · xs · sm · md · lg · xl · xxl · xxxl · auto`.
|
|
50
|
+
|
|
51
|
+
## `and-layout`
|
|
52
|
+
|
|
53
|
+
### Display / direction
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<div and-layout="horizontal"><!-- flex row --></div>
|
|
57
|
+
<div and-layout="vertical"><!-- flex column --></div>
|
|
58
|
+
<div and-layout="grid"><!-- display:grid --></div>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Both `horizontal` and `vertical` are responsive: `horizontal@md`, `vertical@lg`.
|
|
62
|
+
|
|
63
|
+
### Flex alignment
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
align:start | end | center | baseline | stretch
|
|
67
|
+
justify:start | end | center | between | around | evenly
|
|
68
|
+
wrap:nowrap | wrap | wrap-reverse
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Gap
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
gap:{spacing} gap-x:{spacing} gap-y:{spacing}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Grid columns
|
|
78
|
+
|
|
79
|
+
Generates `repeat(N, minmax(0, 1fr))` for N in 1–12.
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<div and-layout="grid cols:1 cols@sm:2 cols@lg:3 gap:lg"></div>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Grid column span
|
|
86
|
+
|
|
87
|
+
Values 1–12 + `full` (span all columns).
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<div and-layout="grid cols:12">
|
|
91
|
+
<header and-layout="span:full">...</header>
|
|
92
|
+
<main and-layout="span:8 span@lg:9">...</main>
|
|
93
|
+
<aside and-layout="span:4 span@lg:3">...</aside>
|
|
94
|
+
</div>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Grid start/end
|
|
98
|
+
|
|
99
|
+
`col-start:1`–`col-start:13`, `col-start:auto`; `col-end:1`–`col-end:13`,
|
|
100
|
+
`col-end:auto`.
|
|
101
|
+
|
|
102
|
+
### Padding / margin
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
p:{s} p-t p-b p-l p-r p-x p-y : {s}
|
|
106
|
+
m:{s} m-t m-b m-l m-r m-x m-y : {s}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Spacing scale
|
|
110
|
+
|
|
111
|
+
| Token | Value | | Token | Value |
|
|
112
|
+
| ----- | -------- | --- | ----- | ------ |
|
|
113
|
+
| none | 0 | | md | 1rem |
|
|
114
|
+
| xxxs | 0.125rem | | lg | 1.5rem |
|
|
115
|
+
| xxs | 0.25rem | | xl | 2rem |
|
|
116
|
+
| xs | 0.5rem | | xxl | 3rem |
|
|
117
|
+
| sm | 0.75rem | | xxxl | 4rem |
|
|
118
|
+
| | | | auto | auto |
|
|
119
|
+
|
|
120
|
+
## `and-text` — typography
|
|
121
|
+
|
|
122
|
+
### Semantic scale
|
|
123
|
+
|
|
124
|
+
`h1 · h2 · h3 · h4 · h5 · h6 · p · p-sm · p-xs · caption`
|
|
125
|
+
|
|
126
|
+
| Token | Font size | Weight | Line-height |
|
|
127
|
+
| ------- | --------- | ------ | ----------- |
|
|
128
|
+
| h1 | 3.75rem | 700 | 1.1 |
|
|
129
|
+
| h2 | 3rem | 700 | 1.1 |
|
|
130
|
+
| h3 | 2.25rem | 600 | 1.2 |
|
|
131
|
+
| h4 | 1.875rem | 600 | 1.2 |
|
|
132
|
+
| h5 | 1.5rem | 500 | 1.3 |
|
|
133
|
+
| h6 | 1.25rem | 500 | 1.3 |
|
|
134
|
+
| p | 1rem | 400 | 1.5 |
|
|
135
|
+
| p-sm | 0.875rem | 400 | 1.5 |
|
|
136
|
+
| p-xs | 0.75rem | 400 | 1.5 |
|
|
137
|
+
| caption | 0.75rem | 400 | — (muted) |
|
|
138
|
+
|
|
139
|
+
### Alignment · weight · color (all responsive)
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
align:left | center | right | justify
|
|
143
|
+
weight:thin | light | normal | medium | semibold | bold | extrabold | black
|
|
144
|
+
color:primary | secondary | accent | muted | destructive | foreground | background
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Color tokens map to CSS variables: `var(--color-primary)`,
|
|
148
|
+
`var(--color-foreground)`, …
|
|
149
|
+
|
|
150
|
+
## Usage examples
|
|
151
|
+
|
|
152
|
+
### Responsive page shell
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<body and-layout="vertical gap:none">
|
|
156
|
+
<nav and-layout="horizontal justify:between align:center p-x:lg p-y:md">
|
|
157
|
+
<a and-text="h6 weight:bold">Logo</a>
|
|
158
|
+
<div and-layout="horizontal gap:sm">
|
|
159
|
+
<a and-text="p-sm">Home</a>
|
|
160
|
+
<a and-text="p-sm">Docs</a>
|
|
161
|
+
</div>
|
|
162
|
+
</nav>
|
|
163
|
+
<main and-layout="vertical gap:xl p:lg p@md:xxl">
|
|
164
|
+
<section and-layout="vertical gap:md">
|
|
165
|
+
<h1 and-text="h1 align:center align@md:left color:foreground">
|
|
166
|
+
Hero Title
|
|
167
|
+
</h1>
|
|
168
|
+
<p and-text="p align:center align@md:left color:muted">Subtitle text</p>
|
|
169
|
+
</section>
|
|
170
|
+
<div and-layout="grid cols:1 cols@sm:2 cols@lg:3 gap:lg">
|
|
171
|
+
<article and-layout="vertical gap:sm p:md">
|
|
172
|
+
<h2 and-text="h5 color:foreground">Card Title</h2>
|
|
173
|
+
<p and-text="p-sm color:muted">Card description</p>
|
|
174
|
+
</article>
|
|
175
|
+
</div>
|
|
176
|
+
</main>
|
|
177
|
+
</body>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 12-column grid
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<section and-layout="grid cols:12 gap:md">
|
|
184
|
+
<div and-layout="span:12 span@md:8">Main content</div>
|
|
185
|
+
<div and-layout="span:12 span@md:4">Sidebar</div>
|
|
186
|
+
</section>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Rules
|
|
190
|
+
|
|
191
|
+
- Use `and-layout` and `and-text` as the primary composition mechanism.
|
|
192
|
+
- Do not mix a utility CSS framework (Tailwind, Bootstrap) with `and-layout`
|
|
193
|
+
tokens on the same element.
|
|
194
|
+
- Responsive tokens use the `@breakpoint` suffix: `cols@md:2`, `align@lg:left`.
|
|
195
|
+
- Color tokens map to CSS custom properties — do not override with hardcoded
|
|
196
|
+
values.
|
|
197
|
+
- `caption` already applies a muted color — do not combine with
|
|
198
|
+
`color:foreground`.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: andersseen-motion
|
|
3
|
+
description:
|
|
4
|
+
'Add attribute-driven animations with @andersseen/motion — scroll/enter,
|
|
5
|
+
hover, and tap triggers via and-motion HTML attributes plus
|
|
6
|
+
initMotion/MotionController. Load when animating element entrances, hover/tap
|
|
7
|
+
feedback, staggered lists, or configuring duration/delay/easing. Respects
|
|
8
|
+
prefers-reduced-motion. Trigger phrases: animation, motion, and-motion,
|
|
9
|
+
fade-up, scroll animation, initMotion, entrance animation.'
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# @andersseen/motion — attribute-driven animation engine
|
|
13
|
+
|
|
14
|
+
Animate the web with HTML attributes + CSS keyframes and a lightweight JS
|
|
15
|
+
controller. Triggers: `enter` (IntersectionObserver), `hover`, `tap`. Respects
|
|
16
|
+
`prefers-reduced-motion` in both CSS and JS.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm i @andersseen/motion
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { initMotion } from '@andersseen/motion';
|
|
28
|
+
import '@andersseen/motion/style.css';
|
|
29
|
+
|
|
30
|
+
// Creates a MotionController + scans the root. Returns a cleanup function.
|
|
31
|
+
const cleanup = initMotion();
|
|
32
|
+
|
|
33
|
+
// Optional options:
|
|
34
|
+
const cleanupWithOpts = initMotion({
|
|
35
|
+
root: document.getElementById('page'),
|
|
36
|
+
threshold: 0.15,
|
|
37
|
+
rootMargin: '0px',
|
|
38
|
+
once: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// On SPA route change / component destroy:
|
|
42
|
+
cleanup();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Advanced: MotionController class
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { MotionController } from '@andersseen/motion';
|
|
49
|
+
|
|
50
|
+
const mc = new MotionController({
|
|
51
|
+
root: document.body,
|
|
52
|
+
threshold: 0.1,
|
|
53
|
+
once: true,
|
|
54
|
+
});
|
|
55
|
+
mc.scan(); // re-scan root (call after dynamic content is added)
|
|
56
|
+
mc.destroy(); // remove all observers and event listeners
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Verified options: `root?` (default `document.body`), `threshold?` (default
|
|
60
|
+
`0.1`), `rootMargin?` (default `'0px'`), `once?` (default `true`).
|
|
61
|
+
|
|
62
|
+
## Attribute reference
|
|
63
|
+
|
|
64
|
+
| Attribute | Values | Notes |
|
|
65
|
+
| --------------------- | -------------------------- | ---------------------------------------------------- |
|
|
66
|
+
| `and-motion` | animation name (required) | Marks the element and sets which animation runs |
|
|
67
|
+
| `and-motion-trigger` | `enter` · `hover` · `tap` | Default `enter`; names ending `-in` also infer enter |
|
|
68
|
+
| `and-motion-duration` | CSS time (`500ms`, `1.2s`) | Sets `--and-motion-duration` on the element |
|
|
69
|
+
| `and-motion-delay` | CSS time (`200ms`) | Sets `--and-motion-delay` on the element |
|
|
70
|
+
| `and-motion-easing` | CSS easing string | Sets `--and-motion-easing` on the element |
|
|
71
|
+
| `and-motion-once` | `true` · `false` | Per-element override of the controller-level `once` |
|
|
72
|
+
|
|
73
|
+
Controller runtime attribute: `and-motion-state=active` is toggled internally
|
|
74
|
+
while an animation is active.
|
|
75
|
+
|
|
76
|
+
## CSS custom properties (global, overridable)
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
--and-motion-duration: 500ms
|
|
80
|
+
--and-motion-delay: 0ms
|
|
81
|
+
--and-motion-easing: cubic-bezier(0.16, 1, 0.3, 1) /* expo-out */
|
|
82
|
+
--and-motion-easing-enter: cubic-bezier(0.16, 1, 0.3, 1)
|
|
83
|
+
--and-motion-easing-exit: cubic-bezier(0.7, 0, 0.84, 0)
|
|
84
|
+
--and-motion-easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1)
|
|
85
|
+
--and-motion-easing-smooth: cubic-bezier(0.25, 0.1, 0.25, 1)
|
|
86
|
+
--and-motion-easing-bounce: cubic-bezier(0.175, 0.885, 0.32, 1.275)
|
|
87
|
+
--and-motion-distance: 20px
|
|
88
|
+
--and-motion-distance-big: 150px
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Animation names
|
|
92
|
+
|
|
93
|
+
- **Fading** (enter by default): `fade`, `fade-up`, `fade-down`, `fade-left`,
|
|
94
|
+
`fade-right` (+ `-big` and corner variants). Explicit: `fade-in`,
|
|
95
|
+
`fade-in-up`, …; exit: `fade-out`, `fade-out-up`, …
|
|
96
|
+
- **Sliding**: `slide-up/down/left/right` (+ `slide-in-*` / `slide-out-*`).
|
|
97
|
+
- **Zooming**: `zoom`, `zoom-up/down/left/right` (+ `zoom-in-*` / `zoom-out-*`).
|
|
98
|
+
- **Bouncing**: `bounce-up/down/left/right` (+ `bounce-in-*` / `bounce-out-*`);
|
|
99
|
+
`bounce-in`, `bounce-out` (750ms).
|
|
100
|
+
- **Flipping**: `flip`, `flip-x`, `flip-y` (+ `flip-in-x/y`, `flip-out-x/y`).
|
|
101
|
+
- **Rotating**: `rotate`, `rotate-down-left/right`, `rotate-up-left/right` (+
|
|
102
|
+
`rotate-in-*` / `rotate-out-*`).
|
|
103
|
+
- **Light speed**: `light-speed-right/left` (+ `light-speed-in/out-*`).
|
|
104
|
+
- **Back** (overshoot from off-screen): `back-down/left/right/up` (+ `back-in-*`
|
|
105
|
+
/ `back-out-*`).
|
|
106
|
+
- **Attention seekers** (use `trigger="hover"` or `trigger="tap"`): `pulse`,
|
|
107
|
+
`rubber-band`, `shake-x`, `shake-y`, `head-shake`, `swing`, `tada`, `wobble`,
|
|
108
|
+
`jello`, `heart-beat`, `flash`, `bounce`, `scale-up`, `scale-down`.
|
|
109
|
+
- **Specials**: `hinge` (2s, origin top-left), `jack-in-the-box`, `roll`,
|
|
110
|
+
`roll-in`, `roll-out`.
|
|
111
|
+
|
|
112
|
+
## Usage examples
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<!-- Scroll-triggered fade-up (once) -->
|
|
116
|
+
<section
|
|
117
|
+
and-motion="fade-up"
|
|
118
|
+
and-motion-duration="700ms"
|
|
119
|
+
and-motion-delay="100ms"
|
|
120
|
+
>
|
|
121
|
+
<h2>Section title</h2>
|
|
122
|
+
</section>
|
|
123
|
+
|
|
124
|
+
<!-- Hover rubber-band attention seeker -->
|
|
125
|
+
<button and-motion="rubber-band" and-motion-trigger="hover">Click me</button>
|
|
126
|
+
|
|
127
|
+
<!-- Tap scale with spring easing -->
|
|
128
|
+
<div
|
|
129
|
+
and-motion="scale-up"
|
|
130
|
+
and-motion-trigger="tap"
|
|
131
|
+
and-motion-easing="cubic-bezier(0.34, 1.56, 0.64, 1)"
|
|
132
|
+
>
|
|
133
|
+
Card
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<!-- Staggered list via delay -->
|
|
137
|
+
<ul>
|
|
138
|
+
<li and-motion="fade-in-up" and-motion-delay="0ms">Item 1</li>
|
|
139
|
+
<li and-motion="fade-in-up" and-motion-delay="100ms">Item 2</li>
|
|
140
|
+
<li and-motion="fade-in-up" and-motion-delay="200ms">Item 3</li>
|
|
141
|
+
</ul>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Angular usage
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// app.config.ts or main.ts
|
|
148
|
+
import { initMotion } from '@andersseen/motion';
|
|
149
|
+
import '@andersseen/motion/style.css';
|
|
150
|
+
|
|
151
|
+
initMotion();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
For OnPush components with dynamic content, call `mc.scan()` after content
|
|
155
|
+
renders.
|
|
156
|
+
|
|
157
|
+
## Rules
|
|
158
|
+
|
|
159
|
+
- Use `and-motion` attributes directly in HTML — no JS required for basic
|
|
160
|
+
animations.
|
|
161
|
+
- Use motion for meaningful feedback (entrance, hover affordance, tap
|
|
162
|
+
confirmation); avoid constant looping animations that distract from content.
|
|
163
|
+
- The experience must be usable without animation (reduced motion is handled
|
|
164
|
+
automatically).
|
|
165
|
+
- Call `cleanup()` / `destroy()` when unmounting SPA views to avoid listener
|
|
166
|
+
leaks.
|