@hyvnt/hyvui 0.3.0 → 0.4.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 (170) hide show
  1. package/README.md +37 -7
  2. package/dist/components/ambient/ArcaneVein.svelte +151 -0
  3. package/dist/components/ambient/ArcaneVein.svelte.d.ts +31 -0
  4. package/dist/components/ambient/BrassFiligree.svelte +109 -0
  5. package/dist/components/ambient/BrassFiligree.svelte.d.ts +20 -0
  6. package/dist/components/ambient/CornerBrackets.svelte +8 -0
  7. package/dist/components/ambient/CornerBrackets.svelte.d.ts +8 -0
  8. package/dist/components/ambient/CrystalShard.svelte +151 -0
  9. package/dist/components/ambient/CrystalShard.svelte.d.ts +19 -0
  10. package/dist/components/ambient/DataStream.svelte +7 -1
  11. package/dist/components/ambient/DataStream.svelte.d.ts +6 -0
  12. package/dist/components/ambient/EnergyArc.svelte +189 -0
  13. package/dist/components/ambient/EnergyArc.svelte.d.ts +32 -0
  14. package/dist/components/ambient/GlyphMark.svelte +6 -0
  15. package/dist/components/ambient/GlyphMark.svelte.d.ts +6 -0
  16. package/dist/components/ambient/GridOverlay.svelte +8 -0
  17. package/dist/components/ambient/GridOverlay.svelte.d.ts +8 -0
  18. package/dist/components/ambient/HexGrid.svelte +119 -0
  19. package/dist/components/ambient/HexGrid.svelte.d.ts +21 -0
  20. package/dist/components/ambient/ParallaxLayer.svelte +9 -1
  21. package/dist/components/ambient/ParallaxLayer.svelte.d.ts +7 -0
  22. package/dist/components/ambient/ScanBand.svelte +8 -0
  23. package/dist/components/ambient/ScanBand.svelte.d.ts +8 -0
  24. package/dist/components/ambient/ShimmerCloud.svelte +180 -0
  25. package/dist/components/ambient/ShimmerCloud.svelte.d.ts +21 -0
  26. package/dist/components/ambient/SignalRing.svelte +7 -1
  27. package/dist/components/ambient/SignalRing.svelte.d.ts +6 -0
  28. package/dist/components/ambient/ThreadLine.svelte +7 -0
  29. package/dist/components/ambient/ThreadLine.svelte.d.ts +7 -0
  30. package/dist/components/ambient/Vignette.svelte +6 -0
  31. package/dist/components/ambient/Vignette.svelte.d.ts +6 -0
  32. package/dist/components/depth/DepthLayer.svelte +8 -0
  33. package/dist/components/depth/DepthLayer.svelte.d.ts +8 -0
  34. package/dist/components/depth/DepthStage.svelte +8 -4
  35. package/dist/components/depth/DepthStage.svelte.d.ts +8 -0
  36. package/dist/components/depth/FloatCard.svelte +17 -1
  37. package/dist/components/depth/FloatCard.svelte.d.ts +8 -0
  38. package/dist/components/depth/HorizonGrid.svelte +25 -0
  39. package/dist/components/depth/HorizonGrid.svelte.d.ts +9 -0
  40. package/dist/components/depth/Plinth.svelte +10 -0
  41. package/dist/components/depth/Plinth.svelte.d.ts +10 -0
  42. package/dist/components/display/Avatar.svelte +5 -0
  43. package/dist/components/display/Avatar.svelte.d.ts +5 -0
  44. package/dist/components/display/Badge.svelte +16 -0
  45. package/dist/components/display/Badge.svelte.d.ts +6 -0
  46. package/dist/components/display/Blockquote.svelte +4 -0
  47. package/dist/components/display/Blockquote.svelte.d.ts +4 -0
  48. package/dist/components/display/CodeBlock.svelte +5 -0
  49. package/dist/components/display/CodeBlock.svelte.d.ts +5 -0
  50. package/dist/components/display/MetricCard.svelte +23 -0
  51. package/dist/components/display/MetricCard.svelte.d.ts +6 -0
  52. package/dist/components/display/Table.svelte +7 -0
  53. package/dist/components/display/Table.svelte.d.ts +7 -0
  54. package/dist/components/feedback/Alert.svelte +24 -0
  55. package/dist/components/feedback/Alert.svelte.d.ts +6 -0
  56. package/dist/components/feedback/EmptyState.svelte +7 -0
  57. package/dist/components/feedback/EmptyState.svelte.d.ts +7 -0
  58. package/dist/components/feedback/ErrorState.svelte +5 -0
  59. package/dist/components/feedback/ErrorState.svelte.d.ts +5 -0
  60. package/dist/components/feedback/Skeleton.svelte +6 -0
  61. package/dist/components/feedback/Skeleton.svelte.d.ts +6 -0
  62. package/dist/components/feedback/StatusDot.svelte +36 -1
  63. package/dist/components/feedback/StatusDot.svelte.d.ts +6 -0
  64. package/dist/components/feedback/StatusLine.svelte +8 -2
  65. package/dist/components/feedback/StatusLine.svelte.d.ts +6 -0
  66. package/dist/components/feedback/Toast.svelte +16 -2
  67. package/dist/components/feedback/Toast.svelte.d.ts +10 -0
  68. package/dist/components/inputs/Button.svelte +74 -4
  69. package/dist/components/inputs/Button.svelte.d.ts +8 -0
  70. package/dist/components/inputs/Checkbox.svelte +5 -0
  71. package/dist/components/inputs/Checkbox.svelte.d.ts +5 -0
  72. package/dist/components/inputs/FileUpload.svelte +5 -0
  73. package/dist/components/inputs/FileUpload.svelte.d.ts +5 -0
  74. package/dist/components/inputs/Input.svelte +10 -2
  75. package/dist/components/inputs/Input.svelte.d.ts +7 -0
  76. package/dist/components/inputs/Select.svelte +8 -0
  77. package/dist/components/inputs/Select.svelte.d.ts +8 -0
  78. package/dist/components/inputs/Textarea.svelte +9 -2
  79. package/dist/components/inputs/Textarea.svelte.d.ts +6 -0
  80. package/dist/components/inputs/Toggle.svelte +6 -1
  81. package/dist/components/inputs/Toggle.svelte.d.ts +5 -0
  82. package/dist/components/layout/Card.svelte +11 -0
  83. package/dist/components/layout/Card.svelte.d.ts +11 -0
  84. package/dist/components/layout/Drawer.svelte +7 -0
  85. package/dist/components/layout/Drawer.svelte.d.ts +6 -0
  86. package/dist/components/layout/Grid.svelte +10 -0
  87. package/dist/components/layout/Grid.svelte.d.ts +10 -0
  88. package/dist/components/layout/Modal.svelte +15 -0
  89. package/dist/components/layout/Modal.svelte.d.ts +10 -0
  90. package/dist/components/layout/Panel.svelte +9 -0
  91. package/dist/components/layout/Panel.svelte.d.ts +9 -0
  92. package/dist/components/layout/Popover.svelte +10 -0
  93. package/dist/components/layout/Popover.svelte.d.ts +9 -0
  94. package/dist/components/layout/Stack.svelte +12 -0
  95. package/dist/components/layout/Stack.svelte.d.ts +12 -0
  96. package/dist/components/navigation/Breadcrumb.svelte +8 -0
  97. package/dist/components/navigation/Breadcrumb.svelte.d.ts +8 -0
  98. package/dist/components/navigation/DropdownMenu.svelte +12 -0
  99. package/dist/components/navigation/DropdownMenu.svelte.d.ts +12 -0
  100. package/dist/components/navigation/SidebarNav.svelte +10 -0
  101. package/dist/components/navigation/SidebarNav.svelte.d.ts +9 -0
  102. package/dist/components/navigation/Tabs.svelte +26 -1
  103. package/dist/components/navigation/Tabs.svelte.d.ts +8 -0
  104. package/dist/components/navigation/Topbar.svelte +9 -0
  105. package/dist/components/navigation/Topbar.svelte.d.ts +9 -0
  106. package/dist/components/patterns/ActionBar.svelte +11 -0
  107. package/dist/components/patterns/ActionBar.svelte.d.ts +10 -0
  108. package/dist/components/patterns/ChapterMark.svelte +152 -0
  109. package/dist/components/patterns/ChapterMark.svelte.d.ts +19 -0
  110. package/dist/components/patterns/ConfirmDialog.svelte +12 -0
  111. package/dist/components/patterns/ConfirmDialog.svelte.d.ts +12 -0
  112. package/dist/components/patterns/DepthPortal.svelte +123 -0
  113. package/dist/components/patterns/DepthPortal.svelte.d.ts +24 -0
  114. package/dist/components/patterns/Manifesto.svelte +171 -0
  115. package/dist/components/patterns/Manifesto.svelte.d.ts +25 -0
  116. package/dist/components/patterns/PageHeader.svelte +8 -0
  117. package/dist/components/patterns/PageHeader.svelte.d.ts +8 -0
  118. package/dist/components/patterns/PullQuote.svelte +145 -0
  119. package/dist/components/patterns/PullQuote.svelte.d.ts +23 -0
  120. package/dist/components/patterns/RegisterSwitcher.svelte +132 -0
  121. package/dist/components/patterns/RegisterSwitcher.svelte.d.ts +21 -0
  122. package/dist/components/patterns/SearchBar.svelte +5 -0
  123. package/dist/components/patterns/SearchBar.svelte.d.ts +5 -0
  124. package/dist/components/patterns/ShowcaseFrame.svelte +117 -0
  125. package/dist/components/patterns/ShowcaseFrame.svelte.d.ts +28 -0
  126. package/dist/components/patterns/TerminalBoot.svelte +15 -1
  127. package/dist/components/patterns/TerminalBoot.svelte.d.ts +12 -0
  128. package/dist/components/primitives/Divider.svelte +30 -0
  129. package/dist/components/primitives/Divider.svelte.d.ts +5 -0
  130. package/dist/components/primitives/Icon.svelte +9 -0
  131. package/dist/components/primitives/Icon.svelte.d.ts +9 -0
  132. package/dist/components/primitives/Label.svelte +6 -0
  133. package/dist/components/primitives/Label.svelte.d.ts +6 -0
  134. package/dist/components/primitives/Surface.svelte +67 -2
  135. package/dist/components/primitives/Surface.svelte.d.ts +7 -0
  136. package/dist/components/primitives/Text.svelte +32 -0
  137. package/dist/components/primitives/Text.svelte.d.ts +7 -0
  138. package/dist/components/scenes/ArchiveScene.svelte +10 -0
  139. package/dist/components/scenes/ArchiveScene.svelte.d.ts +10 -0
  140. package/dist/components/scenes/DepthScene.svelte +128 -0
  141. package/dist/components/scenes/DepthScene.svelte.d.ts +36 -0
  142. package/dist/components/scenes/LogScene.svelte +14 -0
  143. package/dist/components/scenes/LogScene.svelte.d.ts +14 -0
  144. package/dist/components/scenes/NarrativeScene.svelte +9 -0
  145. package/dist/components/scenes/NarrativeScene.svelte.d.ts +9 -0
  146. package/dist/components/scenes/ReadoutScene.svelte +11 -0
  147. package/dist/components/scenes/ReadoutScene.svelte.d.ts +11 -0
  148. package/dist/components/scenes/StageScene.svelte +14 -0
  149. package/dist/components/scenes/StageScene.svelte.d.ts +14 -0
  150. package/dist/components/system/AppShell.svelte +62 -0
  151. package/dist/components/system/AppShell.svelte.d.ts +32 -0
  152. package/dist/examples/ArcaneShard.svelte +364 -0
  153. package/dist/examples/ArcaneShard.svelte.d.ts +3 -0
  154. package/dist/examples/HextechForge.svelte +324 -0
  155. package/dist/examples/HextechForge.svelte.d.ts +3 -0
  156. package/dist/index.d.ts +15 -1
  157. package/dist/index.js +16 -1
  158. package/dist/styles.css +2 -0
  159. package/dist/system/actions/echo.js +13 -4
  160. package/dist/system/actions/resolve.js +20 -6
  161. package/dist/system/actions/reveal.js +1 -1
  162. package/dist/system/actions/surface.js +1 -3
  163. package/dist/system/register.d.ts +1 -1
  164. package/dist/system/register.js +5 -1
  165. package/dist/tokens/arcane.css +96 -0
  166. package/dist/tokens/hextech.css +96 -0
  167. package/dist/tokens/tokens.css +6 -4
  168. package/dist/tokens/tokens.d.ts +41 -0
  169. package/dist/tokens/tokens.js +41 -0
  170. package/package.json +6 -2
@@ -0,0 +1,189 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+
4
+ /**
5
+ * Decorative energy arc (SVG quadratic bezier) between two points.
6
+ * Under `hextech`: single clean cyan arc with traveling dot.
7
+ * Under `arcane`: violet arc with jitter and brighter particle.
8
+ * Parent must have `position: relative`. Renders `aria-hidden`.
9
+ *
10
+ * @example
11
+ * <div style="position: relative; height: 100px;">
12
+ * <EnergyArc x1="10%" y1="100%" x2="90%" y2="100%" bend={-40} />
13
+ * </div>
14
+ */
15
+ interface Props {
16
+ /** Start x (CSS %). */
17
+ x1?: string;
18
+ /** Start y (CSS %). */
19
+ y1?: string;
20
+ /** End x (CSS %). */
21
+ x2?: string;
22
+ /** End y (CSS %). */
23
+ y2?: string;
24
+ /** Control point y-offset in px (negative = arc up, positive = arc down). */
25
+ bend?: number;
26
+ /** Traveling particle speed in seconds. */
27
+ speed?: number;
28
+ /** Enable traveling particle. */
29
+ animated?: boolean;
30
+ /** Additional CSS classes. */
31
+ class?: string;
32
+ }
33
+
34
+ let {
35
+ x1 = '10%',
36
+ y1 = '50%',
37
+ x2 = '90%',
38
+ y2 = '50%',
39
+ bend = -32,
40
+ speed = 2,
41
+ animated = true,
42
+ class: className = ''
43
+ }: Props = $props();
44
+
45
+ const prefersReduced =
46
+ typeof window !== 'undefined'
47
+ ? window.matchMedia('(prefers-reduced-motion: reduce)').matches
48
+ : false;
49
+
50
+ const dur = $derived(`${speed}s`);
51
+ const durJitter = $derived(`${speed * 1.4}s`);
52
+ const shouldAnimate = $derived(animated && !prefersReduced);
53
+
54
+ // We don't know actual px coords until render, so the bezier control point
55
+ // is expressed as a data attribute and animated via SVG animateTransform.
56
+ // For the path `d` we use a placeholder that gets overridden by JS,
57
+ // but since this is a portoflio component, a CSS-only approximation works:
58
+ // we anchor a <path> using % units for x/y and em for control offset.
59
+
60
+ const filterId = `ea-glow-${Math.random().toString(36).slice(2, 8)}`;
61
+
62
+ // Bezier path string: Q cx,cy x2,y2 — control point is midpoint elevated by `bend`
63
+ // We use computed path as a string and pass it as an attribute.
64
+ // Since SVG doesn't mix % and px in path d, we keep all in % and treat bend as %.
65
+ const bendPct = $derived(`${bend}px`);
66
+
67
+ // Path using SVG's ability to do absolute coordinates in %. Not directly possible,
68
+ // so we use a wrapper approach: the SVG has viewBox "0 0 100 100" and we translate %.
69
+ // Keep it simple: use an SVG with proportional coordinates.
70
+ // The consumer positions the SVG fill on the parent, so 0 0 100 100 viewBox is fine.
71
+ const mid = '50%';
72
+ const path = $derived(`M ${x1} ${y1} Q ${mid} calc(50% + ${bendPct}) ${x2} ${y2}`);
73
+ </script>
74
+
75
+ <svg class={cn('hyvui-energy-arc', className)} aria-hidden="true">
76
+ <defs>
77
+ <filter id={filterId} x="-50%" y="-100%" width="200%" height="300%">
78
+ <feGaussianBlur stdDeviation="2" result="blur" />
79
+ <feMerge>
80
+ <feMergeNode in="blur" />
81
+ <feMergeNode in="SourceGraphic" />
82
+ </feMerge>
83
+ </filter>
84
+ </defs>
85
+
86
+ <!-- glow halo -->
87
+ <path
88
+ class="hyvui-ea-halo"
89
+ d={path}
90
+ fill="none"
91
+ stroke-width="5"
92
+ filter="url(#{filterId})"
93
+ />
94
+
95
+ <!-- main arc line -->
96
+ <path
97
+ class="hyvui-ea-line"
98
+ d={path}
99
+ fill="none"
100
+ stroke-width="1"
101
+ />
102
+
103
+ <!-- traveling particle -->
104
+ {#if shouldAnimate}
105
+ <circle class="hyvui-ea-particle" r="3">
106
+ <animateMotion dur={dur} repeatCount="indefinite" keyPoints="0;1" keyTimes="0;1" calcMode="linear">
107
+ <mpath>
108
+ <path d={path} />
109
+ </mpath>
110
+ </animateMotion>
111
+ <animate
112
+ attributeName="opacity"
113
+ values="0;1;1;0"
114
+ keyTimes="0;0.1;0.85;1"
115
+ dur={dur}
116
+ repeatCount="indefinite"
117
+ />
118
+ </circle>
119
+
120
+ <!-- arcane gets a second jitter particle traveling opposite direction -->
121
+ <circle class="hyvui-ea-particle hyvui-ea-particle--jitter" r="2">
122
+ <animateMotion dur={durJitter} repeatCount="indefinite" keyPoints="1;0" keyTimes="0;1" calcMode="linear">
123
+ <mpath>
124
+ <path d={path} />
125
+ </mpath>
126
+ </animateMotion>
127
+ <animate
128
+ attributeName="opacity"
129
+ values="0;0.5;0.5;0"
130
+ keyTimes="0;0.12;0.88;1"
131
+ dur={durJitter}
132
+ repeatCount="indefinite"
133
+ />
134
+ </circle>
135
+ {/if}
136
+ </svg>
137
+
138
+ <style>
139
+ .hyvui-energy-arc {
140
+ position: absolute;
141
+ inset: 0;
142
+ width: 100%;
143
+ height: 100%;
144
+ pointer-events: none;
145
+ overflow: visible;
146
+ }
147
+
148
+ /* ── default (field-notebook) ─────────────────────────────────────── */
149
+ .hyvui-ea-halo { stroke: transparent; }
150
+ .hyvui-ea-line { stroke: rgba(199, 156, 87, 0.25); }
151
+ .hyvui-ea-particle { fill: rgba(199, 156, 87, 0.8); }
152
+ .hyvui-ea-particle--jitter { display: none; }
153
+
154
+ /* ── hextech: clean cyan arc, single particle ─────────────────────── */
155
+ :global([data-register='hextech']) .hyvui-ea-halo {
156
+ stroke: rgba(93, 217, 240, 0.12);
157
+ }
158
+ :global([data-register='hextech']) .hyvui-ea-line {
159
+ stroke: rgba(93, 217, 240, 0.55);
160
+ }
161
+ :global([data-register='hextech']) .hyvui-ea-particle {
162
+ fill: rgba(184, 230, 242, 1);
163
+ }
164
+ :global([data-register='hextech']) .hyvui-ea-particle--jitter {
165
+ display: none;
166
+ }
167
+
168
+ /* ── arcane: violet arc, bidirectional particles ──────────────────── */
169
+ :global([data-register='arcane']) .hyvui-ea-halo {
170
+ stroke: rgba(184, 69, 201, 0.2);
171
+ }
172
+ :global([data-register='arcane']) .hyvui-ea-line {
173
+ stroke: rgba(184, 69, 201, 0.6);
174
+ }
175
+ :global([data-register='arcane']) .hyvui-ea-particle {
176
+ fill: rgba(233, 76, 188, 1);
177
+ }
178
+ :global([data-register='arcane']) .hyvui-ea-particle--jitter {
179
+ display: block;
180
+ fill: rgba(184, 69, 201, 0.7);
181
+ }
182
+
183
+ @media (prefers-reduced-motion: reduce) {
184
+ .hyvui-ea-particle,
185
+ .hyvui-ea-particle--jitter {
186
+ display: none;
187
+ }
188
+ }
189
+ </style>
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Decorative energy arc (SVG quadratic bezier) between two points.
3
+ * Under `hextech`: single clean cyan arc with traveling dot.
4
+ * Under `arcane`: violet arc with jitter and brighter particle.
5
+ * Parent must have `position: relative`. Renders `aria-hidden`.
6
+ *
7
+ * @example
8
+ * <div style="position: relative; height: 100px;">
9
+ * <EnergyArc x1="10%" y1="100%" x2="90%" y2="100%" bend={-40} />
10
+ * </div>
11
+ */
12
+ interface Props {
13
+ /** Start x (CSS %). */
14
+ x1?: string;
15
+ /** Start y (CSS %). */
16
+ y1?: string;
17
+ /** End x (CSS %). */
18
+ x2?: string;
19
+ /** End y (CSS %). */
20
+ y2?: string;
21
+ /** Control point y-offset in px (negative = arc up, positive = arc down). */
22
+ bend?: number;
23
+ /** Traveling particle speed in seconds. */
24
+ speed?: number;
25
+ /** Enable traveling particle. */
26
+ animated?: boolean;
27
+ /** Additional CSS classes. */
28
+ class?: string;
29
+ }
30
+ declare const EnergyArc: import("svelte").Component<Props, {}, "">;
31
+ type EnergyArc = ReturnType<typeof EnergyArc>;
32
+ export default EnergyArc;
@@ -1,6 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * Decorative SVG glyph. Renders `aria-hidden`.
6
+ * @example
7
+ * <GlyphMark variant="reticle" size={32} />
8
+ * <GlyphMark variant="cross" color="var(--accent)" />
9
+ */
4
10
  interface Props {
5
11
  /** Glyph variant. */
6
12
  variant?: 'cross' | 'reticle' | 'coord' | 'mark';
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Decorative SVG glyph. Renders `aria-hidden`.
3
+ * @example
4
+ * <GlyphMark variant="reticle" size={32} />
5
+ * <GlyphMark variant="cross" color="var(--accent)" />
6
+ */
1
7
  interface Props {
2
8
  /** Glyph variant. */
3
9
  variant?: 'cross' | 'reticle' | 'coord' | 'mark';
@@ -1,6 +1,14 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * Decorative. Parent must have `position: relative`. Renders `aria-hidden`.
6
+ * @example
7
+ * <div style="position: relative;">
8
+ * <GridOverlay />
9
+ * content here
10
+ * </div>
11
+ */
4
12
  interface Props {
5
13
  /** Additional CSS classes. */
6
14
  class?: string;
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Decorative. Parent must have `position: relative`. Renders `aria-hidden`.
3
+ * @example
4
+ * <div style="position: relative;">
5
+ * <GridOverlay />
6
+ * content here
7
+ * </div>
8
+ */
1
9
  interface Props {
2
10
  /** Additional CSS classes. */
3
11
  class?: string;
@@ -0,0 +1,119 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+
4
+ /**
5
+ * Decorative hex grid overlay. Adapts color and character per active register:
6
+ * hextech → cyan precise etching; arcane → violet cracked. Parent must have
7
+ * `position: relative`. Renders `aria-hidden`.
8
+ * @example
9
+ * <div style="position: relative;">
10
+ * <HexGrid />
11
+ * content here
12
+ * </div>
13
+ */
14
+ interface Props {
15
+ /** Controls animation playback. */
16
+ animated?: boolean;
17
+ /** Override grid opacity (0–1). Defaults to register's --reg-ornament-opacity. */
18
+ opacity?: number | undefined;
19
+ /** Additional CSS classes. */
20
+ class?: string;
21
+ }
22
+
23
+ let { animated = true, opacity = undefined, class: className = '' }: Props = $props();
24
+
25
+ const prefersReduced =
26
+ typeof window !== 'undefined'
27
+ ? window.matchMedia('(prefers-reduced-motion: reduce)').matches
28
+ : false;
29
+
30
+ const shouldAnimate = $derived(animated && !prefersReduced);
31
+ </script>
32
+
33
+ <div
34
+ class={cn('hyvui-hex-grid', shouldAnimate && 'hyvui-hex-grid--animated', className)}
35
+ style={opacity !== undefined ? `--hex-opacity-override: ${opacity}` : undefined}
36
+ aria-hidden="true"
37
+ ></div>
38
+
39
+ <style>
40
+ .hyvui-hex-grid {
41
+ position: absolute;
42
+ inset: 0;
43
+ pointer-events: none;
44
+
45
+ /* Hex pattern via three-angle stripes (vertical + two diagonals).
46
+ Color and opacity come from register tokens so they shift automatically. */
47
+ background-image:
48
+ linear-gradient(to right, var(--hg-color) 1px, transparent 1px),
49
+ linear-gradient(60deg, var(--hg-color) 1px, transparent 1px),
50
+ linear-gradient(-60deg, var(--hg-color) 1px, transparent 1px);
51
+ background-size: 40px 23px;
52
+
53
+ opacity: var(--hex-opacity-override, var(--reg-ornament-opacity));
54
+ mask-image: linear-gradient(to bottom, transparent, black 12%, black 88%, transparent);
55
+ -webkit-mask-image: linear-gradient(
56
+ to bottom,
57
+ transparent,
58
+ black 12%,
59
+ black 88%,
60
+ transparent
61
+ );
62
+
63
+ /* default color (field-notebook) */
64
+ --hg-color: rgba(199, 156, 87, 0.45);
65
+ }
66
+
67
+ /* ── hextech ─ cyan precision ─────────────────────────────────────── */
68
+ :global([data-register='hextech']) .hyvui-hex-grid {
69
+ --hg-color: rgba(93, 217, 240, 0.55);
70
+ background-size: 48px 28px;
71
+ }
72
+
73
+ /* ── arcane ─ violet instability ─────────────────────────────────── */
74
+ :global([data-register='arcane']) .hyvui-hex-grid {
75
+ --hg-color: rgba(184, 69, 201, 0.5);
76
+ background-size: 40px 23px;
77
+ }
78
+
79
+ /* ── pulse animation ─────────────────────────────────────────────── */
80
+ .hyvui-hex-grid--animated {
81
+ animation: hg-pulse var(--orn-shimmer-rate, 4s) var(--orn-pulse-rhythm, ease-in-out) infinite;
82
+ }
83
+
84
+ :global([data-register='arcane']) .hyvui-hex-grid--animated {
85
+ animation:
86
+ hg-pulse var(--orn-shimmer-rate, 2.4s) var(--orn-pulse-rhythm, ease-in-out) infinite,
87
+ hg-flicker 7s step-end infinite;
88
+ }
89
+
90
+ @keyframes hg-pulse {
91
+ 0%,
92
+ 100% {
93
+ opacity: var(--hex-opacity-override, var(--reg-ornament-opacity));
94
+ }
95
+ 50% {
96
+ opacity: calc(var(--hex-opacity-override, var(--reg-ornament-opacity)) * 1.8);
97
+ }
98
+ }
99
+
100
+ @keyframes hg-flicker {
101
+ 0%,
102
+ 97%,
103
+ 100% {
104
+ opacity: var(--hex-opacity-override, var(--reg-ornament-opacity));
105
+ }
106
+ 98% {
107
+ opacity: 0.02;
108
+ }
109
+ 99% {
110
+ opacity: calc(var(--hex-opacity-override, var(--reg-ornament-opacity)) * 2.2);
111
+ }
112
+ }
113
+
114
+ @media (prefers-reduced-motion: reduce) {
115
+ .hyvui-hex-grid--animated {
116
+ animation: none;
117
+ }
118
+ }
119
+ </style>
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Decorative hex grid overlay. Adapts color and character per active register:
3
+ * hextech → cyan precise etching; arcane → violet cracked. Parent must have
4
+ * `position: relative`. Renders `aria-hidden`.
5
+ * @example
6
+ * <div style="position: relative;">
7
+ * <HexGrid />
8
+ * content here
9
+ * </div>
10
+ */
11
+ interface Props {
12
+ /** Controls animation playback. */
13
+ animated?: boolean;
14
+ /** Override grid opacity (0–1). Defaults to register's --reg-ornament-opacity. */
15
+ opacity?: number | undefined;
16
+ /** Additional CSS classes. */
17
+ class?: string;
18
+ }
19
+ declare const HexGrid: import("svelte").Component<Props, {}, "">;
20
+ type HexGrid = ReturnType<typeof HexGrid>;
21
+ export default HexGrid;
@@ -2,6 +2,13 @@
2
2
  import { cn } from '../../utils/cn.js';
3
3
  import type { Snippet } from 'svelte';
4
4
 
5
+ /**
6
+ * Reads `--px` and `--py` CSS custom properties for pointer-driven parallax. Set these on a parent via JS.
7
+ * @example
8
+ * <div onpointermove={trackPointer} style="position:relative;">
9
+ * <ParallaxLayer strength={12}><GlyphMark /></ParallaxLayer>
10
+ * </div>
11
+ */
5
12
  interface Props {
6
13
  /** Motion multiplier applied to --px/--py custom properties. */
7
14
  strength?: number;
@@ -25,7 +32,8 @@
25
32
  <style>
26
33
  .hyvui-parallax {
27
34
  will-change: transform;
28
- transition: transform 0.15s ease-out;
35
+ backface-visibility: hidden;
36
+ transition: transform 0.15s var(--ease-smooth);
29
37
  }
30
38
 
31
39
  @media (prefers-reduced-motion: reduce) {
@@ -1,4 +1,11 @@
1
1
  import type { Snippet } from 'svelte';
2
+ /**
3
+ * Reads `--px` and `--py` CSS custom properties for pointer-driven parallax. Set these on a parent via JS.
4
+ * @example
5
+ * <div onpointermove={trackPointer} style="position:relative;">
6
+ * <ParallaxLayer strength={12}><GlyphMark /></ParallaxLayer>
7
+ * </div>
8
+ */
2
9
  interface Props {
3
10
  /** Motion multiplier applied to --px/--py custom properties. */
4
11
  strength?: number;
@@ -1,6 +1,14 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils/cn.js';
3
3
 
4
+ /**
5
+ * Decorative. Parent must have `position: relative`. Renders `aria-hidden`.
6
+ * @example
7
+ * <div style="position: relative;">
8
+ * <ScanBand axis="x" duration="6s" />
9
+ * content with scan line
10
+ * </div>
11
+ */
4
12
  interface Props {
5
13
  /** Enable the scan animation. */
6
14
  active?: boolean;
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Decorative. Parent must have `position: relative`. Renders `aria-hidden`.
3
+ * @example
4
+ * <div style="position: relative;">
5
+ * <ScanBand axis="x" duration="6s" />
6
+ * content with scan line
7
+ * </div>
8
+ */
1
9
  interface Props {
2
10
  /** Enable the scan animation. */
3
11
  active?: boolean;
@@ -0,0 +1,180 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../utils/cn.js';
3
+ import { onMount } from 'svelte';
4
+
5
+ /**
6
+ * Particle-smoke ambient effect using canvas.
7
+ * Under `hextech`: slow blue-mist dots, precise motion.
8
+ * Under `arcane`: pink/violet shimmer drift, chaotic.
9
+ * Parent must have `position: relative`. Renders `aria-hidden`.
10
+ *
11
+ * @example
12
+ * <div style="position: relative;">
13
+ * <ShimmerCloud />
14
+ * content
15
+ * </div>
16
+ */
17
+ interface Props {
18
+ /** Particle count. */
19
+ count?: number;
20
+ /** Additional CSS classes. */
21
+ class?: string;
22
+ }
23
+
24
+ let { count = 28, class: className = '' }: Props = $props();
25
+
26
+ const prefersReduced =
27
+ typeof window !== 'undefined'
28
+ ? window.matchMedia('(prefers-reduced-motion: reduce)').matches
29
+ : false;
30
+
31
+ let canvas: HTMLCanvasElement | undefined = $state();
32
+ let rafId: number | undefined;
33
+
34
+ type Particle = {
35
+ x: number;
36
+ y: number;
37
+ r: number;
38
+ vx: number;
39
+ vy: number;
40
+ alpha: number;
41
+ alphaDir: number;
42
+ alphaSpeed: number;
43
+ };
44
+
45
+ function getRegister(): string {
46
+ if (typeof document === 'undefined') return '';
47
+ return document.body.dataset.register ?? '';
48
+ }
49
+
50
+ function getParticleColor(register: string): string {
51
+ if (register === 'hextech') return '93, 217, 240';
52
+ if (register === 'arcane') return '184, 69, 201';
53
+ return '199, 156, 87';
54
+ }
55
+
56
+ function getParticleColorB(register: string): string {
57
+ // Second color for arcane (two-color particles add richness)
58
+ if (register === 'arcane') return '233, 76, 188';
59
+ return getParticleColor(register);
60
+ }
61
+
62
+ onMount(() => {
63
+ if (prefersReduced || !canvas) return;
64
+
65
+ const ctx = canvas.getContext('2d');
66
+ if (!ctx) return;
67
+
68
+ let particles: Particle[] = [];
69
+
70
+ function resize() {
71
+ if (!canvas || !canvas.parentElement) return;
72
+ const { width, height } = canvas.parentElement.getBoundingClientRect();
73
+ canvas.width = width;
74
+ canvas.height = height;
75
+ }
76
+
77
+ function spawn(): Particle {
78
+ const w = canvas?.width ?? 400;
79
+ const h = canvas?.height ?? 300;
80
+ const register = getRegister();
81
+ const fast = register === 'arcane';
82
+ return {
83
+ x: Math.random() * w,
84
+ y: Math.random() * h,
85
+ r: 1 + Math.random() * (fast ? 3 : 2),
86
+ vx: (Math.random() - 0.5) * (fast ? 0.45 : 0.2),
87
+ vy: -(Math.random() * (fast ? 0.5 : 0.3) + 0.05),
88
+ alpha: Math.random() * 0.3,
89
+ alphaDir: 1,
90
+ alphaSpeed: 0.003 + Math.random() * (fast ? 0.008 : 0.004)
91
+ };
92
+ }
93
+
94
+ resize();
95
+ particles = Array.from({ length: count }, spawn);
96
+
97
+ const ro = new ResizeObserver(resize);
98
+ if (canvas.parentElement) ro.observe(canvas.parentElement);
99
+
100
+ let io_visible = true;
101
+ const io = new IntersectionObserver((entries) => {
102
+ io_visible = entries[0]?.isIntersecting ?? true;
103
+ });
104
+ io.observe(canvas);
105
+
106
+ function draw() {
107
+ if (!ctx || !canvas) return;
108
+ const register = getRegister();
109
+ const colorA = getParticleColor(register);
110
+ const colorB = getParticleColorB(register);
111
+
112
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
113
+
114
+ if (io_visible) {
115
+ particles.forEach((p, i) => {
116
+ // breathing alpha
117
+ p.alpha += p.alphaDir * p.alphaSpeed;
118
+ if (p.alpha >= (register === 'arcane' ? 0.38 : 0.22)) p.alphaDir = -1;
119
+ if (p.alpha <= 0.02) p.alphaDir = 1;
120
+
121
+ // drift
122
+ p.x += p.vx;
123
+ p.y += p.vy;
124
+
125
+ // wrap
126
+ if (p.y < -10) p.y = canvas.height + 10;
127
+ if (p.x < -10) p.x = canvas.width + 10;
128
+ if (p.x > canvas.width + 10) p.x = -10;
129
+
130
+ const color = i % 2 === 0 ? colorA : colorB;
131
+ ctx.beginPath();
132
+ ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
133
+ ctx.fillStyle = `rgba(${color}, ${p.alpha})`;
134
+ ctx.fill();
135
+ });
136
+ }
137
+
138
+ rafId = requestAnimationFrame(draw);
139
+ }
140
+
141
+ rafId = requestAnimationFrame(draw);
142
+
143
+ return () => {
144
+ if (rafId !== undefined) cancelAnimationFrame(rafId);
145
+ ro.disconnect();
146
+ io.disconnect();
147
+ };
148
+ });
149
+ </script>
150
+
151
+ <canvas
152
+ bind:this={canvas}
153
+ class={cn('hyvui-shimmer-cloud', className)}
154
+ aria-hidden="true"
155
+ ></canvas>
156
+
157
+ <style>
158
+ .hyvui-shimmer-cloud {
159
+ position: absolute;
160
+ inset: 0;
161
+ width: 100%;
162
+ height: 100%;
163
+ pointer-events: none;
164
+ opacity: 0.7;
165
+ }
166
+
167
+ :global([data-register='hextech']) .hyvui-shimmer-cloud {
168
+ opacity: 0.55;
169
+ }
170
+
171
+ :global([data-register='arcane']) .hyvui-shimmer-cloud {
172
+ opacity: 0.85;
173
+ }
174
+
175
+ @media (prefers-reduced-motion: reduce) {
176
+ .hyvui-shimmer-cloud {
177
+ display: none;
178
+ }
179
+ }
180
+ </style>
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Particle-smoke ambient effect using canvas.
3
+ * Under `hextech`: slow blue-mist dots, precise motion.
4
+ * Under `arcane`: pink/violet shimmer drift, chaotic.
5
+ * Parent must have `position: relative`. Renders `aria-hidden`.
6
+ *
7
+ * @example
8
+ * <div style="position: relative;">
9
+ * <ShimmerCloud />
10
+ * content
11
+ * </div>
12
+ */
13
+ interface Props {
14
+ /** Particle count. */
15
+ count?: number;
16
+ /** Additional CSS classes. */
17
+ class?: string;
18
+ }
19
+ declare const ShimmerCloud: import("svelte").Component<Props, {}, "">;
20
+ type ShimmerCloud = ReturnType<typeof ShimmerCloud>;
21
+ export default ShimmerCloud;