@joewinke/jatui 0.1.33 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +22 -0
- package/dist/actions/attention.d.ts +24 -0
- package/dist/actions/attention.js +94 -0
- package/dist/actions/floating.d.ts +53 -0
- package/dist/actions/floating.js +158 -0
- package/dist/actions/staggerEntrance.d.ts +28 -0
- package/dist/actions/staggerEntrance.js +71 -0
- package/dist/actions/tooltip.d.ts +28 -0
- package/dist/actions/tooltip.js +186 -0
- package/dist/assets/sounds/README.md +47 -0
- package/dist/assets/sounds/error.d.ts +1 -0
- package/dist/assets/sounds/error.js +4 -0
- package/dist/assets/sounds/notify.d.ts +1 -0
- package/dist/assets/sounds/notify.js +4 -0
- package/dist/assets/sounds/pop.d.ts +1 -0
- package/dist/assets/sounds/pop.js +4 -0
- package/dist/assets/sounds/send.d.ts +1 -0
- package/dist/assets/sounds/send.js +4 -0
- package/dist/assets/sounds/success.d.ts +1 -0
- package/dist/assets/sounds/success.js +4 -0
- package/dist/assets/sounds/toggle.d.ts +1 -0
- package/dist/assets/sounds/toggle.js +4 -0
- package/dist/components/AnimatedNumber.svelte +112 -0
- package/dist/components/AnimatedNumber.svelte.d.ts +8 -0
- package/dist/components/Badge.svelte +75 -4
- package/dist/components/Badge.svelte.d.ts +6 -1
- package/dist/components/Button.svelte +196 -21
- package/dist/components/Button.svelte.d.ts +10 -1
- package/dist/components/Carousel.svelte +265 -0
- package/dist/components/Carousel.svelte.d.ts +21 -0
- package/dist/components/ChipInput.svelte +63 -3
- package/dist/components/Collapse.svelte +70 -14
- package/dist/components/Collapse.svelte.d.ts +11 -0
- package/dist/components/ColorSelector.svelte +21 -24
- package/dist/components/CommandPalette.svelte +475 -0
- package/dist/components/CommandPalette.svelte.d.ts +3 -0
- package/dist/components/ContextMenu.svelte +9 -73
- package/dist/components/CopyButton.svelte +156 -0
- package/dist/components/CopyButton.svelte.d.ts +12 -0
- package/dist/components/HoldToConfirm.svelte +183 -0
- package/dist/components/HoldToConfirm.svelte.d.ts +11 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte +54 -8
- package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +3 -0
- package/dist/components/PasswordMeter.svelte +87 -0
- package/dist/components/PasswordMeter.svelte.d.ts +8 -0
- package/dist/components/PinInput.svelte +186 -0
- package/dist/components/PinInput.svelte.d.ts +13 -0
- package/dist/components/QuantityStepper.svelte +185 -0
- package/dist/components/QuantityStepper.svelte.d.ts +12 -0
- package/dist/components/Skeleton.svelte +123 -0
- package/dist/components/Skeleton.svelte.d.ts +12 -0
- package/dist/components/SpeechForm.svelte +37 -0
- package/dist/components/StatusBadge.svelte +31 -3
- package/dist/components/StatusBadge.svelte.d.ts +0 -5
- package/dist/components/Tabs.svelte +270 -0
- package/dist/components/Tabs.svelte.d.ts +15 -0
- package/dist/components/TextInput.svelte +138 -38
- package/dist/components/TextInput.svelte.d.ts +9 -1
- package/dist/components/VoicePlayer.svelte +51 -0
- package/dist/components/basic/Alert.svelte +36 -0
- package/dist/components/basic/Alert.svelte.d.ts +9 -0
- package/dist/components/basic/Breadcrumb.svelte +27 -0
- package/dist/components/basic/Breadcrumb.svelte.d.ts +11 -0
- package/dist/components/basic/ButtonGroup.svelte +15 -0
- package/dist/components/basic/ButtonGroup.svelte.d.ts +8 -0
- package/dist/components/basic/Checkbox.svelte +85 -0
- package/dist/components/basic/Checkbox.svelte.d.ts +15 -0
- package/dist/components/basic/Empty.svelte +17 -0
- package/dist/components/basic/Empty.svelte.d.ts +8 -0
- package/dist/components/basic/Kbd.svelte +16 -0
- package/dist/components/basic/Kbd.svelte.d.ts +8 -0
- package/dist/components/basic/Pagination.svelte +104 -0
- package/dist/components/basic/Pagination.svelte.d.ts +12 -0
- package/dist/components/basic/RadioGroup.svelte +71 -0
- package/dist/components/basic/RadioGroup.svelte.d.ts +18 -0
- package/dist/components/basic/Separator.svelte +19 -0
- package/dist/components/basic/Separator.svelte.d.ts +8 -0
- package/dist/components/basic/Slider.svelte +72 -0
- package/dist/components/basic/Slider.svelte.d.ts +17 -0
- package/dist/components/basic/Switch.svelte +88 -0
- package/dist/components/basic/Switch.svelte.d.ts +14 -0
- package/dist/components/basic/Toggle.svelte +43 -0
- package/dist/components/basic/Toggle.svelte.d.ts +14 -0
- package/dist/components/graph/GraphCanvas.svelte +103 -0
- package/dist/components/graph/GraphCanvas.svelte.d.ts +22 -0
- package/dist/components/graph/JatuiNode.svelte +128 -0
- package/dist/components/graph/JatuiNode.svelte.d.ts +14 -0
- package/dist/components/graph/theme.d.ts +27 -0
- package/dist/components/graph/theme.js +136 -0
- package/dist/components/messaging/MessageItem.svelte +92 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +5 -0
- package/dist/components/messaging/TypingIndicator.svelte +63 -0
- package/dist/components/messaging/TypingIndicator.svelte.d.ts +7 -0
- package/dist/components/pipeline/PipelineColumn.svelte +44 -3
- package/dist/components/progress/ProgressBar.svelte +189 -0
- package/dist/components/progress/ProgressBar.svelte.d.ts +17 -0
- package/dist/components/progress/ProgressRing.svelte +138 -0
- package/dist/components/progress/ProgressRing.svelte.d.ts +12 -0
- package/dist/components/progress/Steps.svelte +195 -0
- package/dist/components/progress/Steps.svelte.d.ts +14 -0
- package/dist/components/shell/NavigationMenu.svelte +422 -0
- package/dist/components/shell/NavigationMenu.svelte.d.ts +43 -0
- package/dist/components/shell/Sidebar.svelte +276 -0
- package/dist/components/shell/Sidebar.svelte.d.ts +32 -0
- package/dist/components/shell/SidebarGroup.svelte +180 -0
- package/dist/components/shell/SidebarGroup.svelte.d.ts +19 -0
- package/dist/components/shell/SidebarItem.svelte +170 -0
- package/dist/components/shell/SidebarItem.svelte.d.ts +24 -0
- package/dist/components/shell/shell.d.ts +30 -0
- package/dist/components/shell/shell.js +65 -0
- package/dist/components/table/DataTable.svelte +364 -0
- package/dist/components/table/DataTable.svelte.d.ts +4 -0
- package/dist/components/table/flexRender.d.ts +31 -0
- package/dist/components/table/flexRender.js +32 -0
- package/dist/components/table/types.d.ts +28 -0
- package/dist/components/table/types.js +1 -0
- package/dist/components/toast/ToastHost.svelte +21 -0
- package/dist/components/toast/ToastHost.svelte.d.ts +3 -0
- package/dist/components/toast/ToastItem.svelte +287 -0
- package/dist/components/toast/ToastItem.svelte.d.ts +9 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +67 -0
- package/dist/showcase/AnimatedBeam.svelte +183 -0
- package/dist/showcase/AnimatedBeam.svelte.d.ts +26 -0
- package/dist/showcase/AuroraDrift.svelte +74 -0
- package/dist/showcase/AuroraDrift.svelte.d.ts +9 -0
- package/dist/showcase/BentoCard.svelte +50 -0
- package/dist/showcase/BentoCard.svelte.d.ts +14 -0
- package/dist/showcase/BentoGrid.svelte +43 -0
- package/dist/showcase/BentoGrid.svelte.d.ts +12 -0
- package/dist/showcase/BorderBeam.svelte +79 -0
- package/dist/showcase/BorderBeam.svelte.d.ts +12 -0
- package/dist/showcase/ClipWipe.svelte +82 -0
- package/dist/showcase/ClipWipe.svelte.d.ts +12 -0
- package/dist/showcase/Confetti.svelte +71 -0
- package/dist/showcase/Confetti.svelte.d.ts +10 -0
- package/dist/showcase/CursorSpotlight.svelte +85 -0
- package/dist/showcase/CursorSpotlight.svelte.d.ts +9 -0
- package/dist/showcase/DeviceMock.svelte +186 -0
- package/dist/showcase/DeviceMock.svelte.d.ts +11 -0
- package/dist/showcase/Dock.svelte +123 -0
- package/dist/showcase/Dock.svelte.d.ts +17 -0
- package/dist/showcase/FlipCard.svelte +103 -0
- package/dist/showcase/FlipCard.svelte.d.ts +10 -0
- package/dist/showcase/FocusReveal.svelte +83 -0
- package/dist/showcase/FocusReveal.svelte.d.ts +11 -0
- package/dist/showcase/Globe.svelte +202 -0
- package/dist/showcase/Globe.svelte.d.ts +16 -0
- package/dist/showcase/KenBurns.svelte +105 -0
- package/dist/showcase/KenBurns.svelte.d.ts +13 -0
- package/dist/showcase/Marquee.svelte +89 -0
- package/dist/showcase/Marquee.svelte.d.ts +9 -0
- package/dist/showcase/ParallaxTilt.svelte +98 -0
- package/dist/showcase/ParallaxTilt.svelte.d.ts +10 -0
- package/dist/showcase/ScrambleText.svelte +98 -0
- package/dist/showcase/ScrambleText.svelte.d.ts +11 -0
- package/dist/showcase/ShineSweep.svelte +81 -0
- package/dist/showcase/ShineSweep.svelte.d.ts +9 -0
- package/dist/showcase/Terminal.svelte +230 -0
- package/dist/showcase/Terminal.svelte.d.ts +18 -0
- package/dist/showcase/TextSplitReveal.svelte +146 -0
- package/dist/showcase/TextSplitReveal.svelte.d.ts +13 -0
- package/dist/showcase/TextWave.svelte +55 -0
- package/dist/showcase/TextWave.svelte.d.ts +8 -0
- package/dist/showcase/TypewriterText.svelte +130 -0
- package/dist/showcase/TypewriterText.svelte.d.ts +9 -0
- package/dist/showcase/backdrop/GrainGradient.svelte +126 -0
- package/dist/showcase/backdrop/GrainGradient.svelte.d.ts +23 -0
- package/dist/showcase/backdrop/MeshGradient.svelte +104 -0
- package/dist/showcase/backdrop/MeshGradient.svelte.d.ts +20 -0
- package/dist/showcase/backdrop/Metaballs.svelte +116 -0
- package/dist/showcase/backdrop/Metaballs.svelte.d.ts +18 -0
- package/dist/showcase/backdrop/NeuroNoise.svelte +115 -0
- package/dist/showcase/backdrop/NeuroNoise.svelte.d.ts +20 -0
- package/dist/showcase/backdrop/ShowcaseBackdrop.svelte +48 -0
- package/dist/showcase/backdrop/ShowcaseBackdrop.svelte.d.ts +12 -0
- package/dist/showcase/generative/GenerativeBackdrop.svelte +234 -0
- package/dist/showcase/generative/GenerativeBackdrop.svelte.d.ts +9 -0
- package/dist/showcase/generative/intent.d.ts +7 -0
- package/dist/showcase/generative/intent.js +67 -0
- package/dist/showcase/generative/manifest.d.ts +9 -0
- package/dist/showcase/generative/manifest.js +97 -0
- package/dist/showcase/generative/types.d.ts +48 -0
- package/dist/showcase/generative/types.js +8 -0
- package/dist/showcase/index.d.ts +36 -0
- package/dist/showcase/index.js +46 -0
- package/dist/showcase/scroll/SmoothScroll.svelte +49 -0
- package/dist/showcase/scroll/SmoothScroll.svelte.d.ts +12 -0
- package/dist/showcase/scroll/scrollProgress.d.ts +24 -0
- package/dist/showcase/scroll/scrollProgress.js +65 -0
- package/dist/showcase/scroll/scrollReveal.d.ts +30 -0
- package/dist/showcase/scroll/scrollReveal.js +70 -0
- package/dist/stores/commandPalette.svelte.d.ts +24 -0
- package/dist/stores/commandPalette.svelte.js +82 -0
- package/dist/stores/toast.svelte.d.ts +28 -0
- package/dist/stores/toast.svelte.js +33 -0
- package/dist/styles/motion.css +46 -0
- package/dist/styles/tokens.css +31 -0
- package/dist/transitions/glide.d.ts +31 -0
- package/dist/transitions/glide.js +58 -0
- package/dist/utils/sound.d.ts +6 -0
- package/dist/utils/sound.js +113 -0
- package/dist/utils/splitText.d.ts +25 -0
- package/dist/utils/splitText.js +94 -0
- package/dist/utils/themeWipe.d.ts +21 -0
- package/dist/utils/themeWipe.js +94 -0
- package/dist/utils/viewTransition.d.ts +23 -0
- package/dist/utils/viewTransition.js +75 -0
- package/package.json +50 -3
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { loadManifest, assetPath } from './manifest.js';
|
|
4
|
+
import { recordIntent } from './intent.js';
|
|
5
|
+
import type { AssetManifest } from './types.js';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
assetId: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
overlay?: 'none' | 'scrim' | 'gradient';
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { assetId, baseUrl = '', overlay = 'none', class: className = '' }: Props = $props();
|
|
15
|
+
|
|
16
|
+
type Phase = 'loading' | 'procedural' | 'poster' | 'video';
|
|
17
|
+
|
|
18
|
+
let container: HTMLDivElement | undefined = $state();
|
|
19
|
+
let phase = $state<Phase>('loading');
|
|
20
|
+
let manifest = $state<AssetManifest | null>(null);
|
|
21
|
+
let videoEl: HTMLVideoElement | undefined = $state();
|
|
22
|
+
let videoLoaded = $state(false);
|
|
23
|
+
let prefersReducedMotion = $state(false);
|
|
24
|
+
|
|
25
|
+
// Derived palette for procedural gradient
|
|
26
|
+
const palette = $derived(
|
|
27
|
+
manifest?.palette.length
|
|
28
|
+
? manifest.palette
|
|
29
|
+
: ['oklch(50% 0.2 240)', 'oklch(40% 0.15 270)', 'oklch(60% 0.25 210)']
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const gradientStyle = $derived(
|
|
33
|
+
`background: linear-gradient(135deg, ${palette.map((c, i) => `${c} ${Math.round((i / Math.max(palette.length - 1, 1)) * 100)}%`).join(', ')});`
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const activeHash = $derived(manifest?.active ?? '');
|
|
37
|
+
const basePath = $derived(manifest ? assetPath(assetId, activeHash, baseUrl) : '');
|
|
38
|
+
|
|
39
|
+
onMount(() => {
|
|
40
|
+
prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
41
|
+
const mql = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
42
|
+
const onMqlChange = (e: MediaQueryListEvent) => {
|
|
43
|
+
prefersReducedMotion = e.matches;
|
|
44
|
+
};
|
|
45
|
+
mql.addEventListener('change', onMqlChange);
|
|
46
|
+
|
|
47
|
+
loadManifest(assetId, baseUrl).then((m) => {
|
|
48
|
+
manifest = m;
|
|
49
|
+
if (!m) {
|
|
50
|
+
// No manifest — record intent in DEV and go procedural
|
|
51
|
+
if (container) recordIntent(assetId, container);
|
|
52
|
+
phase = 'procedural';
|
|
53
|
+
} else {
|
|
54
|
+
phase = 'poster';
|
|
55
|
+
if (!prefersReducedMotion) {
|
|
56
|
+
scheduleVideoLoad();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return () => mql.removeEventListener('change', onMqlChange);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
function scheduleVideoLoad() {
|
|
65
|
+
if (!container) return;
|
|
66
|
+
const obs = new IntersectionObserver(
|
|
67
|
+
(entries) => {
|
|
68
|
+
if (entries[0].isIntersecting) {
|
|
69
|
+
obs.disconnect();
|
|
70
|
+
phase = 'video';
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{ threshold: 0.1 }
|
|
74
|
+
);
|
|
75
|
+
obs.observe(container);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Pause video when scrolled offscreen
|
|
79
|
+
$effect(() => {
|
|
80
|
+
if (!videoEl || phase !== 'video') return;
|
|
81
|
+
const obs = new IntersectionObserver(
|
|
82
|
+
(entries) => {
|
|
83
|
+
if (!videoEl) return;
|
|
84
|
+
if (entries[0].isIntersecting) {
|
|
85
|
+
videoEl.play().catch(() => {});
|
|
86
|
+
} else {
|
|
87
|
+
videoEl.pause();
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{ threshold: 0.1 }
|
|
91
|
+
);
|
|
92
|
+
obs.observe(videoEl);
|
|
93
|
+
return () => obs.disconnect();
|
|
94
|
+
});
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<!--
|
|
98
|
+
GenerativeBackdrop — manifest-driven video/poster/procedural fallback chain.
|
|
99
|
+
Fallback order: CSS gradient (0ms) → poster img → lazy video (IntersectionObserver).
|
|
100
|
+
prefers-reduced-motion: stops at poster. Missing/failed manifest: procedural drift.
|
|
101
|
+
-->
|
|
102
|
+
<div
|
|
103
|
+
bind:this={container}
|
|
104
|
+
class="generative-backdrop {className}"
|
|
105
|
+
aria-hidden="true"
|
|
106
|
+
>
|
|
107
|
+
<!-- Tier 1: CSS gradient (always visible as base, also the procedural fallback) -->
|
|
108
|
+
<div
|
|
109
|
+
class="gen-layer gen-gradient"
|
|
110
|
+
class:gen-animate={phase === 'procedural' && !prefersReducedMotion}
|
|
111
|
+
style={gradientStyle}
|
|
112
|
+
></div>
|
|
113
|
+
|
|
114
|
+
<!-- Tier 2: Poster image (avif with jpg fallback) -->
|
|
115
|
+
{#if phase === 'poster' || phase === 'video'}
|
|
116
|
+
<picture class="gen-layer">
|
|
117
|
+
<source srcset="{basePath}/poster.avif" type="image/avif" />
|
|
118
|
+
<img
|
|
119
|
+
src="{basePath}/poster.jpg"
|
|
120
|
+
alt=""
|
|
121
|
+
class="gen-img"
|
|
122
|
+
loading="eager"
|
|
123
|
+
decoding="async"
|
|
124
|
+
/>
|
|
125
|
+
</picture>
|
|
126
|
+
{/if}
|
|
127
|
+
|
|
128
|
+
<!-- Tier 3: Lazy video (only when intersecting + no reduced-motion) -->
|
|
129
|
+
{#if phase === 'video' && !prefersReducedMotion}
|
|
130
|
+
<video
|
|
131
|
+
bind:this={videoEl}
|
|
132
|
+
class="gen-layer gen-video"
|
|
133
|
+
class:gen-video-ready={videoLoaded}
|
|
134
|
+
muted
|
|
135
|
+
autoplay
|
|
136
|
+
loop
|
|
137
|
+
playsinline
|
|
138
|
+
poster="{basePath}/poster.jpg"
|
|
139
|
+
oncanplaythrough={() => (videoLoaded = true)}
|
|
140
|
+
>
|
|
141
|
+
<source src="{basePath}/clip.webm" type="video/webm" />
|
|
142
|
+
<source src="{basePath}/clip.mp4" type="video/mp4" />
|
|
143
|
+
</video>
|
|
144
|
+
{/if}
|
|
145
|
+
|
|
146
|
+
<!-- Overlay -->
|
|
147
|
+
{#if overlay !== 'none'}
|
|
148
|
+
<div
|
|
149
|
+
class="gen-layer gen-overlay"
|
|
150
|
+
class:gen-overlay-scrim={overlay === 'scrim'}
|
|
151
|
+
class:gen-overlay-gradient={overlay === 'gradient'}
|
|
152
|
+
></div>
|
|
153
|
+
{/if}
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<style>
|
|
157
|
+
.generative-backdrop {
|
|
158
|
+
position: relative;
|
|
159
|
+
overflow: hidden;
|
|
160
|
+
isolation: isolate;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.gen-layer {
|
|
164
|
+
position: absolute;
|
|
165
|
+
inset: 0;
|
|
166
|
+
width: 100%;
|
|
167
|
+
height: 100%;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Tier 1: gradient base */
|
|
171
|
+
.gen-gradient {
|
|
172
|
+
z-index: 0;
|
|
173
|
+
background-size: 200% 200%;
|
|
174
|
+
transition: background var(--motion-move, 300ms) var(--motion-glide, ease-out);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Procedural drift animation — ambient, showcase-only */
|
|
178
|
+
@keyframes gen-drift {
|
|
179
|
+
0% { background-position: 0% 50%; }
|
|
180
|
+
50% { background-position: 100% 50%; }
|
|
181
|
+
100% { background-position: 0% 50%; }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.gen-animate {
|
|
185
|
+
animation: gen-drift 12s var(--motion-glide, ease-in-out) infinite;
|
|
186
|
+
background-size: 300% 300%;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@media (prefers-reduced-motion: reduce) {
|
|
190
|
+
.gen-animate {
|
|
191
|
+
animation: none;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* Tier 2: poster img */
|
|
196
|
+
.gen-img {
|
|
197
|
+
position: absolute;
|
|
198
|
+
inset: 0;
|
|
199
|
+
width: 100%;
|
|
200
|
+
height: 100%;
|
|
201
|
+
object-fit: cover;
|
|
202
|
+
z-index: 1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Tier 3: video */
|
|
206
|
+
.gen-video {
|
|
207
|
+
z-index: 2;
|
|
208
|
+
object-fit: cover;
|
|
209
|
+
opacity: 0;
|
|
210
|
+
transition: opacity var(--motion-enter, 200ms) var(--motion-glide, ease-out);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.gen-video-ready {
|
|
214
|
+
opacity: 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Overlay */
|
|
218
|
+
.gen-overlay {
|
|
219
|
+
z-index: 3;
|
|
220
|
+
pointer-events: none;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.gen-overlay-scrim {
|
|
224
|
+
background: oklch(0% 0 0 / 40%);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.gen-overlay-gradient {
|
|
228
|
+
background: linear-gradient(
|
|
229
|
+
to bottom,
|
|
230
|
+
oklch(0% 0 0 / 0%) 0%,
|
|
231
|
+
oklch(0% 0 0 / 60%) 100%
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
assetId: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
overlay?: 'none' | 'scrim' | 'gradient';
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const GenerativeBackdrop: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type GenerativeBackdrop = ReturnType<typeof GenerativeBackdrop>;
|
|
9
|
+
export default GenerativeBackdrop;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function quantizeRatio(w: number, h: number): string;
|
|
2
|
+
/**
|
|
3
|
+
* In DEV mode: record that this assetId has no manifest yet.
|
|
4
|
+
* Writes to localStorage so the design-time CLI can harvest intents.
|
|
5
|
+
* No-ops in production or when localStorage is unavailable (SSR).
|
|
6
|
+
*/
|
|
7
|
+
export declare function recordIntent(assetId: string, el: HTMLElement): void;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
var INTENTS_KEY = 'jatui-gen-intents';
|
|
2
|
+
/**
|
|
3
|
+
* Standard ratio buckets, ordered widest to tallest.
|
|
4
|
+
* quantizeRatio maps a measured w×h to the nearest bucket.
|
|
5
|
+
*/
|
|
6
|
+
var RATIO_BUCKETS = [
|
|
7
|
+
{ label: '21:9', value: 21 / 9 },
|
|
8
|
+
{ label: '16:9', value: 16 / 9 },
|
|
9
|
+
{ label: '3:2', value: 3 / 2 },
|
|
10
|
+
{ label: '4:3', value: 4 / 3 },
|
|
11
|
+
{ label: '1:1', value: 1 },
|
|
12
|
+
{ label: '3:4', value: 3 / 4 },
|
|
13
|
+
{ label: '9:16', value: 9 / 16 }
|
|
14
|
+
];
|
|
15
|
+
export function quantizeRatio(w, h) {
|
|
16
|
+
if (h === 0)
|
|
17
|
+
return '16:9';
|
|
18
|
+
var ratio = w / h;
|
|
19
|
+
var nearest = RATIO_BUCKETS[0];
|
|
20
|
+
var minDiff = Math.abs(ratio - nearest.value);
|
|
21
|
+
for (var _i = 0, RATIO_BUCKETS_1 = RATIO_BUCKETS; _i < RATIO_BUCKETS_1.length; _i++) {
|
|
22
|
+
var bucket = RATIO_BUCKETS_1[_i];
|
|
23
|
+
var diff = Math.abs(ratio - bucket.value);
|
|
24
|
+
if (diff < minDiff) {
|
|
25
|
+
minDiff = diff;
|
|
26
|
+
nearest = bucket;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return nearest.label;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* In DEV mode: record that this assetId has no manifest yet.
|
|
33
|
+
* Writes to localStorage so the design-time CLI can harvest intents.
|
|
34
|
+
* No-ops in production or when localStorage is unavailable (SSR).
|
|
35
|
+
*/
|
|
36
|
+
export function recordIntent(assetId, el) {
|
|
37
|
+
var _a;
|
|
38
|
+
if (typeof import.meta === 'undefined')
|
|
39
|
+
return;
|
|
40
|
+
if (!((_a = import.meta.env) === null || _a === void 0 ? void 0 : _a.DEV))
|
|
41
|
+
return;
|
|
42
|
+
if (typeof localStorage === 'undefined')
|
|
43
|
+
return;
|
|
44
|
+
var rect = el.getBoundingClientRect();
|
|
45
|
+
var w = Math.round(rect.width) || el.offsetWidth;
|
|
46
|
+
var h = Math.round(rect.height) || el.offsetHeight;
|
|
47
|
+
var ratioBucket = quantizeRatio(w, h);
|
|
48
|
+
var intent = new Date().toISOString();
|
|
49
|
+
var existing = readIntents();
|
|
50
|
+
existing[assetId] = { assetId: assetId, measuredW: w, measuredH: h, ratioBucket: ratioBucket, intent: intent };
|
|
51
|
+
try {
|
|
52
|
+
localStorage.setItem(INTENTS_KEY, JSON.stringify(existing));
|
|
53
|
+
}
|
|
54
|
+
catch (_b) {
|
|
55
|
+
// localStorage full — silently skip
|
|
56
|
+
}
|
|
57
|
+
console.info("[jatui-gen] no manifest for \"".concat(assetId, "\" \u2014 intent recorded (").concat(w, "\u00D7").concat(h, ", ").concat(ratioBucket, "). Run: jatui-gen fulfill"));
|
|
58
|
+
}
|
|
59
|
+
function readIntents() {
|
|
60
|
+
try {
|
|
61
|
+
var raw = localStorage.getItem(INTENTS_KEY);
|
|
62
|
+
return raw ? JSON.parse(raw) : {};
|
|
63
|
+
}
|
|
64
|
+
catch (_a) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AssetManifest } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fetch and validate the asset manifest for a given assetId.
|
|
4
|
+
* Returns null if the manifest is missing or malformed.
|
|
5
|
+
* Results are memoised for the lifetime of the page.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadManifest(assetId: string, baseUrl?: string): Promise<AssetManifest | null>;
|
|
8
|
+
/** Build the asset base path for a given assetId + hash. */
|
|
9
|
+
export declare function assetPath(assetId: string, hash: string, baseUrl?: string): string;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var CACHE = new Map();
|
|
38
|
+
/**
|
|
39
|
+
* Fetch and validate the asset manifest for a given assetId.
|
|
40
|
+
* Returns null if the manifest is missing or malformed.
|
|
41
|
+
* Results are memoised for the lifetime of the page.
|
|
42
|
+
*/
|
|
43
|
+
export function loadManifest(assetId_1) {
|
|
44
|
+
return __awaiter(this, arguments, Promise, function (assetId, baseUrl) {
|
|
45
|
+
var cacheKey, url, res, data, _a;
|
|
46
|
+
var _b;
|
|
47
|
+
if (baseUrl === void 0) { baseUrl = ''; }
|
|
48
|
+
return __generator(this, function (_c) {
|
|
49
|
+
switch (_c.label) {
|
|
50
|
+
case 0:
|
|
51
|
+
cacheKey = "".concat(baseUrl, "/").concat(assetId);
|
|
52
|
+
if (CACHE.has(cacheKey))
|
|
53
|
+
return [2 /*return*/, (_b = CACHE.get(cacheKey)) !== null && _b !== void 0 ? _b : null];
|
|
54
|
+
_c.label = 1;
|
|
55
|
+
case 1:
|
|
56
|
+
_c.trys.push([1, 4, , 5]);
|
|
57
|
+
url = "".concat(baseUrl, "/gen/").concat(assetId, "/manifest.json");
|
|
58
|
+
return [4 /*yield*/, fetch(url)];
|
|
59
|
+
case 2:
|
|
60
|
+
res = _c.sent();
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
CACHE.set(cacheKey, null);
|
|
63
|
+
return [2 /*return*/, null];
|
|
64
|
+
}
|
|
65
|
+
return [4 /*yield*/, res.json()];
|
|
66
|
+
case 3:
|
|
67
|
+
data = _c.sent();
|
|
68
|
+
if (!isValidManifest(data)) {
|
|
69
|
+
CACHE.set(cacheKey, null);
|
|
70
|
+
return [2 /*return*/, null];
|
|
71
|
+
}
|
|
72
|
+
CACHE.set(cacheKey, data);
|
|
73
|
+
return [2 /*return*/, data];
|
|
74
|
+
case 4:
|
|
75
|
+
_a = _c.sent();
|
|
76
|
+
CACHE.set(cacheKey, null);
|
|
77
|
+
return [2 /*return*/, null];
|
|
78
|
+
case 5: return [2 /*return*/];
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function isValidManifest(data) {
|
|
84
|
+
if (!data || typeof data !== 'object')
|
|
85
|
+
return false;
|
|
86
|
+
var m = data;
|
|
87
|
+
return (typeof m.assetId === 'string' &&
|
|
88
|
+
typeof m.active === 'string' &&
|
|
89
|
+
Array.isArray(m.variants) &&
|
|
90
|
+
Array.isArray(m.palette) &&
|
|
91
|
+
m.palette.length > 0);
|
|
92
|
+
}
|
|
93
|
+
/** Build the asset base path for a given assetId + hash. */
|
|
94
|
+
export function assetPath(assetId, hash, baseUrl) {
|
|
95
|
+
if (baseUrl === void 0) { baseUrl = ''; }
|
|
96
|
+
return "".concat(baseUrl, "/gen/").concat(assetId, "/").concat(hash);
|
|
97
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generative asset pipeline — manifest contract types.
|
|
3
|
+
*
|
|
4
|
+
* The manifest describes a versioned, hash-addressed cache of AI-generated
|
|
5
|
+
* video/poster assets for a given assetId. The runtime component reads this;
|
|
6
|
+
* a design-time CLI (sibling task) writes it. Zero API calls at runtime.
|
|
7
|
+
*/
|
|
8
|
+
export interface AssetVariant {
|
|
9
|
+
/** Nearest standard ratio bucket: 21:9|16:9|3:2|4:3|1:1|3:4|9:16 */
|
|
10
|
+
ratio: string;
|
|
11
|
+
/** Resolution label e.g. "1080p", "720p" */
|
|
12
|
+
res: string;
|
|
13
|
+
/** SHA-256 content hash (first 12 chars) — also the sub-directory name */
|
|
14
|
+
hash: string;
|
|
15
|
+
}
|
|
16
|
+
export interface AssetProvenance {
|
|
17
|
+
/** Model that generated the asset, e.g. "seedance-2-0" */
|
|
18
|
+
model: string;
|
|
19
|
+
/** Prompt used for generation */
|
|
20
|
+
prompt: string;
|
|
21
|
+
/** Random seed for reproducibility */
|
|
22
|
+
seed?: number;
|
|
23
|
+
/** ISO 8601 timestamp */
|
|
24
|
+
generatedAt: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Manifest stored at /gen/<assetId>/manifest.json.
|
|
28
|
+
* Asset files live at /gen/<assetId>/<hash>/{clip.mp4,clip.webm,poster.avif,poster.jpg}.
|
|
29
|
+
*/
|
|
30
|
+
export interface AssetManifest {
|
|
31
|
+
assetId: string;
|
|
32
|
+
/** Hash of the currently active variant (points into variants[]) */
|
|
33
|
+
active: string;
|
|
34
|
+
variants: AssetVariant[];
|
|
35
|
+
/** Theme-extracted palette for the procedural CSS gradient fallback */
|
|
36
|
+
palette: string[];
|
|
37
|
+
provenance: AssetProvenance;
|
|
38
|
+
}
|
|
39
|
+
/** Intent written to localStorage by dev-mode components with no manifest */
|
|
40
|
+
export interface AssetIntent {
|
|
41
|
+
assetId: string;
|
|
42
|
+
measuredW: number;
|
|
43
|
+
measuredH: number;
|
|
44
|
+
/** Quantized ratio bucket */
|
|
45
|
+
ratioBucket: string;
|
|
46
|
+
/** ISO timestamp when the intent was recorded */
|
|
47
|
+
intent: string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generative asset pipeline — manifest contract types.
|
|
3
|
+
*
|
|
4
|
+
* The manifest describes a versioned, hash-addressed cache of AI-generated
|
|
5
|
+
* video/poster assets for a given assetId. The runtime component reads this;
|
|
6
|
+
* a design-time CLI (sibling task) writes it. Zero API calls at runtime.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export { default as BorderBeam } from './BorderBeam.svelte';
|
|
2
|
+
export { default as AuroraDrift } from './AuroraDrift.svelte';
|
|
3
|
+
export { default as ShineSweep } from './ShineSweep.svelte';
|
|
4
|
+
export { default as CursorSpotlight } from './CursorSpotlight.svelte';
|
|
5
|
+
export { default as ScrambleText } from './ScrambleText.svelte';
|
|
6
|
+
export { default as TypewriterText } from './TypewriterText.svelte';
|
|
7
|
+
export { default as TextSplitReveal } from './TextSplitReveal.svelte';
|
|
8
|
+
export { default as TextWave } from './TextWave.svelte';
|
|
9
|
+
export { default as Marquee } from './Marquee.svelte';
|
|
10
|
+
export { default as FocusReveal } from './FocusReveal.svelte';
|
|
11
|
+
export { default as ParallaxTilt } from './ParallaxTilt.svelte';
|
|
12
|
+
export { default as FlipCard } from './FlipCard.svelte';
|
|
13
|
+
export { default as Confetti } from './Confetti.svelte';
|
|
14
|
+
export { default as ClipWipe } from './ClipWipe.svelte';
|
|
15
|
+
export { default as KenBurns } from './KenBurns.svelte';
|
|
16
|
+
export { default as DeviceMock } from './DeviceMock.svelte';
|
|
17
|
+
export { default as AnimatedBeam } from './AnimatedBeam.svelte';
|
|
18
|
+
export { default as Dock } from './Dock.svelte';
|
|
19
|
+
export { default as Terminal } from './Terminal.svelte';
|
|
20
|
+
export { default as BentoGrid } from './BentoGrid.svelte';
|
|
21
|
+
export { default as BentoCard } from './BentoCard.svelte';
|
|
22
|
+
export { default as ShowcaseBackdrop } from './backdrop/ShowcaseBackdrop.svelte';
|
|
23
|
+
export { default as MeshGradient } from './backdrop/MeshGradient.svelte';
|
|
24
|
+
export { default as GrainGradient } from './backdrop/GrainGradient.svelte';
|
|
25
|
+
export { default as Metaballs } from './backdrop/Metaballs.svelte';
|
|
26
|
+
export { default as NeuroNoise } from './backdrop/NeuroNoise.svelte';
|
|
27
|
+
export { default as Globe } from './Globe.svelte';
|
|
28
|
+
export { scrollReveal } from './scroll/scrollReveal';
|
|
29
|
+
export type { ScrollRevealOptions } from './scroll/scrollReveal';
|
|
30
|
+
export { scrollProgress } from './scroll/scrollProgress';
|
|
31
|
+
export type { ScrollProgressOptions } from './scroll/scrollProgress';
|
|
32
|
+
export { default as SmoothScroll } from './scroll/SmoothScroll.svelte';
|
|
33
|
+
export { default as GenerativeBackdrop } from './generative/GenerativeBackdrop.svelte';
|
|
34
|
+
export { loadManifest, assetPath } from './generative/manifest';
|
|
35
|
+
export { quantizeRatio, recordIntent } from './generative/intent';
|
|
36
|
+
export type { AssetManifest, AssetVariant, AssetProvenance, AssetIntent } from './generative/types';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Showcase module — marketing-surface kinetics effects.
|
|
2
|
+
// SANCTIONED ONLY on marketing/landing pages (outside product routes).
|
|
3
|
+
// See shared/craft/animation-discipline.md "Surfaces" for policy.
|
|
4
|
+
// Consumer repos enforce the boundary with scripts/check-showcase-imports.mjs.
|
|
5
|
+
//
|
|
6
|
+
// Import via the subpath: import { BorderBeam } from '@joewinke/jatui/showcase'
|
|
7
|
+
// Ambient effects (kinetics wave)
|
|
8
|
+
export { default as BorderBeam } from './BorderBeam.svelte';
|
|
9
|
+
export { default as AuroraDrift } from './AuroraDrift.svelte';
|
|
10
|
+
export { default as ShineSweep } from './ShineSweep.svelte';
|
|
11
|
+
export { default as CursorSpotlight } from './CursorSpotlight.svelte';
|
|
12
|
+
// Text effects
|
|
13
|
+
export { default as ScrambleText } from './ScrambleText.svelte';
|
|
14
|
+
export { default as TypewriterText } from './TypewriterText.svelte';
|
|
15
|
+
export { default as TextSplitReveal } from './TextSplitReveal.svelte';
|
|
16
|
+
export { default as TextWave } from './TextWave.svelte';
|
|
17
|
+
export { default as Marquee } from './Marquee.svelte';
|
|
18
|
+
export { default as FocusReveal } from './FocusReveal.svelte';
|
|
19
|
+
// Flair
|
|
20
|
+
export { default as ParallaxTilt } from './ParallaxTilt.svelte';
|
|
21
|
+
export { default as FlipCard } from './FlipCard.svelte';
|
|
22
|
+
export { default as Confetti } from './Confetti.svelte';
|
|
23
|
+
export { default as ClipWipe } from './ClipWipe.svelte';
|
|
24
|
+
export { default as KenBurns } from './KenBurns.svelte';
|
|
25
|
+
// Magic UI ports
|
|
26
|
+
export { default as DeviceMock } from './DeviceMock.svelte';
|
|
27
|
+
export { default as AnimatedBeam } from './AnimatedBeam.svelte';
|
|
28
|
+
export { default as Dock } from './Dock.svelte';
|
|
29
|
+
export { default as Terminal } from './Terminal.svelte';
|
|
30
|
+
export { default as BentoGrid } from './BentoGrid.svelte';
|
|
31
|
+
export { default as BentoCard } from './BentoCard.svelte';
|
|
32
|
+
// WebGL backdrops (@paper-design/shaders + cobe)
|
|
33
|
+
export { default as ShowcaseBackdrop } from './backdrop/ShowcaseBackdrop.svelte';
|
|
34
|
+
export { default as MeshGradient } from './backdrop/MeshGradient.svelte';
|
|
35
|
+
export { default as GrainGradient } from './backdrop/GrainGradient.svelte';
|
|
36
|
+
export { default as Metaballs } from './backdrop/Metaballs.svelte';
|
|
37
|
+
export { default as NeuroNoise } from './backdrop/NeuroNoise.svelte';
|
|
38
|
+
export { default as Globe } from './Globe.svelte';
|
|
39
|
+
// Scroll kit (marketing surfaces only)
|
|
40
|
+
export { scrollReveal } from './scroll/scrollReveal';
|
|
41
|
+
export { scrollProgress } from './scroll/scrollProgress';
|
|
42
|
+
export { default as SmoothScroll } from './scroll/SmoothScroll.svelte';
|
|
43
|
+
// Generative asset pipeline (runtime half; see scripts/jatui-gen for the CLI)
|
|
44
|
+
export { default as GenerativeBackdrop } from './generative/GenerativeBackdrop.svelte';
|
|
45
|
+
export { loadManifest, assetPath } from './generative/manifest';
|
|
46
|
+
export { quantizeRatio, recordIntent } from './generative/intent';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Lenis from 'lenis';
|
|
3
|
+
import { onMount } from 'svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
children: import('svelte').Snippet;
|
|
7
|
+
/** Lenis lerp intensity — lower = smoother (default 0.1) */
|
|
8
|
+
lerp?: number;
|
|
9
|
+
/** Lenis scroll duration in seconds (overrides lerp when set) */
|
|
10
|
+
duration?: number;
|
|
11
|
+
/** Lenis smooth-wheel toggle (default true) */
|
|
12
|
+
smoothWheel?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { children, lerp = 0.1, duration, smoothWheel = true }: Props = $props();
|
|
16
|
+
|
|
17
|
+
const isTouch =
|
|
18
|
+
typeof navigator !== 'undefined' && navigator.maxTouchPoints > 0;
|
|
19
|
+
const reducedMotion =
|
|
20
|
+
typeof window !== 'undefined' &&
|
|
21
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
22
|
+
|
|
23
|
+
// Never run on touch devices or reduced-motion — scroll-hijack is hostile there.
|
|
24
|
+
const enabled = !isTouch && !reducedMotion;
|
|
25
|
+
|
|
26
|
+
onMount(() => {
|
|
27
|
+
if (!enabled) return;
|
|
28
|
+
|
|
29
|
+
const opts: ConstructorParameters<typeof Lenis>[0] = { smoothWheel };
|
|
30
|
+
if (duration != null) opts.duration = duration;
|
|
31
|
+
else opts.lerp = lerp;
|
|
32
|
+
|
|
33
|
+
const lenis = new Lenis(opts);
|
|
34
|
+
|
|
35
|
+
let rafId: number;
|
|
36
|
+
function raf(time: number) {
|
|
37
|
+
lenis.raf(time);
|
|
38
|
+
rafId = requestAnimationFrame(raf);
|
|
39
|
+
}
|
|
40
|
+
rafId = requestAnimationFrame(raf);
|
|
41
|
+
|
|
42
|
+
return () => {
|
|
43
|
+
cancelAnimationFrame(rafId);
|
|
44
|
+
lenis.destroy();
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
{@render children()}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
children: import('svelte').Snippet;
|
|
3
|
+
/** Lenis lerp intensity — lower = smoother (default 0.1) */
|
|
4
|
+
lerp?: number;
|
|
5
|
+
/** Lenis scroll duration in seconds (overrides lerp when set) */
|
|
6
|
+
duration?: number;
|
|
7
|
+
/** Lenis smooth-wheel toggle (default true) */
|
|
8
|
+
smoothWheel?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const SmoothScroll: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type SmoothScroll = ReturnType<typeof SmoothScroll>;
|
|
12
|
+
export default SmoothScroll;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ScrollProgressOptions {
|
|
2
|
+
/** CSS variable name to bind (default '--scroll-progress') */
|
|
3
|
+
varName?: string;
|
|
4
|
+
/** Container to observe — default window scroll */
|
|
5
|
+
container?: HTMLElement;
|
|
6
|
+
/** Scroll axis (default 'y') */
|
|
7
|
+
axis?: 'x' | 'y';
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Svelte action: binds a CSS custom property (default --scroll-progress, 0..1)
|
|
11
|
+
* to the page scroll position via motion scroll(). Uses native ScrollTimeline
|
|
12
|
+
* where available for compositor-thread performance.
|
|
13
|
+
*
|
|
14
|
+
* Reduced-motion: no-ops (leaves var unset / at whatever CSS default).
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* <div use:scrollProgress style="width: calc(var(--scroll-progress) * 100%)">
|
|
18
|
+
* <div use:scrollProgress={{ varName: '--depth', container: panelEl }}>
|
|
19
|
+
*/
|
|
20
|
+
export declare function scrollProgress(node: HTMLElement, opts?: ScrollProgressOptions): {
|
|
21
|
+
destroy?: undefined;
|
|
22
|
+
} | {
|
|
23
|
+
destroy(): void;
|
|
24
|
+
};
|