@birdapi/velinstyle 1.2.1 → 1.3.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.
Files changed (156) hide show
  1. package/README.de.md +148 -11
  2. package/README.md +174 -16
  3. package/cli/__fixtures__/atelier-library/showcases/01-login/app.css +1 -0
  4. package/cli/__fixtures__/atelier-library/showcases/01-login/app.js +2 -0
  5. package/cli/__fixtures__/atelier-library/showcases/01-login/index.html +5 -0
  6. package/cli/__fixtures__/atelier-library/showcases/04-pricing/app.css +1 -0
  7. package/cli/__fixtures__/atelier-library/showcases/04-pricing/app.js +2 -0
  8. package/cli/__fixtures__/atelier-library/showcases/04-pricing/index.html +5 -0
  9. package/cli/__fixtures__/atelier-library/showcases/36-calendar/app.css +1 -0
  10. package/cli/__fixtures__/atelier-library/showcases/36-calendar/app.js +2 -0
  11. package/cli/__fixtures__/atelier-library/showcases/36-calendar/index.html +5 -0
  12. package/cli/atelier-catalog.json +1267 -0
  13. package/cli/atelier-formats.js +159 -0
  14. package/cli/atelier.js +382 -0
  15. package/cli/blueprints/empty-state.html +3 -5
  16. package/cli/cli-manifest.json +441 -161
  17. package/cli/docgen/extract-cli.js +2 -1
  18. package/cli/docs-generate.js +9 -0
  19. package/cli/experience.js +173 -0
  20. package/cli/index.js +1384 -361
  21. package/cli/motion.js +738 -0
  22. package/cli/production/component-graph.json +166 -0
  23. package/cli/production/explain.js +52 -0
  24. package/cli/production/extract.js +278 -0
  25. package/cli/production/graph.js +102 -0
  26. package/cli/production/report.js +168 -0
  27. package/cli/production/run.js +355 -0
  28. package/cli/production/trim-css.js +177 -0
  29. package/cli/production/trim-fonts.js +23 -0
  30. package/cli/production/trim-icons.js +38 -0
  31. package/cli/production/trim-js.js +48 -0
  32. package/cli/production/trim-motion.js +22 -0
  33. package/cli/production/trim-themes.js +50 -0
  34. package/cli/production/watch.js +38 -0
  35. package/cli/review.js +48 -1
  36. package/cli/scripts/write-atelier-fixtures.mjs +33 -0
  37. package/cli/security.js +190 -0
  38. package/cli/skills.js +53 -10
  39. package/cli/transparency.js +140 -41
  40. package/cli/workflow.js +32 -17
  41. package/components/index.js +3 -0
  42. package/components/runtime/component-loaders.js +3 -0
  43. package/components/velin-drawer.js +43 -4
  44. package/components/velin-empty-state.js +83 -0
  45. package/components/velin-modal.js +76 -15
  46. package/components/velin-otp-input.js +220 -0
  47. package/components/velin-password-strength.js +147 -0
  48. package/components/velin-sheet.js +49 -4
  49. package/components/velin-theme-toggle.js +15 -1
  50. package/core/a11y/component-contracts.json +391 -255
  51. package/core/attributes/registry.js +1 -1
  52. package/core/meta/knowledge/components.json +75 -3
  53. package/core/motion/analyze.js +38 -0
  54. package/core/motion/blueprint.js +51 -0
  55. package/core/motion/composer.js +114 -0
  56. package/core/motion/data/registry.json +352 -0
  57. package/core/motion/effects.js +17 -1
  58. package/core/motion/index.js +112 -9
  59. package/core/motion/optimize.js +44 -0
  60. package/core/motion/policy.js +77 -0
  61. package/core/motion/registry.js +131 -0
  62. package/core/motion/review.js +59 -0
  63. package/core/motion/scan.js +150 -0
  64. package/core/motion/timeline.js +68 -0
  65. package/core/motion/transitions.js +49 -0
  66. package/core/motion/triggers.js +168 -0
  67. package/core/security/checks/fs.js +92 -0
  68. package/core/security/detect.js +35 -0
  69. package/core/security/engine.js +116 -0
  70. package/core/security/index.js +18 -0
  71. package/core/security/registry.js +85 -0
  72. package/core/security/report/report.js +113 -0
  73. package/core/security/rules/ci/index.js +146 -0
  74. package/core/security/rules/consumer/index.js +174 -0
  75. package/core/security/rules/deps/index.js +182 -0
  76. package/core/security/rules/index.js +24 -0
  77. package/core/security/rules/publish/index.js +230 -0
  78. package/core/security/rules/repo/index.js +143 -0
  79. package/core/security/rules/secrets/index.js +133 -0
  80. package/core/security/score/dependency-health.js +53 -0
  81. package/core/security/score/release-health.js +66 -0
  82. package/core/security/score/score.js +102 -0
  83. package/core/security/timeline/timeline.js +76 -0
  84. package/dist/chunks/attributes-2ORR27KA.js +404 -0
  85. package/dist/chunks/attributes-HK7VIOLA.js +1080 -0
  86. package/dist/chunks/attributes-VRHHVNDO.js +1080 -0
  87. package/dist/chunks/chunk-MYKUI364.js +116 -0
  88. package/dist/chunks/chunk-NEVBPD5T.js +116 -0
  89. package/dist/chunks/chunk-Y6HN7HWX.js +116 -0
  90. package/dist/chunks/runtime-entry.js +1 -1
  91. package/dist/chunks/velin-drawer-A7Q7EBOS.js +162 -0
  92. package/dist/chunks/velin-empty-state-3NTUH2RF.js +81 -0
  93. package/dist/chunks/velin-modal-3MV4FYBK.js +231 -0
  94. package/dist/chunks/velin-otp-input-PSK42MM6.js +207 -0
  95. package/dist/chunks/velin-password-strength-TAXMLSED.js +136 -0
  96. package/dist/chunks/velin-sheet-N2VVYXFP.js +157 -0
  97. package/dist/chunks/velin-theme-toggle-J2NHC7IM.js +304 -0
  98. package/dist/llms.txt +4 -4
  99. package/dist/search-index.json +232 -5
  100. package/dist/velin-agent.json +433 -46
  101. package/dist/velinstyle-components.iife.js +3695 -2272
  102. package/dist/velinstyle-components.js +3698 -2271
  103. package/dist/velinstyle-components.min.js +262 -120
  104. package/dist/velinstyle.css +96 -13
  105. package/dist/velinstyle.d.ts +3 -0
  106. package/dist/velinstyle.min.css +1 -1
  107. package/package.json +19 -4
  108. package/packages/velinstyle-cli-core/package.json +11 -0
  109. package/packages/velinstyle-cli-core/src/config.js +84 -0
  110. package/packages/velinstyle-cli-core/src/contract.js +56 -0
  111. package/packages/velinstyle-cli-core/src/event-bus.js +50 -0
  112. package/packages/velinstyle-cli-core/src/index.js +18 -0
  113. package/packages/velinstyle-cli-core/src/lifecycle.js +33 -0
  114. package/packages/velinstyle-cli-core/src/runner.js +129 -0
  115. package/packages/velinstyle-cli-registry/data/commands.json +1216 -0
  116. package/packages/velinstyle-cli-registry/data/layouts.json +33 -0
  117. package/packages/velinstyle-cli-registry/data/widgets.json +35 -0
  118. package/packages/velinstyle-cli-registry/package.json +13 -0
  119. package/packages/velinstyle-cli-registry/src/index.js +88 -0
  120. package/packages/velinstyle-cli-renderer/package.json +8 -0
  121. package/packages/velinstyle-cli-renderer/src/index.js +286 -0
  122. package/packages/velinstyle-cli-theme/package.json +8 -0
  123. package/packages/velinstyle-cli-theme/src/index.js +84 -0
  124. package/packages/velinstyle-cli-ui/package.json +8 -0
  125. package/packages/velinstyle-cli-ui/src/index.js +34 -0
  126. package/packages/velinstyle-motion/README.md +81 -0
  127. package/packages/velinstyle-motion/package.json +37 -0
  128. package/packages/velinstyle-motion/src/ai/mini-prompt.js +119 -0
  129. package/packages/velinstyle-motion/src/ai/provider.js +59 -0
  130. package/packages/velinstyle-motion/src/ai/providers/pixverse-setup.js +402 -0
  131. package/packages/velinstyle-motion/src/ai/providers/pixverse.js +245 -0
  132. package/packages/velinstyle-motion/src/config.js +257 -0
  133. package/packages/velinstyle-motion/src/export/html-clip.js +141 -0
  134. package/packages/velinstyle-motion/src/index.js +304 -0
  135. package/packages/velinstyle-motion/src/jobs/cache.js +30 -0
  136. package/packages/velinstyle-motion/src/jobs/queue.js +69 -0
  137. package/packages/velinstyle-motion/src/jobs/usage.js +53 -0
  138. package/packages/velinstyle-motion/src/local/effects.js +139 -0
  139. package/packages/velinstyle-motion/src/local/engine.js +96 -0
  140. package/packages/velinstyle-motion/src/providers-catalog.js +44 -0
  141. package/packages/velinstyle-motion/src/registry/presets.js +25 -0
  142. package/packages/velinstyle-motion/src/registry/presets.json +85 -0
  143. package/packages/velinstyle-motion/src/ux/cost-gate.js +37 -0
  144. package/packages/velinstyle-motion/src/ux/pixverse-gate.js +153 -0
  145. package/packages/velinstyle-motion/src/ux/wizard.js +171 -0
  146. package/packages/velinstyle-motion/src/validate-image.js +91 -0
  147. package/packages/velinstyle-skills/catalog.json +1 -1
  148. package/packages/velinstyle-skills/registry.json +1 -142
  149. package/packages/velinstyle-skills/skills/velin-motion-reduced-safe/SKILL.md +1 -1
  150. package/packages/velinstyle-skills/skills/velin-motion-reveal-feedback/SKILL.md +1 -1
  151. package/src/components/data-table.css +19 -0
  152. package/src/components/empty-auth.css +33 -0
  153. package/src/components/table.css +16 -6
  154. package/src/tokens/motion.css +7 -0
  155. package/src/utilities/scroll-animation.css +66 -0
  156. package/src/velinstyle.css +1 -0
@@ -0,0 +1,352 @@
1
+ {
2
+ "schema": "velinstyle.motion.registry",
3
+ "version": 1,
4
+ "presets": [
5
+ {
6
+ "id": "fade",
7
+ "title": "Fade",
8
+ "description": "Opacity entrance; layout-safe default reveal.",
9
+ "kind": "preset",
10
+ "category": "hero",
11
+ "tags": ["entrance"],
12
+ "duration": 400,
13
+ "fps": "60",
14
+ "reducedMotion": true,
15
+ "layoutSafe": true,
16
+ "status": "stable",
17
+ "cssClass": "velin-animate-on-scroll--fade",
18
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
19
+ },
20
+ {
21
+ "id": "slide",
22
+ "title": "Slide Up",
23
+ "description": "Slide from below into view.",
24
+ "kind": "preset",
25
+ "category": "cards",
26
+ "tags": ["entrance", "slide"],
27
+ "duration": 500,
28
+ "fps": "60",
29
+ "reducedMotion": true,
30
+ "layoutSafe": true,
31
+ "status": "stable",
32
+ "cssClass": "velin-animate-on-scroll--slide-up",
33
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
34
+ },
35
+ {
36
+ "id": "slide-down",
37
+ "title": "Slide Down",
38
+ "description": "Slide from above into view.",
39
+ "kind": "preset",
40
+ "category": "navigation",
41
+ "tags": ["entrance", "slide"],
42
+ "duration": 500,
43
+ "reducedMotion": true,
44
+ "layoutSafe": true,
45
+ "status": "stable",
46
+ "cssClass": "velin-animate-on-scroll--slide-down",
47
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
48
+ },
49
+ {
50
+ "id": "slide-left",
51
+ "title": "Slide Left",
52
+ "description": "Slide from the inline-end.",
53
+ "kind": "preset",
54
+ "category": "lists",
55
+ "tags": ["entrance", "slide"],
56
+ "duration": 500,
57
+ "reducedMotion": true,
58
+ "layoutSafe": true,
59
+ "status": "stable",
60
+ "cssClass": "velin-animate-on-scroll--slide-left",
61
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
62
+ },
63
+ {
64
+ "id": "slide-right",
65
+ "title": "Slide Right",
66
+ "description": "Slide from the inline-start.",
67
+ "kind": "preset",
68
+ "category": "lists",
69
+ "tags": ["entrance", "slide"],
70
+ "duration": 500,
71
+ "reducedMotion": true,
72
+ "layoutSafe": true,
73
+ "status": "stable",
74
+ "cssClass": "velin-animate-on-scroll--slide-right",
75
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
76
+ },
77
+ {
78
+ "id": "zoom",
79
+ "title": "Zoom / Scale",
80
+ "description": "Scale-in entrance for cards and media.",
81
+ "kind": "preset",
82
+ "category": "media",
83
+ "tags": ["entrance", "scale"],
84
+ "duration": 450,
85
+ "reducedMotion": true,
86
+ "layoutSafe": true,
87
+ "status": "stable",
88
+ "cssClass": "velin-animate-on-scroll--scale",
89
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
90
+ },
91
+ {
92
+ "id": "blur",
93
+ "title": "Blur In",
94
+ "description": "Soft fade/blur entrance (maps to fade-in utility).",
95
+ "kind": "preset",
96
+ "category": "overlay",
97
+ "tags": ["entrance"],
98
+ "duration": 500,
99
+ "reducedMotion": true,
100
+ "layoutSafe": true,
101
+ "status": "beta",
102
+ "cssClass": "velin-animate-fade-in",
103
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
104
+ },
105
+ {
106
+ "id": "flip",
107
+ "title": "Flip / Scale In",
108
+ "description": "Attention scale-in for emphasis.",
109
+ "kind": "preset",
110
+ "category": "feedback",
111
+ "tags": ["attention"],
112
+ "duration": 400,
113
+ "reducedMotion": true,
114
+ "layoutSafe": true,
115
+ "status": "beta",
116
+ "cssClass": "velin-animate-scale-in",
117
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
118
+ },
119
+ {
120
+ "id": "lift",
121
+ "title": "Hover Lift",
122
+ "description": "Subtle lift on hover for interactive cards and buttons.",
123
+ "kind": "preset",
124
+ "category": "buttons",
125
+ "tags": ["hover"],
126
+ "duration": 200,
127
+ "reducedMotion": true,
128
+ "layoutSafe": true,
129
+ "status": "stable",
130
+ "cssClass": "velin-animate-hover",
131
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
132
+ },
133
+ {
134
+ "id": "pulse",
135
+ "title": "Pulse",
136
+ "description": "Attention pulse; prefer finite loops under performance policy.",
137
+ "kind": "preset",
138
+ "category": "feedback",
139
+ "tags": ["attention"],
140
+ "duration": 1000,
141
+ "reducedMotion": true,
142
+ "layoutSafe": true,
143
+ "status": "stable",
144
+ "cssClass": "velin-animate-pulse",
145
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
146
+ },
147
+ {
148
+ "id": "shake",
149
+ "title": "Shake",
150
+ "description": "Error/attention shake feedback.",
151
+ "kind": "preset",
152
+ "category": "forms",
153
+ "tags": ["attention", "feedback"],
154
+ "duration": 400,
155
+ "reducedMotion": true,
156
+ "layoutSafe": true,
157
+ "status": "stable",
158
+ "cssClass": "velin-animate-shake",
159
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
160
+ },
161
+ {
162
+ "id": "bounce",
163
+ "title": "Bounce",
164
+ "description": "Playful bounce entrance or attention.",
165
+ "kind": "preset",
166
+ "category": "feedback",
167
+ "tags": ["attention"],
168
+ "duration": 600,
169
+ "reducedMotion": true,
170
+ "layoutSafe": true,
171
+ "status": "stable",
172
+ "cssClass": "velin-animate-bounce",
173
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
174
+ },
175
+ {
176
+ "id": "shimmer",
177
+ "title": "Shimmer",
178
+ "description": "Loading shimmer surface (skeleton companion).",
179
+ "kind": "preset",
180
+ "category": "loading",
181
+ "tags": ["loading"],
182
+ "duration": 1200,
183
+ "reducedMotion": true,
184
+ "layoutSafe": true,
185
+ "status": "stable",
186
+ "cssClass": "velin-skeleton",
187
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
188
+ },
189
+ {
190
+ "id": "heroReveal",
191
+ "title": "Hero Reveal",
192
+ "description": "Staggered entrance for hero content; layout-safe; reduced-motion fallback.",
193
+ "kind": "preset",
194
+ "category": "hero",
195
+ "tags": ["entrance", "stagger"],
196
+ "duration": 600,
197
+ "fps": "60",
198
+ "reducedMotion": true,
199
+ "layoutSafe": true,
200
+ "status": "stable",
201
+ "cssClass": "velin-animate-on-scroll--fade",
202
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
203
+ },
204
+ {
205
+ "id": "parallax",
206
+ "title": "Parallax",
207
+ "description": "Scroll-driven parallax shift.",
208
+ "kind": "preset",
209
+ "category": "media",
210
+ "tags": ["scroll"],
211
+ "duration": 0,
212
+ "reducedMotion": true,
213
+ "layoutSafe": false,
214
+ "status": "stable",
215
+ "cssClass": "velin-parallax",
216
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
217
+ },
218
+ {
219
+ "id": "fadeOut",
220
+ "title": "Fade Out",
221
+ "description": "Exit fade (planned composition with timelines).",
222
+ "kind": "preset",
223
+ "category": "overlay",
224
+ "tags": ["exit"],
225
+ "duration": 300,
226
+ "reducedMotion": true,
227
+ "layoutSafe": true,
228
+ "status": "beta",
229
+ "cssClass": "velin-animate-fade-out",
230
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
231
+ }
232
+ ],
233
+ "timelines": [
234
+ {
235
+ "id": "hero-intro",
236
+ "title": "Hero Intro",
237
+ "description": "Title → subtitle → buttons → image",
238
+ "kind": "timeline",
239
+ "category": "hero",
240
+ "steps": ["title", "subtitle", "buttons", "image"],
241
+ "status": "beta",
242
+ "compatibility": { "cssOnly": false, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
243
+ },
244
+ {
245
+ "id": "card-stagger",
246
+ "title": "Card Stagger",
247
+ "description": "Sequential card entrance labels.",
248
+ "kind": "timeline",
249
+ "category": "cards",
250
+ "steps": ["card-1", "card-2", "card-3"],
251
+ "status": "beta",
252
+ "compatibility": { "cssOnly": false, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
253
+ }
254
+ ],
255
+ "transitions": [
256
+ {
257
+ "id": "cross-fade",
258
+ "title": "Cross Fade",
259
+ "description": "Page/view cross-fade (View Transition friendly).",
260
+ "kind": "transition",
261
+ "category": "page",
262
+ "status": "planned",
263
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
264
+ },
265
+ {
266
+ "id": "modal-enter",
267
+ "title": "Modal Enter",
268
+ "description": "Overlay modal entrance transition.",
269
+ "kind": "transition",
270
+ "category": "modal",
271
+ "status": "planned",
272
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
273
+ },
274
+ {
275
+ "id": "drawer-enter",
276
+ "title": "Drawer Enter",
277
+ "description": "Drawer slide transition.",
278
+ "kind": "transition",
279
+ "category": "drawer",
280
+ "status": "planned",
281
+ "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
282
+ }
283
+ ],
284
+ "physics": [
285
+ {
286
+ "id": "spring",
287
+ "title": "Spring",
288
+ "description": "Spring easing token mapping (runtime simulation later).",
289
+ "kind": "physics",
290
+ "category": "feedback",
291
+ "status": "planned",
292
+ "token": "--velin-ease-spring",
293
+ "compatibility": { "cssOnly": true, "runtime": false, "webComponents": false, "studio": true, "production": true, "review": true, "cli": true }
294
+ },
295
+ {
296
+ "id": "elastic",
297
+ "title": "Elastic",
298
+ "description": "Elastic easing token mapping.",
299
+ "kind": "physics",
300
+ "category": "feedback",
301
+ "status": "planned",
302
+ "token": "--velin-ease-elastic",
303
+ "compatibility": { "cssOnly": true, "runtime": false, "webComponents": false, "studio": true, "production": true, "review": true, "cli": true }
304
+ }
305
+ ],
306
+ "composers": [
307
+ {
308
+ "id": "sequence",
309
+ "title": "Sequence Composer",
310
+ "description": "Ordered fade/wait/slide composition API.",
311
+ "kind": "composer",
312
+ "category": "page",
313
+ "status": "planned",
314
+ "compatibility": { "cssOnly": false, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true }
315
+ }
316
+ ],
317
+ "triggers": [
318
+ { "id": "load", "title": "Load", "description": "Start when document/module initializes.", "kind": "trigger", "category": "page", "status": "stable", "compatibility": { "cssOnly": false, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
319
+ { "id": "visible", "title": "Visible", "description": "Start when element enters the viewport (IntersectionObserver).", "kind": "trigger", "category": "page", "status": "stable", "compatibility": { "cssOnly": false, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
320
+ { "id": "hidden", "title": "Hidden", "description": "Fire when element leaves the viewport. (Planned — runtime falls back to visible.)", "kind": "trigger", "category": "page", "status": "planned", "compatibility": { "cssOnly": false, "runtime": false, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
321
+ { "id": "hover", "title": "Hover", "description": "Pointer enter / hover.", "kind": "trigger", "category": "buttons", "status": "stable", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
322
+ { "id": "focus", "title": "Focus", "description": "Keyboard/pointer focus.", "kind": "trigger", "category": "forms", "status": "stable", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
323
+ { "id": "click", "title": "Click", "description": "Pointer activation.", "kind": "trigger", "category": "buttons", "status": "stable", "compatibility": { "cssOnly": false, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
324
+ { "id": "scroll", "title": "Scroll", "description": "Scroll-linked or scroll-progress trigger.", "kind": "trigger", "category": "page", "status": "stable", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
325
+ { "id": "idle", "title": "Idle", "description": "After user idle timeout. (Planned — runtime falls back to visible.)", "kind": "trigger", "category": "feedback", "status": "planned", "compatibility": { "cssOnly": false, "runtime": false, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
326
+ { "id": "media", "title": "Media", "description": "Match media query condition. (Planned — runtime falls back to visible.)", "kind": "trigger", "category": "page", "status": "planned", "compatibility": { "cssOnly": false, "runtime": false, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
327
+ { "id": "container", "title": "Container", "description": "Container query / size trigger. (Planned — runtime falls back to visible.)", "kind": "trigger", "category": "cards", "status": "planned", "compatibility": { "cssOnly": false, "runtime": false, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
328
+ { "id": "theme", "title": "Theme", "description": "Theme change trigger. (Planned — runtime falls back to visible.)", "kind": "trigger", "category": "page", "status": "planned", "compatibility": { "cssOnly": false, "runtime": false, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
329
+ { "id": "custom", "title": "Custom", "description": "Custom event name via velin-trigger-event. (Planned — runtime falls back to visible.)", "kind": "trigger", "category": "page", "status": "planned", "compatibility": { "cssOnly": false, "runtime": false, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } }
330
+ ],
331
+ "policies": [
332
+ { "id": "safe", "title": "Safe", "description": "Default layout-safe motion with capped durations.", "kind": "policy", "category": "page", "status": "stable", "maxDurationMs": 800, "allowInfinite": false, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
333
+ { "id": "reduced", "title": "Reduced", "description": "Honors prefers-reduced-motion first; shorten or skip decorative motion.", "kind": "policy", "category": "page", "status": "stable", "maxDurationMs": 200, "forceReduced": true, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
334
+ { "id": "marketing", "title": "Marketing", "description": "Expressive hero motion allowed within caps.", "kind": "policy", "category": "hero", "status": "stable", "maxDurationMs": 1200, "allowInfinite": false, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
335
+ { "id": "minimal", "title": "Minimal", "description": "Very little motion; feedback only.", "kind": "policy", "category": "page", "status": "stable", "maxDurationMs": 300, "allowInfinite": false, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
336
+ { "id": "accessibility", "title": "Accessibility", "description": "Strict reduced-motion + focus-safe interactions.", "kind": "policy", "category": "page", "status": "stable", "maxDurationMs": 200, "forceReduced": true, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
337
+ { "id": "performance", "title": "Performance", "description": "FPS-friendly; ban infinite decorative loops.", "kind": "policy", "category": "page", "status": "stable", "maxDurationMs": 600, "allowInfinite": false, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
338
+ { "id": "disabled", "title": "Disabled", "description": "All motion off.", "kind": "policy", "category": "page", "status": "stable", "disabled": true, "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } }
339
+ ],
340
+ "blueprints": [
341
+ { "id": "landing", "title": "Landing", "description": "Hero reveal + staggered sections + CTA hover.", "kind": "blueprint", "category": "hero", "status": "beta", "presets": ["heroReveal", "fade", "lift"], "timeline": "hero-intro", "policy": "marketing", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
342
+ { "id": "dashboard", "title": "Dashboard", "description": "Minimal card stagger for admin shells.", "kind": "blueprint", "category": "cards", "status": "beta", "presets": ["fade", "slide"], "timeline": "card-stagger", "policy": "minimal", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
343
+ { "id": "pricing", "title": "Pricing", "description": "Pricing cards with stagger and lift.", "kind": "blueprint", "category": "cards", "status": "beta", "presets": ["slide", "lift"], "policy": "marketing", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
344
+ { "id": "portfolio", "title": "Portfolio", "description": "Media zoom + parallax-safe reveals.", "kind": "blueprint", "category": "media", "status": "beta", "presets": ["zoom", "fade"], "policy": "marketing", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
345
+ { "id": "shop", "title": "Shop", "description": "Product cards and feedback pulses.", "kind": "blueprint", "category": "cards", "status": "planned", "presets": ["fade", "lift"], "policy": "safe", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
346
+ { "id": "forum", "title": "Forum", "description": "List slides and form feedback.", "kind": "blueprint", "category": "lists", "status": "planned", "presets": ["slide", "shake"], "policy": "safe", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
347
+ { "id": "docs", "title": "Docs", "description": "Minimal fade for documentation pages.", "kind": "blueprint", "category": "page", "status": "beta", "presets": ["fade"], "policy": "minimal", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
348
+ { "id": "blog", "title": "Blog", "description": "Article hero fade and card slides.", "kind": "blueprint", "category": "hero", "status": "planned", "presets": ["fade", "slide"], "policy": "safe", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
349
+ { "id": "crm", "title": "CRM", "description": "Table-safe minimal motion.", "kind": "blueprint", "category": "tables", "status": "planned", "presets": ["fade"], "policy": "performance", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } },
350
+ { "id": "login", "title": "Login", "description": "Form feedback and focus-safe motion.", "kind": "blueprint", "category": "forms", "status": "beta", "presets": ["fade", "shake"], "policy": "accessibility", "compatibility": { "cssOnly": true, "runtime": true, "webComponents": true, "studio": true, "production": true, "review": true, "cli": true } }
351
+ ]
352
+ }
@@ -9,16 +9,24 @@ const EFFECT_MAP = {
9
9
  'slide-left': ['velin-animate-on-scroll', 'velin-animate-on-scroll--slide-left'],
10
10
  'slide-right': ['velin-animate-on-scroll', 'velin-animate-on-scroll--slide-right'],
11
11
  scale: ['velin-animate-on-scroll', 'velin-animate-on-scroll--scale'],
12
+ zoom: ['velin-animate-on-scroll', 'velin-animate-on-scroll--scale'],
12
13
  parallax: ['velin-parallax'],
13
14
  'parallax-slow': ['velin-parallax', 'velin-parallax--slow'],
14
15
  hover: ['velin-animate-hover'],
15
16
  'hover-lift': ['velin-animate-hover'],
17
+ lift: ['velin-animate-hover'],
16
18
  flip: ['velin-animate-scale-in'],
17
19
  blur: ['velin-animate-fade-in'],
20
+ pulse: ['velin-animate-pulse'],
21
+ shake: ['velin-animate-shake'],
22
+ bounce: ['velin-animate-bounce'],
23
+ shimmer: ['velin-skeleton'],
24
+ heroReveal: ['velin-animate-on-scroll', 'velin-animate-on-scroll--fade'],
25
+ fadeOut: ['velin-animate-fade-out'],
18
26
  };
19
27
 
20
28
  /**
21
- * Apply motion effect classes from velin-* attribute values.
29
+ * Apply motion effect classes from velin-* attribute values or velin-motion preset.
22
30
  * @param {HTMLElement} el
23
31
  * @param {Record<string, string>} attrs keyed by effect name
24
32
  */
@@ -26,6 +34,12 @@ export function applyEffects(el, attrs = {}) {
26
34
  const classes = new Set();
27
35
  for (const [name, value] of Object.entries(attrs)) {
28
36
  if (value === 'false' || value === 'off') continue;
37
+ if (name === 'motion' && value && value !== 'true') {
38
+ const presetKey = value;
39
+ const mapped = EFFECT_MAP[presetKey];
40
+ if (mapped) mapped.forEach((c) => classes.add(c));
41
+ continue;
42
+ }
29
43
  const mapped = EFFECT_MAP[name];
30
44
  if (mapped) mapped.forEach((c) => classes.add(c));
31
45
  if (name === 'slide' && value && value !== 'true' && value !== '') {
@@ -52,3 +66,5 @@ export function prefersReducedMotion() {
52
66
  window.matchMedia('(prefers-reduced-motion: reduce)').matches
53
67
  );
54
68
  }
69
+
70
+ export { EFFECT_MAP };
@@ -2,24 +2,62 @@ import { observeInView, disconnectInViewObserver } from './scheduler.js';
2
2
  import { applyEffects, markVisible, prefersReducedMotion, VISIBLE_CLASS } from './effects.js';
3
3
  import { enhanceStagger } from './stagger.js';
4
4
  import { bindSmoothScroll } from './scroll.js';
5
+ import { armMotionElement, readTrigger } from './triggers.js';
6
+ import { applyMotionVars, resolvePolicy, shouldDisableMotion } from './policy.js';
7
+ import { enhanceTimelines } from './timeline.js';
8
+ import { enhanceSequences, Motion } from './composer.js';
9
+ import {
10
+ loadMotionRegistry,
11
+ listPresets,
12
+ listPolicies,
13
+ catalogSummary,
14
+ getPreset,
15
+ resolvePresetId,
16
+ } from './registry.js';
5
17
 
6
- const MOTION_ATTRS = ['velin-reveal', 'velin-fade', 'velin-slide', 'velin-scale', 'velin-parallax', 'velin-hover'];
18
+ const LEGACY_ATTRS = ['velin-reveal', 'velin-fade', 'velin-slide', 'velin-scale', 'velin-parallax', 'velin-hover'];
7
19
 
8
20
  let teardownFns = [];
9
21
 
10
22
  /**
11
- * Initialize motion system: in-view reveals, stagger, smooth scroll anchors.
23
+ * Create a motion engine bound to an optional policy.
24
+ * @param {{ policy?: string }} [options]
25
+ */
26
+ export function createMotionEngine(options = {}) {
27
+ const policy = resolvePolicy(options.policy || 'safe');
28
+ return {
29
+ policy,
30
+ registry: () => loadMotionRegistry(),
31
+ catalog: catalogSummary,
32
+ listPresets,
33
+ listPolicies,
34
+ init: (opts = {}) => initMotion({ ...opts, policy: policy.id }),
35
+ Motion,
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Initialize motion system: unified velin-motion + triggers + legacy attrs.
12
41
  * @param {object} [options]
13
42
  * @param {HTMLElement|Document} [options.root]
14
43
  * @param {string} [options.selector]
44
+ * @param {string} [options.policy]
15
45
  */
16
46
  export function initMotion(options = {}) {
17
47
  const root = options.root || (typeof document !== 'undefined' ? document : null);
18
48
  if (!root) return () => {};
19
49
 
50
+ const policy = resolvePolicy(
51
+ options.policy
52
+ || root.documentElement?.getAttribute?.('data-velin-motion-policy')
53
+ || root.querySelector?.('[data-velin-motion-policy]')?.getAttribute('data-velin-motion-policy')
54
+ || 'safe',
55
+ );
56
+
20
57
  const selector =
21
58
  options.selector ||
22
59
  [
60
+ '[velin-motion]',
23
61
  '[velin-reveal]',
24
62
  '[velin-fade]',
25
63
  '[velin-slide]',
@@ -30,32 +68,48 @@ export function initMotion(options = {}) {
30
68
  ].join(',');
31
69
 
32
70
  const elements = root.querySelectorAll(selector);
33
- const reduced = prefersReducedMotion();
71
+ const reduced = shouldDisableMotion(policy) || prefersReducedMotion();
34
72
 
35
73
  for (const el of elements) {
36
74
  if (el.dataset.velinMotionInit) continue;
37
75
  el.dataset.velinMotionInit = '1';
38
76
 
77
+ applyMotionVars(el, policy);
78
+
39
79
  const attrs = {};
40
- for (const name of MOTION_ATTRS) {
80
+ const motionPreset = el.getAttribute('velin-motion');
81
+ if (motionPreset) {
82
+ attrs.motion = motionPreset;
83
+ const resolved = resolvePresetId(motionPreset);
84
+ if (resolved?.id) attrs[resolved.id] = 'true';
85
+ }
86
+ for (const name of LEGACY_ATTRS) {
41
87
  if (el.hasAttribute(name)) attrs[name.replace('velin-', '')] = el.getAttribute(name) || 'true';
42
88
  }
43
89
  applyEffects(el, attrs);
44
90
 
45
- if (reduced) {
91
+ if (reduced || el.dataset.velinMotion === 'off') {
46
92
  markVisible(el);
47
93
  continue;
48
94
  }
49
95
 
50
- const stop = observeInView(el, (node) => markVisible(node));
96
+ const stop = armMotionElement(el, () => applyEffects(el, attrs));
51
97
  teardownFns.push(stop);
52
98
  }
53
99
 
54
100
  enhanceStagger(root);
55
101
  bindSmoothScroll(root);
102
+ enhanceTimelines(root);
103
+ enhanceSequences(root);
56
104
 
57
105
  return () => {
58
- teardownFns.forEach((fn) => fn());
106
+ teardownFns.forEach((fn) => {
107
+ try {
108
+ fn();
109
+ } catch {
110
+ /* ignore */
111
+ }
112
+ });
59
113
  teardownFns = [];
60
114
  disconnectInViewObserver();
61
115
  };
@@ -69,8 +123,57 @@ export function initReveal(options = {}) {
69
123
  });
70
124
  }
71
125
 
72
- export const velinMotion = { init: initMotion, observe: observeInView, markVisible, VISIBLE_CLASS };
126
+ export const velinMotion = {
127
+ init: initMotion,
128
+ observe: observeInView,
129
+ markVisible,
130
+ VISIBLE_CLASS,
131
+ createEngine: createMotionEngine,
132
+ readTrigger,
133
+ };
134
+
73
135
  export { observeInView, disconnectInViewObserver } from './scheduler.js';
74
- export { applyEffects, markVisible, prefersReducedMotion, VISIBLE_CLASS } from './effects.js';
136
+ export { applyEffects, markVisible, prefersReducedMotion, VISIBLE_CLASS, EFFECT_MAP } from './effects.js';
75
137
  export { enhanceStagger, applyStagger } from './stagger.js';
76
138
  export { smoothScrollTo, bindSmoothScroll } from './scroll.js';
139
+ export {
140
+ loadMotionRegistry,
141
+ listPresets,
142
+ listPolicies,
143
+ listTriggers,
144
+ listBlueprints,
145
+ listTimelines,
146
+ listMotion,
147
+ getPreset,
148
+ getPolicy,
149
+ getTrigger,
150
+ getTimeline,
151
+ getBlueprint,
152
+ catalogSummary,
153
+ resolvePresetId,
154
+ NAMESPACES,
155
+ } from './registry.js';
156
+ export {
157
+ bindTrigger,
158
+ readTrigger,
159
+ armMotionElement,
160
+ TRIGGER_V1,
161
+ TRIGGER_V2,
162
+ ALL_TRIGGERS,
163
+ } from './triggers.js';
164
+ export {
165
+ resolvePolicy,
166
+ listMotionPolicies,
167
+ shouldDisableMotion,
168
+ capDuration,
169
+ validatePolicy,
170
+ applyMotionVars,
171
+ } from './policy.js';
172
+ export { scanMotionHtml, doctorMotionHtml, collectMotionElements } from './scan.js';
173
+ export { analyzeMotionHtml } from './analyze.js';
174
+ export { runTimeline, enhanceTimelines } from './timeline.js';
175
+ export { Motion, sequence, fade, slide, wait, rotate, blur, preset, enhanceSequences } from './composer.js';
176
+ export { runViewTransition, applyTransitionHint, getTransitionPreset } from './transitions.js';
177
+ export { emitMotionBlueprint } from './blueprint.js';
178
+ export { optimizeMotionHtml } from './optimize.js';
179
+ export { reviewMotionHtml } from './review.js';
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Safe motion optimize — cap durations, strip infinite where safe.
3
+ * @param {string} html
4
+ * @param {{ write?: boolean, maxDuration?: number }} [opts]
5
+ */
6
+ export function optimizeMotionHtml(html, opts = {}) {
7
+ const max = opts.maxDuration ?? 800;
8
+ let next = String(html || '');
9
+ const changes = [];
10
+
11
+ next = next.replace(/velin-duration\s*=\s*["'](\d+)["']/gi, (full, n) => {
12
+ const v = Number(n);
13
+ if (v > max) {
14
+ changes.push(`capped duration ${v} → ${max}`);
15
+ return `velin-duration="${max}"`;
16
+ }
17
+ return full;
18
+ });
19
+
20
+ next = next.replace(/velin-delay\s*=\s*["'](\d+)["']/gi, (full, n) => {
21
+ const v = Number(n);
22
+ if (v > 500) {
23
+ changes.push(`capped delay ${v} → 500`);
24
+ return `velin-delay="500"`;
25
+ }
26
+ return full;
27
+ });
28
+
29
+ const beforeInf = next;
30
+ next = next.replace(/\s*velin-animate[^\s"']*--infinite/gi, (m) => {
31
+ changes.push(`removed infinite modifier ${m.trim()}`);
32
+ return '';
33
+ });
34
+ if (next !== beforeInf && !changes.some((c) => c.includes('infinite'))) {
35
+ changes.push('stripped infinite animation classes');
36
+ }
37
+
38
+ return {
39
+ ok: true,
40
+ changed: changes.length > 0,
41
+ changes,
42
+ html: next,
43
+ };
44
+ }