@birdapi/velinstyle 1.2.2 → 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 (109) hide show
  1. package/README.de.md +18 -4
  2. package/README.md +42 -7
  3. package/cli/cli-manifest.json +441 -174
  4. package/cli/docgen/extract-cli.js +2 -1
  5. package/cli/docs-generate.js +9 -0
  6. package/cli/experience.js +173 -0
  7. package/cli/index.js +1294 -417
  8. package/cli/motion.js +738 -0
  9. package/cli/production/extract.js +46 -6
  10. package/cli/production/report.js +104 -14
  11. package/cli/production/run.js +44 -1
  12. package/cli/security.js +190 -0
  13. package/cli/skills.js +53 -10
  14. package/cli/transparency.js +140 -41
  15. package/cli/workflow.js +32 -17
  16. package/components/velin-theme-toggle.js +15 -1
  17. package/core/a11y/component-contracts.json +391 -274
  18. package/core/attributes/registry.js +1 -1
  19. package/core/motion/analyze.js +38 -0
  20. package/core/motion/blueprint.js +51 -0
  21. package/core/motion/composer.js +114 -0
  22. package/core/motion/data/registry.json +352 -0
  23. package/core/motion/effects.js +17 -1
  24. package/core/motion/index.js +112 -9
  25. package/core/motion/optimize.js +44 -0
  26. package/core/motion/policy.js +77 -0
  27. package/core/motion/registry.js +131 -0
  28. package/core/motion/review.js +59 -0
  29. package/core/motion/scan.js +150 -0
  30. package/core/motion/timeline.js +68 -0
  31. package/core/motion/transitions.js +49 -0
  32. package/core/motion/triggers.js +168 -0
  33. package/core/security/checks/fs.js +92 -0
  34. package/core/security/detect.js +35 -0
  35. package/core/security/engine.js +116 -0
  36. package/core/security/index.js +18 -0
  37. package/core/security/registry.js +85 -0
  38. package/core/security/report/report.js +113 -0
  39. package/core/security/rules/ci/index.js +146 -0
  40. package/core/security/rules/consumer/index.js +174 -0
  41. package/core/security/rules/deps/index.js +182 -0
  42. package/core/security/rules/index.js +24 -0
  43. package/core/security/rules/publish/index.js +230 -0
  44. package/core/security/rules/repo/index.js +143 -0
  45. package/core/security/rules/secrets/index.js +133 -0
  46. package/core/security/score/dependency-health.js +53 -0
  47. package/core/security/score/release-health.js +66 -0
  48. package/core/security/score/score.js +102 -0
  49. package/core/security/timeline/timeline.js +76 -0
  50. package/dist/chunks/attributes-HK7VIOLA.js +1080 -0
  51. package/dist/chunks/attributes-VRHHVNDO.js +1080 -0
  52. package/dist/chunks/chunk-MYKUI364.js +116 -0
  53. package/dist/chunks/chunk-NEVBPD5T.js +116 -0
  54. package/dist/chunks/runtime-entry.js +1 -1
  55. package/dist/chunks/velin-theme-toggle-J2NHC7IM.js +304 -0
  56. package/dist/llms.txt +2 -2
  57. package/dist/search-index.json +166 -2
  58. package/dist/velin-agent.json +156 -32
  59. package/dist/velinstyle-components.iife.js +862 -17
  60. package/dist/velinstyle-components.js +862 -17
  61. package/dist/velinstyle-components.min.js +126 -126
  62. package/dist/velinstyle.css +42 -7
  63. package/dist/velinstyle.min.css +1 -1
  64. package/package.json +158 -143
  65. package/packages/velinstyle-cli-core/package.json +11 -0
  66. package/packages/velinstyle-cli-core/src/config.js +84 -0
  67. package/packages/velinstyle-cli-core/src/contract.js +56 -0
  68. package/packages/velinstyle-cli-core/src/event-bus.js +50 -0
  69. package/packages/velinstyle-cli-core/src/index.js +18 -0
  70. package/packages/velinstyle-cli-core/src/lifecycle.js +33 -0
  71. package/packages/velinstyle-cli-core/src/runner.js +129 -0
  72. package/packages/velinstyle-cli-registry/data/commands.json +1216 -0
  73. package/packages/velinstyle-cli-registry/data/layouts.json +33 -0
  74. package/packages/velinstyle-cli-registry/data/widgets.json +35 -0
  75. package/packages/velinstyle-cli-registry/package.json +13 -0
  76. package/packages/velinstyle-cli-registry/src/index.js +88 -0
  77. package/packages/velinstyle-cli-renderer/package.json +8 -0
  78. package/packages/velinstyle-cli-renderer/src/index.js +286 -0
  79. package/packages/velinstyle-cli-theme/package.json +8 -0
  80. package/packages/velinstyle-cli-theme/src/index.js +84 -0
  81. package/packages/velinstyle-cli-ui/package.json +8 -0
  82. package/packages/velinstyle-cli-ui/src/index.js +34 -0
  83. package/packages/velinstyle-motion/README.md +81 -0
  84. package/packages/velinstyle-motion/package.json +37 -0
  85. package/packages/velinstyle-motion/src/ai/mini-prompt.js +119 -0
  86. package/packages/velinstyle-motion/src/ai/provider.js +59 -0
  87. package/packages/velinstyle-motion/src/ai/providers/pixverse-setup.js +402 -0
  88. package/packages/velinstyle-motion/src/ai/providers/pixverse.js +245 -0
  89. package/packages/velinstyle-motion/src/config.js +257 -0
  90. package/packages/velinstyle-motion/src/export/html-clip.js +141 -0
  91. package/packages/velinstyle-motion/src/index.js +304 -0
  92. package/packages/velinstyle-motion/src/jobs/cache.js +30 -0
  93. package/packages/velinstyle-motion/src/jobs/queue.js +69 -0
  94. package/packages/velinstyle-motion/src/jobs/usage.js +53 -0
  95. package/packages/velinstyle-motion/src/local/effects.js +139 -0
  96. package/packages/velinstyle-motion/src/local/engine.js +96 -0
  97. package/packages/velinstyle-motion/src/providers-catalog.js +44 -0
  98. package/packages/velinstyle-motion/src/registry/presets.js +25 -0
  99. package/packages/velinstyle-motion/src/registry/presets.json +85 -0
  100. package/packages/velinstyle-motion/src/ux/cost-gate.js +37 -0
  101. package/packages/velinstyle-motion/src/ux/pixverse-gate.js +153 -0
  102. package/packages/velinstyle-motion/src/ux/wizard.js +171 -0
  103. package/packages/velinstyle-motion/src/validate-image.js +91 -0
  104. package/packages/velinstyle-skills/catalog.json +1 -1
  105. package/packages/velinstyle-skills/registry.json +1 -142
  106. package/packages/velinstyle-skills/skills/velin-motion-reduced-safe/SKILL.md +1 -1
  107. package/packages/velinstyle-skills/skills/velin-motion-reveal-feedback/SKILL.md +1 -1
  108. package/src/tokens/motion.css +7 -0
  109. package/src/utilities/scroll-animation.css +66 -0
@@ -2996,6 +2996,13 @@
2996
2996
  __export(velin_theme_toggle_exports, {
2997
2997
  default: () => velin_theme_toggle_default
2998
2998
  });
2999
+ function applyColorScheme(target, slug) {
3000
+ const dark = DARK_THEME_SLUGS.has(slug);
3001
+ if (target === document.documentElement || target === document.body) {
3002
+ target.style.colorScheme = dark ? "dark" : "light";
3003
+ }
3004
+ target.setAttribute("data-velin-color-scheme", dark ? "dark" : "light");
3005
+ }
2999
3006
  function ensureThemeStylesheet(slug, base) {
3000
3007
  if (!slug || BUILTIN_THEMES.has(slug)) return;
3001
3008
  if (loadedThemeStylesheets.has(slug)) return;
@@ -3011,7 +3018,7 @@
3011
3018
  document.head.appendChild(link);
3012
3019
  loadedThemeStylesheets.add(slug);
3013
3020
  }
3014
- var THEMES, BUILTIN_THEMES, loadedThemeStylesheets, styles6, VelinThemeToggle, velin_theme_toggle_default;
3021
+ var THEMES, BUILTIN_THEMES, DARK_THEME_SLUGS, loadedThemeStylesheets, styles6, VelinThemeToggle, velin_theme_toggle_default;
3015
3022
  var init_velin_theme_toggle = __esm({
3016
3023
  "components/velin-theme-toggle.js"() {
3017
3024
  THEMES = [
@@ -3032,6 +3039,7 @@
3032
3039
  { slug: "sunset", label: "Sunset" }
3033
3040
  ];
3034
3041
  BUILTIN_THEMES = /* @__PURE__ */ new Set(["", "dark"]);
3042
+ DARK_THEME_SLUGS = /* @__PURE__ */ new Set(["dark", "midnight", "neon"]);
3035
3043
  loadedThemeStylesheets = /* @__PURE__ */ new Set();
3036
3044
  styles6 = `
3037
3045
  :host { display: inline-flex; position: relative; }
@@ -3263,6 +3271,7 @@
3263
3271
  this.setAttribute("theme", normalized === "dark" ? "dark" : normalized);
3264
3272
  ensureThemeStylesheet(normalized, this._themesBase);
3265
3273
  }
3274
+ applyColorScheme(this._target, normalized);
3266
3275
  if (persist) {
3267
3276
  if (!normalized) localStorage.removeItem("velin-theme");
3268
3277
  else localStorage.setItem("velin-theme", normalized);
@@ -3270,7 +3279,11 @@
3270
3279
  this._highlightActive();
3271
3280
  this.dispatchEvent(new CustomEvent("velin-theme-change", {
3272
3281
  bubbles: true,
3273
- detail: { theme: normalized || "light", dark: normalized === "dark", slug: normalized }
3282
+ detail: {
3283
+ theme: normalized || "light",
3284
+ dark: DARK_THEME_SLUGS.has(normalized),
3285
+ slug: normalized
3286
+ }
3274
3287
  }));
3275
3288
  }
3276
3289
  _syncTogglePressed() {
@@ -9677,6 +9690,12 @@
9677
9690
  const classes = /* @__PURE__ */ new Set();
9678
9691
  for (const [name, value] of Object.entries(attrs)) {
9679
9692
  if (value === "false" || value === "off") continue;
9693
+ if (name === "motion" && value && value !== "true") {
9694
+ const presetKey = value;
9695
+ const mapped2 = EFFECT_MAP[presetKey];
9696
+ if (mapped2) mapped2.forEach((c) => classes.add(c));
9697
+ continue;
9698
+ }
9680
9699
  const mapped = EFFECT_MAP[name];
9681
9700
  if (mapped) mapped.forEach((c) => classes.add(c));
9682
9701
  if (name === "slide" && value && value !== "true" && value !== "") {
@@ -9710,12 +9729,20 @@
9710
9729
  "slide-left": ["velin-animate-on-scroll", "velin-animate-on-scroll--slide-left"],
9711
9730
  "slide-right": ["velin-animate-on-scroll", "velin-animate-on-scroll--slide-right"],
9712
9731
  scale: ["velin-animate-on-scroll", "velin-animate-on-scroll--scale"],
9732
+ zoom: ["velin-animate-on-scroll", "velin-animate-on-scroll--scale"],
9713
9733
  parallax: ["velin-parallax"],
9714
9734
  "parallax-slow": ["velin-parallax", "velin-parallax--slow"],
9715
9735
  hover: ["velin-animate-hover"],
9716
9736
  "hover-lift": ["velin-animate-hover"],
9737
+ lift: ["velin-animate-hover"],
9717
9738
  flip: ["velin-animate-scale-in"],
9718
- blur: ["velin-animate-fade-in"]
9739
+ blur: ["velin-animate-fade-in"],
9740
+ pulse: ["velin-animate-pulse"],
9741
+ shake: ["velin-animate-shake"],
9742
+ bounce: ["velin-animate-bounce"],
9743
+ shimmer: ["velin-skeleton"],
9744
+ heroReveal: ["velin-animate-on-scroll", "velin-animate-on-scroll--fade"],
9745
+ fadeOut: ["velin-animate-fade-out"]
9719
9746
  };
9720
9747
  }
9721
9748
  });
@@ -9778,12 +9805,804 @@
9778
9805
  }
9779
9806
  });
9780
9807
 
9808
+ // core/motion/data/registry.json
9809
+ var registry_default;
9810
+ var init_registry2 = __esm({
9811
+ "core/motion/data/registry.json"() {
9812
+ registry_default = {
9813
+ schema: "velinstyle.motion.registry",
9814
+ version: 1,
9815
+ presets: [
9816
+ {
9817
+ id: "fade",
9818
+ title: "Fade",
9819
+ description: "Opacity entrance; layout-safe default reveal.",
9820
+ kind: "preset",
9821
+ category: "hero",
9822
+ tags: ["entrance"],
9823
+ duration: 400,
9824
+ fps: "60",
9825
+ reducedMotion: true,
9826
+ layoutSafe: true,
9827
+ status: "stable",
9828
+ cssClass: "velin-animate-on-scroll--fade",
9829
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9830
+ },
9831
+ {
9832
+ id: "slide",
9833
+ title: "Slide Up",
9834
+ description: "Slide from below into view.",
9835
+ kind: "preset",
9836
+ category: "cards",
9837
+ tags: ["entrance", "slide"],
9838
+ duration: 500,
9839
+ fps: "60",
9840
+ reducedMotion: true,
9841
+ layoutSafe: true,
9842
+ status: "stable",
9843
+ cssClass: "velin-animate-on-scroll--slide-up",
9844
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9845
+ },
9846
+ {
9847
+ id: "slide-down",
9848
+ title: "Slide Down",
9849
+ description: "Slide from above into view.",
9850
+ kind: "preset",
9851
+ category: "navigation",
9852
+ tags: ["entrance", "slide"],
9853
+ duration: 500,
9854
+ reducedMotion: true,
9855
+ layoutSafe: true,
9856
+ status: "stable",
9857
+ cssClass: "velin-animate-on-scroll--slide-down",
9858
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9859
+ },
9860
+ {
9861
+ id: "slide-left",
9862
+ title: "Slide Left",
9863
+ description: "Slide from the inline-end.",
9864
+ kind: "preset",
9865
+ category: "lists",
9866
+ tags: ["entrance", "slide"],
9867
+ duration: 500,
9868
+ reducedMotion: true,
9869
+ layoutSafe: true,
9870
+ status: "stable",
9871
+ cssClass: "velin-animate-on-scroll--slide-left",
9872
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9873
+ },
9874
+ {
9875
+ id: "slide-right",
9876
+ title: "Slide Right",
9877
+ description: "Slide from the inline-start.",
9878
+ kind: "preset",
9879
+ category: "lists",
9880
+ tags: ["entrance", "slide"],
9881
+ duration: 500,
9882
+ reducedMotion: true,
9883
+ layoutSafe: true,
9884
+ status: "stable",
9885
+ cssClass: "velin-animate-on-scroll--slide-right",
9886
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9887
+ },
9888
+ {
9889
+ id: "zoom",
9890
+ title: "Zoom / Scale",
9891
+ description: "Scale-in entrance for cards and media.",
9892
+ kind: "preset",
9893
+ category: "media",
9894
+ tags: ["entrance", "scale"],
9895
+ duration: 450,
9896
+ reducedMotion: true,
9897
+ layoutSafe: true,
9898
+ status: "stable",
9899
+ cssClass: "velin-animate-on-scroll--scale",
9900
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9901
+ },
9902
+ {
9903
+ id: "blur",
9904
+ title: "Blur In",
9905
+ description: "Soft fade/blur entrance (maps to fade-in utility).",
9906
+ kind: "preset",
9907
+ category: "overlay",
9908
+ tags: ["entrance"],
9909
+ duration: 500,
9910
+ reducedMotion: true,
9911
+ layoutSafe: true,
9912
+ status: "beta",
9913
+ cssClass: "velin-animate-fade-in",
9914
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9915
+ },
9916
+ {
9917
+ id: "flip",
9918
+ title: "Flip / Scale In",
9919
+ description: "Attention scale-in for emphasis.",
9920
+ kind: "preset",
9921
+ category: "feedback",
9922
+ tags: ["attention"],
9923
+ duration: 400,
9924
+ reducedMotion: true,
9925
+ layoutSafe: true,
9926
+ status: "beta",
9927
+ cssClass: "velin-animate-scale-in",
9928
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9929
+ },
9930
+ {
9931
+ id: "lift",
9932
+ title: "Hover Lift",
9933
+ description: "Subtle lift on hover for interactive cards and buttons.",
9934
+ kind: "preset",
9935
+ category: "buttons",
9936
+ tags: ["hover"],
9937
+ duration: 200,
9938
+ reducedMotion: true,
9939
+ layoutSafe: true,
9940
+ status: "stable",
9941
+ cssClass: "velin-animate-hover",
9942
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9943
+ },
9944
+ {
9945
+ id: "pulse",
9946
+ title: "Pulse",
9947
+ description: "Attention pulse; prefer finite loops under performance policy.",
9948
+ kind: "preset",
9949
+ category: "feedback",
9950
+ tags: ["attention"],
9951
+ duration: 1e3,
9952
+ reducedMotion: true,
9953
+ layoutSafe: true,
9954
+ status: "stable",
9955
+ cssClass: "velin-animate-pulse",
9956
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9957
+ },
9958
+ {
9959
+ id: "shake",
9960
+ title: "Shake",
9961
+ description: "Error/attention shake feedback.",
9962
+ kind: "preset",
9963
+ category: "forms",
9964
+ tags: ["attention", "feedback"],
9965
+ duration: 400,
9966
+ reducedMotion: true,
9967
+ layoutSafe: true,
9968
+ status: "stable",
9969
+ cssClass: "velin-animate-shake",
9970
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9971
+ },
9972
+ {
9973
+ id: "bounce",
9974
+ title: "Bounce",
9975
+ description: "Playful bounce entrance or attention.",
9976
+ kind: "preset",
9977
+ category: "feedback",
9978
+ tags: ["attention"],
9979
+ duration: 600,
9980
+ reducedMotion: true,
9981
+ layoutSafe: true,
9982
+ status: "stable",
9983
+ cssClass: "velin-animate-bounce",
9984
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9985
+ },
9986
+ {
9987
+ id: "shimmer",
9988
+ title: "Shimmer",
9989
+ description: "Loading shimmer surface (skeleton companion).",
9990
+ kind: "preset",
9991
+ category: "loading",
9992
+ tags: ["loading"],
9993
+ duration: 1200,
9994
+ reducedMotion: true,
9995
+ layoutSafe: true,
9996
+ status: "stable",
9997
+ cssClass: "velin-skeleton",
9998
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
9999
+ },
10000
+ {
10001
+ id: "heroReveal",
10002
+ title: "Hero Reveal",
10003
+ description: "Staggered entrance for hero content; layout-safe; reduced-motion fallback.",
10004
+ kind: "preset",
10005
+ category: "hero",
10006
+ tags: ["entrance", "stagger"],
10007
+ duration: 600,
10008
+ fps: "60",
10009
+ reducedMotion: true,
10010
+ layoutSafe: true,
10011
+ status: "stable",
10012
+ cssClass: "velin-animate-on-scroll--fade",
10013
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10014
+ },
10015
+ {
10016
+ id: "parallax",
10017
+ title: "Parallax",
10018
+ description: "Scroll-driven parallax shift.",
10019
+ kind: "preset",
10020
+ category: "media",
10021
+ tags: ["scroll"],
10022
+ duration: 0,
10023
+ reducedMotion: true,
10024
+ layoutSafe: false,
10025
+ status: "stable",
10026
+ cssClass: "velin-parallax",
10027
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10028
+ },
10029
+ {
10030
+ id: "fadeOut",
10031
+ title: "Fade Out",
10032
+ description: "Exit fade (planned composition with timelines).",
10033
+ kind: "preset",
10034
+ category: "overlay",
10035
+ tags: ["exit"],
10036
+ duration: 300,
10037
+ reducedMotion: true,
10038
+ layoutSafe: true,
10039
+ status: "beta",
10040
+ cssClass: "velin-animate-fade-out",
10041
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10042
+ }
10043
+ ],
10044
+ timelines: [
10045
+ {
10046
+ id: "hero-intro",
10047
+ title: "Hero Intro",
10048
+ description: "Title \u2192 subtitle \u2192 buttons \u2192 image",
10049
+ kind: "timeline",
10050
+ category: "hero",
10051
+ steps: ["title", "subtitle", "buttons", "image"],
10052
+ status: "beta",
10053
+ compatibility: { cssOnly: false, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10054
+ },
10055
+ {
10056
+ id: "card-stagger",
10057
+ title: "Card Stagger",
10058
+ description: "Sequential card entrance labels.",
10059
+ kind: "timeline",
10060
+ category: "cards",
10061
+ steps: ["card-1", "card-2", "card-3"],
10062
+ status: "beta",
10063
+ compatibility: { cssOnly: false, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10064
+ }
10065
+ ],
10066
+ transitions: [
10067
+ {
10068
+ id: "cross-fade",
10069
+ title: "Cross Fade",
10070
+ description: "Page/view cross-fade (View Transition friendly).",
10071
+ kind: "transition",
10072
+ category: "page",
10073
+ status: "planned",
10074
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10075
+ },
10076
+ {
10077
+ id: "modal-enter",
10078
+ title: "Modal Enter",
10079
+ description: "Overlay modal entrance transition.",
10080
+ kind: "transition",
10081
+ category: "modal",
10082
+ status: "planned",
10083
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10084
+ },
10085
+ {
10086
+ id: "drawer-enter",
10087
+ title: "Drawer Enter",
10088
+ description: "Drawer slide transition.",
10089
+ kind: "transition",
10090
+ category: "drawer",
10091
+ status: "planned",
10092
+ compatibility: { cssOnly: true, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10093
+ }
10094
+ ],
10095
+ physics: [
10096
+ {
10097
+ id: "spring",
10098
+ title: "Spring",
10099
+ description: "Spring easing token mapping (runtime simulation later).",
10100
+ kind: "physics",
10101
+ category: "feedback",
10102
+ status: "planned",
10103
+ token: "--velin-ease-spring",
10104
+ compatibility: { cssOnly: true, runtime: false, webComponents: false, studio: true, production: true, review: true, cli: true }
10105
+ },
10106
+ {
10107
+ id: "elastic",
10108
+ title: "Elastic",
10109
+ description: "Elastic easing token mapping.",
10110
+ kind: "physics",
10111
+ category: "feedback",
10112
+ status: "planned",
10113
+ token: "--velin-ease-elastic",
10114
+ compatibility: { cssOnly: true, runtime: false, webComponents: false, studio: true, production: true, review: true, cli: true }
10115
+ }
10116
+ ],
10117
+ composers: [
10118
+ {
10119
+ id: "sequence",
10120
+ title: "Sequence Composer",
10121
+ description: "Ordered fade/wait/slide composition API.",
10122
+ kind: "composer",
10123
+ category: "page",
10124
+ status: "planned",
10125
+ compatibility: { cssOnly: false, runtime: true, webComponents: true, studio: true, production: true, review: true, cli: true }
10126
+ }
10127
+ ],
10128
+ triggers: [
10129
+ { 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 } },
10130
+ { 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 } },
10131
+ { id: "hidden", title: "Hidden", description: "Fire when element leaves the viewport. (Planned \u2014 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 } },
10132
+ { 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 } },
10133
+ { 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 } },
10134
+ { 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 } },
10135
+ { 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 } },
10136
+ { id: "idle", title: "Idle", description: "After user idle timeout. (Planned \u2014 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 } },
10137
+ { id: "media", title: "Media", description: "Match media query condition. (Planned \u2014 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 } },
10138
+ { id: "container", title: "Container", description: "Container query / size trigger. (Planned \u2014 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 } },
10139
+ { id: "theme", title: "Theme", description: "Theme change trigger. (Planned \u2014 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 } },
10140
+ { id: "custom", title: "Custom", description: "Custom event name via velin-trigger-event. (Planned \u2014 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 } }
10141
+ ],
10142
+ policies: [
10143
+ { 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 } },
10144
+ { 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 } },
10145
+ { 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 } },
10146
+ { 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 } },
10147
+ { 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 } },
10148
+ { 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 } },
10149
+ { 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 } }
10150
+ ],
10151
+ blueprints: [
10152
+ { 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 } },
10153
+ { 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 } },
10154
+ { 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 } },
10155
+ { 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 } },
10156
+ { 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 } },
10157
+ { 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 } },
10158
+ { 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 } },
10159
+ { 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 } },
10160
+ { 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 } },
10161
+ { 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 } }
10162
+ ]
10163
+ };
10164
+ }
10165
+ });
10166
+
10167
+ // core/motion/registry.js
10168
+ function loadMotionRegistry(override = null) {
10169
+ if (override) {
10170
+ cached = override;
10171
+ return cached;
10172
+ }
10173
+ return cached || registry_default;
10174
+ }
10175
+ function listMotion(namespace, filter = {}) {
10176
+ const reg = loadMotionRegistry();
10177
+ const key = namespace.endsWith("s") ? namespace : `${namespace}s`;
10178
+ const items = reg[key] || reg[namespace] || [];
10179
+ return items.filter((item) => {
10180
+ if (filter.status && item.status !== filter.status) return false;
10181
+ if (filter.category && item.category !== filter.category) return false;
10182
+ if (filter.tag && !(item.tags || []).includes(filter.tag)) return false;
10183
+ return true;
10184
+ });
10185
+ }
10186
+ function getMotion(namespace, id) {
10187
+ return listMotion(namespace).find((item) => item.id === id) || null;
10188
+ }
10189
+ function getPreset(id) {
10190
+ return getMotion("presets", id);
10191
+ }
10192
+ function getPolicy(id) {
10193
+ return getMotion("policies", id);
10194
+ }
10195
+ function getTrigger(id) {
10196
+ return getMotion("triggers", id);
10197
+ }
10198
+ function getTimeline(id) {
10199
+ return getMotion("timelines", id);
10200
+ }
10201
+ function listPresets(filter) {
10202
+ return listMotion("presets", filter);
10203
+ }
10204
+ function listPolicies(filter) {
10205
+ return listMotion("policies", filter);
10206
+ }
10207
+ function catalogSummary() {
10208
+ const reg = loadMotionRegistry();
10209
+ const counts = {};
10210
+ for (const ns of NAMESPACES) {
10211
+ counts[ns] = (reg[ns] || []).length;
10212
+ }
10213
+ return {
10214
+ schema: reg.schema,
10215
+ version: reg.version,
10216
+ counts,
10217
+ namespaces: NAMESPACES
10218
+ };
10219
+ }
10220
+ function resolvePresetId(id) {
10221
+ if (!id) return null;
10222
+ const direct = getPreset(id);
10223
+ if (direct) return direct;
10224
+ const aliases = {
10225
+ scale: "zoom",
10226
+ "hover-lift": "lift",
10227
+ reveal: "fade"
10228
+ };
10229
+ const mapped = aliases[id];
10230
+ return mapped ? getPreset(mapped) : null;
10231
+ }
10232
+ var cached, NAMESPACES;
10233
+ var init_registry3 = __esm({
10234
+ "core/motion/registry.js"() {
10235
+ init_registry2();
10236
+ cached = registry_default;
10237
+ NAMESPACES = [
10238
+ "presets",
10239
+ "timelines",
10240
+ "transitions",
10241
+ "physics",
10242
+ "composers",
10243
+ "triggers",
10244
+ "policies",
10245
+ "blueprints"
10246
+ ];
10247
+ }
10248
+ });
10249
+
10250
+ // core/motion/triggers.js
10251
+ function readTrigger(el, fallback = "visible") {
10252
+ const raw = (el.getAttribute("velin-trigger") || fallback || "visible").trim().toLowerCase();
10253
+ return raw || fallback;
10254
+ }
10255
+ function bindTrigger(el, triggerId, onFire, opts = {}) {
10256
+ const once = opts.once !== false;
10257
+ const reduced = opts.reduced ?? prefersReducedMotion();
10258
+ const id = (triggerId || "visible").toLowerCase();
10259
+ const meta = getTrigger(id);
10260
+ if (reduced || el.dataset.velinMotion === "off") {
10261
+ onFire();
10262
+ return () => {
10263
+ };
10264
+ }
10265
+ if (meta?.status === "planned" && !TRIGGER_V1.includes(id)) {
10266
+ return bindTrigger(el, "visible", onFire, opts);
10267
+ }
10268
+ let fired = false;
10269
+ const fire = () => {
10270
+ if (once && fired) return;
10271
+ fired = true;
10272
+ onFire();
10273
+ };
10274
+ if (id === "load") {
10275
+ fire();
10276
+ return () => {
10277
+ };
10278
+ }
10279
+ if (id === "visible" || id === "scroll") {
10280
+ return observeInView(el, () => fire());
10281
+ }
10282
+ if (id === "hover") {
10283
+ const enter = () => fire();
10284
+ el.addEventListener("pointerenter", enter);
10285
+ return () => el.removeEventListener("pointerenter", enter);
10286
+ }
10287
+ if (id === "focus") {
10288
+ const onFocus = () => fire();
10289
+ el.addEventListener("focusin", onFocus);
10290
+ return () => el.removeEventListener("focusin", onFocus);
10291
+ }
10292
+ if (id === "click") {
10293
+ const onClick = () => fire();
10294
+ el.addEventListener("click", onClick);
10295
+ return () => el.removeEventListener("click", onClick);
10296
+ }
10297
+ if (id === "hidden") {
10298
+ const stop = observeInView(el, () => {
10299
+ });
10300
+ if (typeof IntersectionObserver === "undefined") return () => {
10301
+ };
10302
+ const io = new IntersectionObserver((entries2) => {
10303
+ for (const entry of entries2) {
10304
+ if (!entry.isIntersecting) fire();
10305
+ }
10306
+ }, { threshold: 0 });
10307
+ io.observe(el);
10308
+ return () => {
10309
+ stop();
10310
+ io.disconnect();
10311
+ };
10312
+ }
10313
+ if (id === "idle") {
10314
+ const ms = Number(el.getAttribute("velin-trigger-delay") || 3e3);
10315
+ const t = setTimeout(fire, ms);
10316
+ return () => clearTimeout(t);
10317
+ }
10318
+ if (id === "media") {
10319
+ const q = el.getAttribute("velin-trigger-media") || "(min-width: 768px)";
10320
+ if (typeof window === "undefined" || !window.matchMedia) {
10321
+ fire();
10322
+ return () => {
10323
+ };
10324
+ }
10325
+ const mql = window.matchMedia(q);
10326
+ const handler = () => {
10327
+ if (mql.matches) fire();
10328
+ };
10329
+ handler();
10330
+ mql.addEventListener?.("change", handler);
10331
+ return () => mql.removeEventListener?.("change", handler);
10332
+ }
10333
+ if (id === "theme") {
10334
+ const root = el.ownerDocument?.documentElement;
10335
+ if (!root || typeof MutationObserver === "undefined") {
10336
+ fire();
10337
+ return () => {
10338
+ };
10339
+ }
10340
+ const mo = new MutationObserver(() => fire());
10341
+ mo.observe(root, { attributes: true, attributeFilter: ["data-velin-theme", "class"] });
10342
+ return () => mo.disconnect();
10343
+ }
10344
+ if (id === "custom") {
10345
+ const evt = el.getAttribute("velin-trigger-event") || "velin:motion";
10346
+ const handler = () => fire();
10347
+ el.addEventListener(evt, handler);
10348
+ return () => el.removeEventListener(evt, handler);
10349
+ }
10350
+ if (id === "container") {
10351
+ return observeInView(el, () => fire());
10352
+ }
10353
+ return observeInView(el, () => fire());
10354
+ }
10355
+ function armMotionElement(el, applyPreset) {
10356
+ applyPreset();
10357
+ const trigger = readTrigger(el, el.hasAttribute("velin-hover") ? "hover" : "visible");
10358
+ if (prefersReducedMotion() || el.dataset.velinMotion === "off") {
10359
+ markVisible(el);
10360
+ return () => {
10361
+ };
10362
+ }
10363
+ if (trigger === "hover" || trigger === "focus") {
10364
+ markVisible(el);
10365
+ return () => {
10366
+ };
10367
+ }
10368
+ if (trigger === "load") {
10369
+ markVisible(el);
10370
+ return () => {
10371
+ };
10372
+ }
10373
+ return bindTrigger(el, trigger, () => markVisible(el));
10374
+ }
10375
+ var TRIGGER_V1, TRIGGER_V2, ALL_TRIGGERS;
10376
+ var init_triggers = __esm({
10377
+ "core/motion/triggers.js"() {
10378
+ init_scheduler();
10379
+ init_effects();
10380
+ init_registry3();
10381
+ TRIGGER_V1 = ["load", "visible", "hover", "focus", "click", "scroll"];
10382
+ TRIGGER_V2 = ["hidden", "idle", "media", "container", "theme", "custom"];
10383
+ ALL_TRIGGERS = [...TRIGGER_V1, ...TRIGGER_V2];
10384
+ }
10385
+ });
10386
+
10387
+ // core/motion/policy.js
10388
+ function resolvePolicy(id = "safe") {
10389
+ return getPolicy(id) || getPolicy("safe");
10390
+ }
10391
+ function shouldDisableMotion(policy) {
10392
+ if (!policy) return prefersReducedMotion();
10393
+ if (policy.disabled) return true;
10394
+ if (policy.forceReduced && prefersReducedMotion()) return true;
10395
+ if (prefersReducedMotion() && policy.id !== "marketing") return true;
10396
+ return false;
10397
+ }
10398
+ function capDuration(ms, policy) {
10399
+ const max = policy?.maxDurationMs ?? 800;
10400
+ if (policy?.disabled) return 0;
10401
+ return Math.min(Number(ms) || 0, max);
10402
+ }
10403
+ function applyMotionVars(el, policy) {
10404
+ const duration = el.getAttribute("velin-duration");
10405
+ const delay2 = el.getAttribute("velin-delay");
10406
+ const ease = el.getAttribute("velin-ease");
10407
+ if (duration) {
10408
+ const capped = capDuration(Number(duration), policy);
10409
+ el.style.setProperty("--velin-motion-duration", `${capped}ms`);
10410
+ el.style.animationDuration = `${capped}ms`;
10411
+ }
10412
+ if (delay2) el.style.animationDelay = `${Number(delay2)}ms`;
10413
+ if (ease) {
10414
+ const map = {
10415
+ spring: "var(--velin-ease-spring)",
10416
+ bounce: "var(--velin-ease-bounce)",
10417
+ elastic: "var(--velin-ease-elastic)",
10418
+ default: "var(--velin-ease-default)"
10419
+ };
10420
+ el.style.animationTimingFunction = map[ease] || ease;
10421
+ }
10422
+ if (policy?.disabled || shouldDisableMotion(policy)) {
10423
+ el.dataset.velinMotion = "off";
10424
+ }
10425
+ }
10426
+ var init_policy = __esm({
10427
+ "core/motion/policy.js"() {
10428
+ init_registry3();
10429
+ init_effects();
10430
+ }
10431
+ });
10432
+
10433
+ // core/motion/timeline.js
10434
+ function runTimeline(timelineId, root, opts = {}) {
10435
+ const tl = getTimeline(timelineId);
10436
+ if (!tl) return { ok: false, error: `Unknown timeline "${timelineId}"`, ran: [] };
10437
+ const stepMs = opts.stepMs ?? 120;
10438
+ const ran = [];
10439
+ if (opts.policyDisabled || prefersReducedMotion()) {
10440
+ for (const step of tl.steps || []) {
10441
+ const el = resolveStep(root, step);
10442
+ if (el) markVisible(el);
10443
+ ran.push(step);
10444
+ }
10445
+ return { ok: true, ran };
10446
+ }
10447
+ let delay2 = 0;
10448
+ for (const step of tl.steps || []) {
10449
+ const el = resolveStep(root, step);
10450
+ if (!el) continue;
10451
+ const d = delay2;
10452
+ delay2 += stepMs;
10453
+ if (typeof window !== "undefined" && window.setTimeout) {
10454
+ window.setTimeout(() => markVisible(el), d);
10455
+ } else {
10456
+ markVisible(el);
10457
+ }
10458
+ ran.push(step);
10459
+ }
10460
+ return { ok: true, ran, timeline: tl };
10461
+ }
10462
+ function resolveStep(root, step) {
10463
+ if (!root?.querySelector) return null;
10464
+ return root.querySelector(`[data-velin-step="${step}"]`) || root.querySelector(`[velin-step="${step}"]`) || root.querySelector(`#${CSS.escape?.(step) || step}`);
10465
+ }
10466
+ function enhanceTimelines(root) {
10467
+ if (!root?.querySelectorAll) return () => {
10468
+ };
10469
+ const nodes = root.querySelectorAll("[velin-timeline]");
10470
+ const teardowns = [];
10471
+ for (const el of nodes) {
10472
+ const id = el.getAttribute("velin-timeline");
10473
+ const result = runTimeline(id, el);
10474
+ teardowns.push(() => result);
10475
+ }
10476
+ return () => {
10477
+ };
10478
+ }
10479
+ var init_timeline = __esm({
10480
+ "core/motion/timeline.js"() {
10481
+ init_registry3();
10482
+ init_effects();
10483
+ }
10484
+ });
10485
+
10486
+ // core/motion/composer.js
10487
+ function fade(ms = 400) {
10488
+ return { type: "fade", ms };
10489
+ }
10490
+ function slide(ms = 500, value = "up") {
10491
+ return { type: "slide", ms, value };
10492
+ }
10493
+ function wait(ms = 200) {
10494
+ return { type: "wait", ms };
10495
+ }
10496
+ function rotate(ms = 400) {
10497
+ return { type: "rotate", ms };
10498
+ }
10499
+ function blur(ms = 400) {
10500
+ return { type: "blur", ms };
10501
+ }
10502
+ function preset(id, ms) {
10503
+ return { type: "preset", preset: id, ms };
10504
+ }
10505
+ async function sequence(steps = [], ctx = {}) {
10506
+ const target = ctx.target || ctx.root;
10507
+ const reduced = prefersReducedMotion();
10508
+ const ran = [];
10509
+ for (const step of steps) {
10510
+ if (step.type === "wait") {
10511
+ if (!reduced && step.ms) await delay(step.ms);
10512
+ ran.push(step);
10513
+ continue;
10514
+ }
10515
+ if (target && typeof target.classList?.add === "function") {
10516
+ if (step.type === "preset" && step.preset) {
10517
+ const p = resolvePresetId(step.preset);
10518
+ if (p?.cssClass) target.classList.add(...String(p.cssClass).split(/\s+/));
10519
+ applyEffects(target, { [step.preset]: "true" });
10520
+ } else if (step.type === "fade") {
10521
+ applyEffects(target, { fade: "true" });
10522
+ } else if (step.type === "slide") {
10523
+ applyEffects(target, { slide: step.value || "up" });
10524
+ } else if (step.type === "blur") {
10525
+ applyEffects(target, { blur: "true" });
10526
+ } else if (step.type === "rotate") {
10527
+ applyEffects(target, { flip: "true" });
10528
+ }
10529
+ markVisible(target);
10530
+ }
10531
+ if (!reduced && step.ms) await delay(step.ms);
10532
+ ran.push(step);
10533
+ }
10534
+ return { ok: true, ran };
10535
+ }
10536
+ function delay(ms) {
10537
+ return new Promise((resolve) => {
10538
+ if (typeof setTimeout === "undefined") return resolve();
10539
+ setTimeout(resolve, ms);
10540
+ });
10541
+ }
10542
+ function enhanceSequences(root) {
10543
+ if (!root?.querySelectorAll) return () => {
10544
+ };
10545
+ const nodes = [...root.querySelectorAll("[velin-motion-sequence]")];
10546
+ for (const section of nodes) {
10547
+ const children = [...section.children];
10548
+ let i = 0;
10549
+ const stepMs = Number(section.getAttribute("velin-sequence-gap") || 120);
10550
+ for (const child of children) {
10551
+ child.classList.add("velin-animate-on-scroll", "velin-animate-on-scroll--fade");
10552
+ if (prefersReducedMotion()) {
10553
+ markVisible(child);
10554
+ } else if (typeof setTimeout !== "undefined") {
10555
+ const delayMs = i * stepMs;
10556
+ setTimeout(() => markVisible(child), delayMs);
10557
+ } else {
10558
+ markVisible(child);
10559
+ }
10560
+ i += 1;
10561
+ }
10562
+ }
10563
+ return () => {
10564
+ };
10565
+ }
10566
+ var Motion;
10567
+ var init_composer = __esm({
10568
+ "core/motion/composer.js"() {
10569
+ init_effects();
10570
+ init_registry3();
10571
+ init_effects();
10572
+ Motion = {
10573
+ sequence,
10574
+ fade,
10575
+ slide,
10576
+ wait,
10577
+ rotate,
10578
+ blur,
10579
+ preset
10580
+ };
10581
+ }
10582
+ });
10583
+
9781
10584
  // core/motion/index.js
10585
+ function createMotionEngine(options = {}) {
10586
+ const policy = resolvePolicy(options.policy || "safe");
10587
+ return {
10588
+ policy,
10589
+ registry: () => loadMotionRegistry(),
10590
+ catalog: catalogSummary,
10591
+ listPresets,
10592
+ listPolicies,
10593
+ init: (opts = {}) => initMotion({ ...opts, policy: policy.id }),
10594
+ Motion
10595
+ };
10596
+ }
9782
10597
  function initMotion(options = {}) {
9783
10598
  const root = options.root || (typeof document !== "undefined" ? document : null);
9784
10599
  if (!root) return () => {
9785
10600
  };
10601
+ const policy = resolvePolicy(
10602
+ options.policy || root.documentElement?.getAttribute?.("data-velin-motion-policy") || root.querySelector?.("[data-velin-motion-policy]")?.getAttribute("data-velin-motion-policy") || "safe"
10603
+ );
9786
10604
  const selector = options.selector || [
10605
+ "[velin-motion]",
9787
10606
  "[velin-reveal]",
9788
10607
  "[velin-fade]",
9789
10608
  "[velin-slide]",
@@ -9793,26 +10612,40 @@
9793
10612
  ".velin-animate-on-scroll"
9794
10613
  ].join(",");
9795
10614
  const elements = root.querySelectorAll(selector);
9796
- const reduced = prefersReducedMotion();
10615
+ const reduced = shouldDisableMotion(policy) || prefersReducedMotion();
9797
10616
  for (const el of elements) {
9798
10617
  if (el.dataset.velinMotionInit) continue;
9799
10618
  el.dataset.velinMotionInit = "1";
10619
+ applyMotionVars(el, policy);
9800
10620
  const attrs = {};
9801
- for (const name of MOTION_ATTRS) {
10621
+ const motionPreset = el.getAttribute("velin-motion");
10622
+ if (motionPreset) {
10623
+ attrs.motion = motionPreset;
10624
+ const resolved = resolvePresetId(motionPreset);
10625
+ if (resolved?.id) attrs[resolved.id] = "true";
10626
+ }
10627
+ for (const name of LEGACY_ATTRS) {
9802
10628
  if (el.hasAttribute(name)) attrs[name.replace("velin-", "")] = el.getAttribute(name) || "true";
9803
10629
  }
9804
10630
  applyEffects(el, attrs);
9805
- if (reduced) {
10631
+ if (reduced || el.dataset.velinMotion === "off") {
9806
10632
  markVisible(el);
9807
10633
  continue;
9808
10634
  }
9809
- const stop = observeInView(el, (node) => markVisible(node));
10635
+ const stop = armMotionElement(el, () => applyEffects(el, attrs));
9810
10636
  teardownFns.push(stop);
9811
10637
  }
9812
10638
  enhanceStagger(root);
9813
10639
  bindSmoothScroll(root);
10640
+ enhanceTimelines(root);
10641
+ enhanceSequences(root);
9814
10642
  return () => {
9815
- teardownFns.forEach((fn) => fn());
10643
+ teardownFns.forEach((fn) => {
10644
+ try {
10645
+ fn();
10646
+ } catch {
10647
+ }
10648
+ });
9816
10649
  teardownFns = [];
9817
10650
  disconnectInViewObserver();
9818
10651
  };
@@ -9823,16 +10656,28 @@
9823
10656
  selector: options.selector || ".velin-animate-on-scroll"
9824
10657
  });
9825
10658
  }
9826
- var MOTION_ATTRS, teardownFns, velinMotion;
10659
+ var LEGACY_ATTRS, teardownFns, velinMotion;
9827
10660
  var init_motion = __esm({
9828
10661
  "core/motion/index.js"() {
9829
10662
  init_scheduler();
9830
10663
  init_effects();
9831
10664
  init_stagger();
9832
10665
  init_scroll();
9833
- MOTION_ATTRS = ["velin-reveal", "velin-fade", "velin-slide", "velin-scale", "velin-parallax", "velin-hover"];
10666
+ init_triggers();
10667
+ init_policy();
10668
+ init_timeline();
10669
+ init_composer();
10670
+ init_registry3();
10671
+ LEGACY_ATTRS = ["velin-reveal", "velin-fade", "velin-slide", "velin-scale", "velin-parallax", "velin-hover"];
9834
10672
  teardownFns = [];
9835
- velinMotion = { init: initMotion, observe: observeInView, markVisible, VISIBLE_CLASS };
10673
+ velinMotion = {
10674
+ init: initMotion,
10675
+ observe: observeInView,
10676
+ markVisible,
10677
+ VISIBLE_CLASS,
10678
+ createEngine: createMotionEngine,
10679
+ readTrigger
10680
+ };
9836
10681
  }
9837
10682
  });
9838
10683
 
@@ -9976,7 +10821,7 @@
9976
10821
  }
9977
10822
  return `tx-${(h >>> 0).toString(16)}`;
9978
10823
  }
9979
- var init_registry2 = __esm({
10824
+ var init_registry4 = __esm({
9980
10825
  "core/transparency/registry.js"() {
9981
10826
  }
9982
10827
  });
@@ -10058,7 +10903,7 @@
10058
10903
  var init_normalize = __esm({
10059
10904
  "core/transparency/normalize.js"() {
10060
10905
  init_claims();
10061
- init_registry2();
10906
+ init_registry4();
10062
10907
  PROVENANCE_KEYS = [
10063
10908
  "createdBy",
10064
10909
  "createdAt",
@@ -10222,7 +11067,7 @@
10222
11067
  "core/transparency/attach.js"() {
10223
11068
  init_normalize();
10224
11069
  init_renderer();
10225
- init_registry2();
11070
+ init_registry4();
10226
11071
  defaultRegistry = createRegistry();
10227
11072
  VelinTransparency = {
10228
11073
  attach,
@@ -10455,7 +11300,7 @@
10455
11300
  attach2(el);
10456
11301
  }
10457
11302
  });
10458
- for (const motion of ["velin-reveal", "velin-fade", "velin-slide", "velin-scale", "velin-parallax", "velin-hover", "velin-stagger", "velin-scroll"]) {
11303
+ for (const motion of ["velin-motion", "velin-trigger", "velin-duration", "velin-delay", "velin-ease", "velin-timeline", "velin-motion-sequence", "velin-reveal", "velin-fade", "velin-slide", "velin-scale", "velin-parallax", "velin-hover", "velin-stagger", "velin-scroll"]) {
10459
11304
  registerAttribute(motion, { enhance() {
10460
11305
  } });
10461
11306
  }
@@ -10486,7 +11331,7 @@
10486
11331
  return [...registry.keys()];
10487
11332
  }
10488
11333
  var registry, enhanced;
10489
- var init_registry3 = __esm({
11334
+ var init_registry5 = __esm({
10490
11335
  "core/attributes/registry.js"() {
10491
11336
  init_runtime();
10492
11337
  init_motion();
@@ -10506,7 +11351,7 @@
10506
11351
  });
10507
11352
  var init_attributes = __esm({
10508
11353
  "core/attributes/index.js"() {
10509
- init_registry3();
11354
+ init_registry5();
10510
11355
  }
10511
11356
  });
10512
11357