kmcom-nuxt-layers 1.3.1 → 1.5.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/layers/content/app/components/Blog/List.vue +5 -1
- package/layers/content/app/components/Gallery/AmbientImage.vue +5 -12
- package/layers/content/app/components/Gallery/Detail.vue +8 -6
- package/layers/content/app/components/Gallery/Grid.vue +11 -3
- package/layers/content/app/components/Portfolio/ColorPalette.vue +1 -4
- package/layers/content/app/components/Portfolio/Detail.vue +6 -1
- package/layers/content/app/components/Portfolio/List.vue +5 -1
- package/layers/content/app/components/content/Figure.vue +1 -7
- package/layers/content/nuxt.config.ts +16 -5
- package/layers/content/package.json +5 -5
- package/layers/core/app/assets/css/main.css +5 -0
- package/layers/core/app/composables/useCache.ts +8 -4
- package/layers/core/app/composables/useErrorLog.ts +9 -5
- package/layers/core/app/composables/useScrollGuard.ts +4 -2
- package/layers/core/app/plugins/feature-detection.client.ts +1 -1
- package/layers/core/app/plugins/init.ts +2 -1
- package/layers/core/app/plugins/scroll-guard.client.ts +4 -1
- package/layers/core/app.config.ts +0 -9
- package/layers/forms/app/components/Form/Contact.vue +16 -7
- package/layers/forms/nuxt.config.ts +18 -0
- package/layers/forms/package.json +2 -0
- package/layers/layout/app/components/Layout/Container.vue +1 -4
- package/layers/layout/app/components/Layout/Grid/Debug.vue +0 -1
- package/layers/layout/app/components/Layout/Grid/Item.vue +12 -6
- package/layers/layout/app/components/Layout/Main.vue +1 -4
- package/layers/layout/app/components/Layout/Page/Container.vue +3 -1
- package/layers/layout/app/components/Layout/Page/Header.vue +16 -7
- package/layers/layout/app/components/Layout/Section/Grid.vue +1 -4
- package/layers/layout/app/components/Layout/Section/Sidebar.vue +6 -1
- package/layers/layout/app/components/Layout/Section/Stack.vue +1 -1
- package/layers/layout/app/composables/useGridConfig.ts +6 -1
- package/layers/motion/app/components/Motion/HorizontalScroll.vue +61 -0
- package/layers/motion/app/components/Motion/PinnedSection.vue +77 -0
- package/layers/motion/app/components/Motion/ScrollProgress.vue +8 -56
- package/layers/motion/app/components/Motion/ScrollScene.vue +121 -0
- package/layers/motion/app/components/Motion/ScrollStep.vue +45 -0
- package/layers/motion/app/components/Motion/TextReveal.vue +28 -63
- package/layers/motion/app/composables/useScrollSteps.ts +41 -0
- package/layers/motion/app/composables/useSectionProgress.ts +58 -0
- package/layers/motion/app/composables/useSmoothScroll.ts +3 -2
- package/layers/motion/app/plugins/locomotive-scroll.client.ts +6 -6
- package/layers/motion/nuxt.config.ts +6 -0
- package/layers/motion/package.json +2 -1
- package/layers/routing/app/app.config.ts +20 -0
- package/layers/routing/app/composables/useFeatures.ts +12 -0
- package/layers/routing/app/composables/useMaintenance.ts +7 -0
- package/layers/routing/app/composables/useRoutingConfig.ts +20 -0
- package/layers/routing/app/middleware/01.maintenance.global.ts +6 -0
- package/layers/routing/app/middleware/02.governance.global.ts +25 -0
- package/layers/routing/app/plugins/feature-flags.client.ts +15 -0
- package/layers/routing/app/plugins/scroll-routing.client.ts +21 -0
- package/layers/routing/app/types/route-meta.d.ts +6 -0
- package/layers/routing/app/types/routing.ts +48 -0
- package/layers/routing/nuxt.config.ts +27 -0
- package/layers/routing/package.json +6 -0
- package/layers/shader/app/components/Preset/ThemeAurora.client.vue +86 -0
- package/layers/shader/app/components/Preset/ThemeBubble.client.vue +87 -0
- package/layers/shader/app/components/Preset/ThemeFlow.client.vue +86 -0
- package/layers/shader/app/components/Preset/ThemeGradient.client.vue +87 -0
- package/layers/shader/app/components/Preset/ThemeLavaLamp.client.vue +86 -0
- package/layers/shader/app/components/Preset/ThemePlasma.client.vue +86 -0
- package/layers/shader/app/components/Preset/ThemeWave.client.vue +86 -0
- package/layers/shader/app/components/Shader/Background.client.vue +15 -0
- package/layers/shader/app/composables/useAmbientMaterials.ts +306 -0
- package/layers/shader/app/composables/useThemeColors.ts +52 -0
- package/layers/shader/app/utils/tsl/oklch.ts +12 -6
- package/layers/theme/app/assets/css/theme.css +19 -14
- package/layers/theme/app/components/ThemePicker/AccentButton.vue +2 -2
- package/layers/theme/app/components/ThemePicker/Colors.vue +2 -4
- package/layers/theme/app/components/ThemePicker/Menu.vue +4 -13
- package/layers/theme/app/components/ThemePicker/MenuButton.vue +1 -7
- package/layers/theme/app/composables/useAccentColor.ts +38 -0
- package/layers/theme/app/composables/useTheme.ts +14 -0
- package/layers/theme/app/composables/useThemeContrast.ts +34 -0
- package/layers/theme/app/composables/useThemeMotion.ts +34 -0
- package/layers/theme/app/composables/useThemePreferences.ts +3 -156
- package/layers/theme/app/composables/useThemeTransparency.ts +41 -0
- package/layers/theme/app/plugins/theme.client.ts +3 -3
- package/layers/theme/app/types/theme.ts +4 -0
- package/layers/theme/nuxt.config.ts +7 -0
- package/layers/ui/app/app.config.ts +44 -0
- package/layers/ui/app/assets/css/main.css +14 -0
- package/layers/ui/app/components/Accent/Blob.vue +29 -0
- package/layers/ui/app/components/Accent/Scene.vue +38 -0
- package/layers/ui/app/components/Gradient/Background.vue +22 -0
- package/layers/ui/app/components/Gradient/Text.vue +22 -0
- package/layers/ui/app/components/Progress/Bar.vue +25 -0
- package/layers/ui/app/components/Progress/Circular.vue +69 -0
- package/layers/ui/app/components/Tint/Overlay.vue +25 -0
- package/layers/ui/app/components/Typography/CodeBlock.vue +2 -1
- package/layers/ui/app/components/Typography/Headline.vue +2 -1
- package/layers/ui/app/components/Typography/QuoteBlock.vue +2 -1
- package/layers/ui/app/components/Typography/TextStroke.vue +18 -16
- package/layers/ui/app/composables/accent.ts +51 -0
- package/layers/ui/app/composables/gradient.ts +79 -0
- package/layers/ui/app/composables/tint.ts +20 -0
- package/layers/ui/app/types/accent.ts +17 -0
- package/layers/ui/app/types/gradient.ts +27 -0
- package/layers/ui/app/types/tint.ts +25 -0
- package/package.json +37 -31
- package/layers/motion/app/utils/gsapAnimations.ts +0 -122
- package/layers/ui/app.config.ts +0 -12
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FeatureValue } from '../types/routing'
|
|
2
|
+
|
|
3
|
+
export function useFeatures() {
|
|
4
|
+
const { config } = useRoutingConfig()
|
|
5
|
+
const runtimeFlags = useState<Record<string, FeatureValue>>('routing:flags', () => ({}))
|
|
6
|
+
|
|
7
|
+
function resolve(name: string): FeatureValue {
|
|
8
|
+
return runtimeFlags.value[name] ?? config.features[name] ?? 'disabled'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return { resolve, runtimeFlags }
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defu } from 'defu'
|
|
2
|
+
import { ROUTING_PRESETS } from '../types/routing'
|
|
3
|
+
import type { RoutingLayerConfig, FeatureValue } from '../types/routing'
|
|
4
|
+
|
|
5
|
+
export function useRoutingConfig() {
|
|
6
|
+
const appConfig = useAppConfig()
|
|
7
|
+
const user = appConfig.routingLayer as Partial<RoutingLayerConfig>
|
|
8
|
+
const preset = ROUTING_PRESETS[user.preset ?? 'simple']
|
|
9
|
+
const config = defu(user, preset) as RoutingLayerConfig
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
config,
|
|
13
|
+
isStrictMode: () => config.strictDefaultDeny,
|
|
14
|
+
isLayerDefaultDeny: () => config.layerDefaultDeny,
|
|
15
|
+
getFeatureVariant: (name: string): FeatureValue =>
|
|
16
|
+
config.features[name] ?? 'disabled',
|
|
17
|
+
isFeatureEnabled: (name: string) =>
|
|
18
|
+
config.features[name] === 'enabled',
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export default defineNuxtRouteMiddleware((to) => {
|
|
2
|
+
const { config, isStrictMode, isLayerDefaultDeny } = useRoutingConfig()
|
|
3
|
+
const { resolve } = useFeatures()
|
|
4
|
+
const meta = to.meta
|
|
5
|
+
|
|
6
|
+
if (config.debug) console.log('[routing] governance check', to.path, meta)
|
|
7
|
+
|
|
8
|
+
// strict default-deny: every route must declare a feature
|
|
9
|
+
if (isStrictMode() && !meta.feature) {
|
|
10
|
+
throw createError({ statusCode: 404 })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// layer default-deny: layer routes must declare a feature
|
|
14
|
+
if (isLayerDefaultDeny() && meta.__fromLayer && !meta.feature) {
|
|
15
|
+
throw createError({ statusCode: 404 })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!meta.feature) return
|
|
19
|
+
|
|
20
|
+
const variant = resolve(meta.feature)
|
|
21
|
+
if (config.debug) console.log(`[routing] feature "${meta.feature}" resolved to "${variant}"`)
|
|
22
|
+
|
|
23
|
+
if (variant === 'disabled') throw createError({ statusCode: 404 })
|
|
24
|
+
if (variant === 'beta' || variant === 'coming-soon') return navigateTo('/coming-soon')
|
|
25
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FeatureValue } from '../types/routing'
|
|
2
|
+
|
|
3
|
+
export default defineNuxtPlugin(async () => {
|
|
4
|
+
const { config } = useRoutingConfig()
|
|
5
|
+
if (!config.runtimeFlags) return
|
|
6
|
+
|
|
7
|
+
const { runtimeFlags } = useFeatures()
|
|
8
|
+
try {
|
|
9
|
+
const data = await $fetch<Record<string, FeatureValue>>('/api/feature-flags')
|
|
10
|
+
runtimeFlags.value = data
|
|
11
|
+
}
|
|
12
|
+
catch (e) {
|
|
13
|
+
if (config.debug) console.warn('[routing] Failed to fetch feature flags', e)
|
|
14
|
+
}
|
|
15
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default defineNuxtPlugin(() => {
|
|
2
|
+
const { config } = useRoutingConfig()
|
|
3
|
+
if (!config.scrollRouting.enabled) return
|
|
4
|
+
|
|
5
|
+
const router = useRouter()
|
|
6
|
+
const observer = new IntersectionObserver(
|
|
7
|
+
(entries) => {
|
|
8
|
+
const visible = entries.find(e => e.isIntersecting)
|
|
9
|
+
if (!visible) return
|
|
10
|
+
const id = visible.target.getAttribute('data-section')
|
|
11
|
+
if (!id) return
|
|
12
|
+
const method = config.scrollRouting.mode === 'push' ? 'push' : 'replace'
|
|
13
|
+
router[method]({ hash: `#${id}` })
|
|
14
|
+
},
|
|
15
|
+
{ threshold: 0.5 },
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
onNuxtReady(() => {
|
|
19
|
+
document.querySelectorAll('[data-section]').forEach(el => observer.observe(el))
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type FeatureValue = 'enabled' | 'disabled' | 'beta' | 'coming-soon'
|
|
2
|
+
export type RoutingPreset = 'simple' | 'marketing' | 'product' | 'enterprise'
|
|
3
|
+
|
|
4
|
+
export interface RoutingLayerConfig {
|
|
5
|
+
preset: RoutingPreset
|
|
6
|
+
strictDefaultDeny: boolean
|
|
7
|
+
layerDefaultDeny: boolean
|
|
8
|
+
runtimeFlags: boolean
|
|
9
|
+
debug: boolean
|
|
10
|
+
maintenance: { enabled: boolean; allowRoutes: string[] }
|
|
11
|
+
scrollRouting: { enabled: boolean; mode: 'replace' | 'push' }
|
|
12
|
+
features: Record<string, FeatureValue>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const ROUTING_PRESETS: Record<RoutingPreset, Omit<RoutingLayerConfig, 'preset' | 'features'>> = {
|
|
16
|
+
simple: {
|
|
17
|
+
strictDefaultDeny: false,
|
|
18
|
+
layerDefaultDeny: false,
|
|
19
|
+
runtimeFlags: false,
|
|
20
|
+
debug: false,
|
|
21
|
+
maintenance: { enabled: false, allowRoutes: ['/maintenance'] },
|
|
22
|
+
scrollRouting: { enabled: false, mode: 'replace' },
|
|
23
|
+
},
|
|
24
|
+
marketing: {
|
|
25
|
+
strictDefaultDeny: false,
|
|
26
|
+
layerDefaultDeny: true,
|
|
27
|
+
runtimeFlags: false,
|
|
28
|
+
debug: false,
|
|
29
|
+
maintenance: { enabled: true, allowRoutes: ['/maintenance'] },
|
|
30
|
+
scrollRouting: { enabled: true, mode: 'replace' },
|
|
31
|
+
},
|
|
32
|
+
product: {
|
|
33
|
+
strictDefaultDeny: false,
|
|
34
|
+
layerDefaultDeny: true,
|
|
35
|
+
runtimeFlags: true,
|
|
36
|
+
debug: false,
|
|
37
|
+
maintenance: { enabled: true, allowRoutes: ['/maintenance'] },
|
|
38
|
+
scrollRouting: { enabled: false, mode: 'replace' },
|
|
39
|
+
},
|
|
40
|
+
enterprise: {
|
|
41
|
+
strictDefaultDeny: true,
|
|
42
|
+
layerDefaultDeny: true,
|
|
43
|
+
runtimeFlags: true,
|
|
44
|
+
debug: false,
|
|
45
|
+
maintenance: { enabled: true, allowRoutes: ['/maintenance'] },
|
|
46
|
+
scrollRouting: { enabled: false, mode: 'replace' },
|
|
47
|
+
},
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { NuxtPage } from '@nuxt/schema'
|
|
2
|
+
|
|
3
|
+
export default defineNuxtConfig({
|
|
4
|
+
$meta: { name: 'routing' },
|
|
5
|
+
|
|
6
|
+
alias: {
|
|
7
|
+
'#layers/routing': import.meta.dirname,
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
compatibilityDate: '2026-01-30',
|
|
11
|
+
|
|
12
|
+
hooks: {
|
|
13
|
+
'pages:extend'(pages) {
|
|
14
|
+
const cwd = process.cwd()
|
|
15
|
+
const tag = (list: NuxtPage[]) => {
|
|
16
|
+
for (const page of list) {
|
|
17
|
+
if (page.file && !page.file.startsWith(cwd)) {
|
|
18
|
+
page.meta ??= {}
|
|
19
|
+
page.meta.__fromLayer = true
|
|
20
|
+
}
|
|
21
|
+
if (page.children) tag(page.children)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
tag(pages)
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemeAuroraColorNode,
|
|
6
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
speed?: number
|
|
11
|
+
intensity?: number
|
|
12
|
+
mouseInteraction?: boolean
|
|
13
|
+
mouseStrength?: number
|
|
14
|
+
color1?: string
|
|
15
|
+
color2?: string
|
|
16
|
+
color3?: string
|
|
17
|
+
color4?: string
|
|
18
|
+
}>(),
|
|
19
|
+
{
|
|
20
|
+
speed: 1.0,
|
|
21
|
+
intensity: 1.0,
|
|
22
|
+
mouseInteraction: true,
|
|
23
|
+
mouseStrength: 0.3,
|
|
24
|
+
color1: '#8b5cf6',
|
|
25
|
+
color2: '#6366f1',
|
|
26
|
+
color3: '#a78bfa',
|
|
27
|
+
color4: '#38bdf8',
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
node: [colorNode: any]
|
|
33
|
+
}>()
|
|
34
|
+
|
|
35
|
+
const uniforms = createAmbientUniforms({
|
|
36
|
+
speed: props.speed,
|
|
37
|
+
intensity: props.intensity,
|
|
38
|
+
mouseInteraction: props.mouseInteraction,
|
|
39
|
+
})
|
|
40
|
+
if (props.mouseInteraction) {
|
|
41
|
+
uniforms.mouseStrength.value = props.mouseStrength
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const c1 = useShaderColor(props.color1)
|
|
45
|
+
const c2 = useShaderColor(props.color2)
|
|
46
|
+
const c3 = useShaderColor(props.color3)
|
|
47
|
+
const c4 = useShaderColor(props.color4)
|
|
48
|
+
|
|
49
|
+
const colorNode = createThemeAuroraColorNode(uniforms, {
|
|
50
|
+
color1: c1.node,
|
|
51
|
+
color2: c2.node,
|
|
52
|
+
color3: c3.node,
|
|
53
|
+
color4: c4.node,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
watch(() => props.color1, (hex) => c1.tweenTo(hex, 0.8))
|
|
57
|
+
watch(() => props.color2, (hex) => c2.tweenTo(hex, 0.8))
|
|
58
|
+
watch(() => props.color3, (hex) => c3.tweenTo(hex, 0.8))
|
|
59
|
+
watch(() => props.color4, (hex) => c4.tweenTo(hex, 0.8))
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const runtime = useShaderRuntimeContext()
|
|
63
|
+
watch(
|
|
64
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
65
|
+
([mx, my]) => {
|
|
66
|
+
uniforms.mouseX.value = mx
|
|
67
|
+
uniforms.mouseY.value = my
|
|
68
|
+
},
|
|
69
|
+
{ immediate: true }
|
|
70
|
+
)
|
|
71
|
+
} catch {
|
|
72
|
+
// No runtime context
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
76
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
77
|
+
watch(() => props.mouseInteraction, (v) => { uniforms.mouseStrength.value = v ? props.mouseStrength : 0 })
|
|
78
|
+
watch(() => props.mouseStrength, (v) => { if (props.mouseInteraction) uniforms.mouseStrength.value = v })
|
|
79
|
+
|
|
80
|
+
emit('node', colorNode)
|
|
81
|
+
defineExpose({ uniforms, colorNode })
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<slot />
|
|
86
|
+
</template>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemeBubbleColorNode,
|
|
6
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
speed?: number
|
|
11
|
+
intensity?: number
|
|
12
|
+
mouseInteraction?: boolean
|
|
13
|
+
mouseStrength?: number
|
|
14
|
+
color1?: string
|
|
15
|
+
color2?: string
|
|
16
|
+
color3?: string
|
|
17
|
+
color4?: string
|
|
18
|
+
}>(),
|
|
19
|
+
{
|
|
20
|
+
speed: 1.0,
|
|
21
|
+
intensity: 1.0,
|
|
22
|
+
mouseInteraction: true,
|
|
23
|
+
mouseStrength: 0.3,
|
|
24
|
+
color1: '#8b5cf6',
|
|
25
|
+
color2: '#6366f1',
|
|
26
|
+
color3: '#a78bfa',
|
|
27
|
+
color4: '#38bdf8',
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
node: [colorNode: any]
|
|
33
|
+
}>()
|
|
34
|
+
|
|
35
|
+
const uniforms = createAmbientUniforms({
|
|
36
|
+
speed: props.speed,
|
|
37
|
+
intensity: props.intensity,
|
|
38
|
+
mouseInteraction: props.mouseInteraction,
|
|
39
|
+
})
|
|
40
|
+
if (props.mouseInteraction) {
|
|
41
|
+
uniforms.mouseStrength.value = props.mouseStrength
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const c1 = useShaderColor(props.color1)
|
|
45
|
+
const c2 = useShaderColor(props.color2)
|
|
46
|
+
const c3 = useShaderColor(props.color3)
|
|
47
|
+
const c4 = useShaderColor(props.color4)
|
|
48
|
+
|
|
49
|
+
// color3/color4 accepted for API consistency but Bubble only uses color1+color2
|
|
50
|
+
const colorNode = createThemeBubbleColorNode(uniforms, {
|
|
51
|
+
color1: c1.node,
|
|
52
|
+
color2: c2.node,
|
|
53
|
+
color3: c3.node,
|
|
54
|
+
color4: c4.node,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
watch(() => props.color1, (hex) => c1.tweenTo(hex, 0.8))
|
|
58
|
+
watch(() => props.color2, (hex) => c2.tweenTo(hex, 0.8))
|
|
59
|
+
watch(() => props.color3, (hex) => c3.tweenTo(hex, 0.8))
|
|
60
|
+
watch(() => props.color4, (hex) => c4.tweenTo(hex, 0.8))
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const runtime = useShaderRuntimeContext()
|
|
64
|
+
watch(
|
|
65
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
66
|
+
([mx, my]) => {
|
|
67
|
+
uniforms.mouseX.value = mx
|
|
68
|
+
uniforms.mouseY.value = my
|
|
69
|
+
},
|
|
70
|
+
{ immediate: true }
|
|
71
|
+
)
|
|
72
|
+
} catch {
|
|
73
|
+
// No runtime context
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
77
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
78
|
+
watch(() => props.mouseInteraction, (v) => { uniforms.mouseStrength.value = v ? props.mouseStrength : 0 })
|
|
79
|
+
watch(() => props.mouseStrength, (v) => { if (props.mouseInteraction) uniforms.mouseStrength.value = v })
|
|
80
|
+
|
|
81
|
+
emit('node', colorNode)
|
|
82
|
+
defineExpose({ uniforms, colorNode })
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<slot />
|
|
87
|
+
</template>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemeFlowColorNode,
|
|
6
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
speed?: number
|
|
11
|
+
intensity?: number
|
|
12
|
+
mouseInteraction?: boolean
|
|
13
|
+
mouseStrength?: number
|
|
14
|
+
color1?: string
|
|
15
|
+
color2?: string
|
|
16
|
+
color3?: string
|
|
17
|
+
color4?: string
|
|
18
|
+
}>(),
|
|
19
|
+
{
|
|
20
|
+
speed: 1.0,
|
|
21
|
+
intensity: 1.0,
|
|
22
|
+
mouseInteraction: true,
|
|
23
|
+
mouseStrength: 0.3,
|
|
24
|
+
color1: '#8b5cf6',
|
|
25
|
+
color2: '#6366f1',
|
|
26
|
+
color3: '#a78bfa',
|
|
27
|
+
color4: '#38bdf8',
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
node: [colorNode: any]
|
|
33
|
+
}>()
|
|
34
|
+
|
|
35
|
+
const uniforms = createAmbientUniforms({
|
|
36
|
+
speed: props.speed,
|
|
37
|
+
intensity: props.intensity,
|
|
38
|
+
mouseInteraction: props.mouseInteraction,
|
|
39
|
+
})
|
|
40
|
+
if (props.mouseInteraction) {
|
|
41
|
+
uniforms.mouseStrength.value = props.mouseStrength
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const c1 = useShaderColor(props.color1)
|
|
45
|
+
const c2 = useShaderColor(props.color2)
|
|
46
|
+
const c3 = useShaderColor(props.color3)
|
|
47
|
+
const c4 = useShaderColor(props.color4)
|
|
48
|
+
|
|
49
|
+
const colorNode = createThemeFlowColorNode(uniforms, {
|
|
50
|
+
color1: c1.node,
|
|
51
|
+
color2: c2.node,
|
|
52
|
+
color3: c3.node,
|
|
53
|
+
color4: c4.node,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
watch(() => props.color1, (hex) => c1.tweenTo(hex, 0.8))
|
|
57
|
+
watch(() => props.color2, (hex) => c2.tweenTo(hex, 0.8))
|
|
58
|
+
watch(() => props.color3, (hex) => c3.tweenTo(hex, 0.8))
|
|
59
|
+
watch(() => props.color4, (hex) => c4.tweenTo(hex, 0.8))
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const runtime = useShaderRuntimeContext()
|
|
63
|
+
watch(
|
|
64
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
65
|
+
([mx, my]) => {
|
|
66
|
+
uniforms.mouseX.value = mx
|
|
67
|
+
uniforms.mouseY.value = my
|
|
68
|
+
},
|
|
69
|
+
{ immediate: true }
|
|
70
|
+
)
|
|
71
|
+
} catch {
|
|
72
|
+
// No runtime context
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
76
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
77
|
+
watch(() => props.mouseInteraction, (v) => { uniforms.mouseStrength.value = v ? props.mouseStrength : 0 })
|
|
78
|
+
watch(() => props.mouseStrength, (v) => { if (props.mouseInteraction) uniforms.mouseStrength.value = v })
|
|
79
|
+
|
|
80
|
+
emit('node', colorNode)
|
|
81
|
+
defineExpose({ uniforms, colorNode })
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<slot />
|
|
86
|
+
</template>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemeGradientColorNode,
|
|
6
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
speed?: number
|
|
11
|
+
intensity?: number
|
|
12
|
+
mouseInteraction?: boolean
|
|
13
|
+
mouseStrength?: number
|
|
14
|
+
color1?: string
|
|
15
|
+
color2?: string
|
|
16
|
+
color3?: string
|
|
17
|
+
color4?: string
|
|
18
|
+
}>(),
|
|
19
|
+
{
|
|
20
|
+
speed: 1.0,
|
|
21
|
+
intensity: 1.0,
|
|
22
|
+
mouseInteraction: true,
|
|
23
|
+
mouseStrength: 0.3,
|
|
24
|
+
color1: '#8b5cf6',
|
|
25
|
+
color2: '#6366f1',
|
|
26
|
+
color3: '#a78bfa',
|
|
27
|
+
color4: '#38bdf8',
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
node: [colorNode: any]
|
|
33
|
+
}>()
|
|
34
|
+
|
|
35
|
+
const uniforms = createAmbientUniforms({
|
|
36
|
+
speed: props.speed,
|
|
37
|
+
intensity: props.intensity,
|
|
38
|
+
mouseInteraction: props.mouseInteraction,
|
|
39
|
+
})
|
|
40
|
+
// createAmbientUniforms hardcodes 0.5 — override with our prop value
|
|
41
|
+
if (props.mouseInteraction) {
|
|
42
|
+
uniforms.mouseStrength.value = props.mouseStrength
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const c1 = useShaderColor(props.color1)
|
|
46
|
+
const c2 = useShaderColor(props.color2)
|
|
47
|
+
const c3 = useShaderColor(props.color3)
|
|
48
|
+
const c4 = useShaderColor(props.color4)
|
|
49
|
+
|
|
50
|
+
const colorNode = createThemeGradientColorNode(uniforms, {
|
|
51
|
+
color1: c1.node,
|
|
52
|
+
color2: c2.node,
|
|
53
|
+
color3: c3.node,
|
|
54
|
+
color4: c4.node,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
watch(() => props.color1, (hex) => c1.tweenTo(hex, 0.8))
|
|
58
|
+
watch(() => props.color2, (hex) => c2.tweenTo(hex, 0.8))
|
|
59
|
+
watch(() => props.color3, (hex) => c3.tweenTo(hex, 0.8))
|
|
60
|
+
watch(() => props.color4, (hex) => c4.tweenTo(hex, 0.8))
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const runtime = useShaderRuntimeContext()
|
|
64
|
+
watch(
|
|
65
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
66
|
+
([mx, my]) => {
|
|
67
|
+
uniforms.mouseX.value = mx
|
|
68
|
+
uniforms.mouseY.value = my
|
|
69
|
+
},
|
|
70
|
+
{ immediate: true }
|
|
71
|
+
)
|
|
72
|
+
} catch {
|
|
73
|
+
// No runtime context
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
77
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
78
|
+
watch(() => props.mouseInteraction, (v) => { uniforms.mouseStrength.value = v ? props.mouseStrength : 0 })
|
|
79
|
+
watch(() => props.mouseStrength, (v) => { if (props.mouseInteraction) uniforms.mouseStrength.value = v })
|
|
80
|
+
|
|
81
|
+
emit('node', colorNode)
|
|
82
|
+
defineExpose({ uniforms, colorNode })
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<slot />
|
|
87
|
+
</template>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemeLavaLampColorNode,
|
|
6
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
speed?: number
|
|
11
|
+
intensity?: number
|
|
12
|
+
mouseInteraction?: boolean
|
|
13
|
+
mouseStrength?: number
|
|
14
|
+
color1?: string
|
|
15
|
+
color2?: string
|
|
16
|
+
color3?: string
|
|
17
|
+
color4?: string
|
|
18
|
+
}>(),
|
|
19
|
+
{
|
|
20
|
+
speed: 1.0,
|
|
21
|
+
intensity: 1.0,
|
|
22
|
+
mouseInteraction: true,
|
|
23
|
+
mouseStrength: 0.3,
|
|
24
|
+
color1: '#8b5cf6',
|
|
25
|
+
color2: '#6366f1',
|
|
26
|
+
color3: '#a78bfa',
|
|
27
|
+
color4: '#38bdf8',
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
node: [colorNode: any]
|
|
33
|
+
}>()
|
|
34
|
+
|
|
35
|
+
const uniforms = createAmbientUniforms({
|
|
36
|
+
speed: props.speed,
|
|
37
|
+
intensity: props.intensity,
|
|
38
|
+
mouseInteraction: props.mouseInteraction,
|
|
39
|
+
})
|
|
40
|
+
if (props.mouseInteraction) {
|
|
41
|
+
uniforms.mouseStrength.value = props.mouseStrength
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const c1 = useShaderColor(props.color1)
|
|
45
|
+
const c2 = useShaderColor(props.color2)
|
|
46
|
+
const c3 = useShaderColor(props.color3)
|
|
47
|
+
const c4 = useShaderColor(props.color4)
|
|
48
|
+
|
|
49
|
+
const colorNode = createThemeLavaLampColorNode(uniforms, {
|
|
50
|
+
color1: c1.node,
|
|
51
|
+
color2: c2.node,
|
|
52
|
+
color3: c3.node,
|
|
53
|
+
color4: c4.node,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
watch(() => props.color1, (hex) => c1.tweenTo(hex, 0.8))
|
|
57
|
+
watch(() => props.color2, (hex) => c2.tweenTo(hex, 0.8))
|
|
58
|
+
watch(() => props.color3, (hex) => c3.tweenTo(hex, 0.8))
|
|
59
|
+
watch(() => props.color4, (hex) => c4.tweenTo(hex, 0.8))
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const runtime = useShaderRuntimeContext()
|
|
63
|
+
watch(
|
|
64
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
65
|
+
([mx, my]) => {
|
|
66
|
+
uniforms.mouseX.value = mx
|
|
67
|
+
uniforms.mouseY.value = my
|
|
68
|
+
},
|
|
69
|
+
{ immediate: true }
|
|
70
|
+
)
|
|
71
|
+
} catch {
|
|
72
|
+
// No runtime context
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
76
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
77
|
+
watch(() => props.mouseInteraction, (v) => { uniforms.mouseStrength.value = v ? props.mouseStrength : 0 })
|
|
78
|
+
watch(() => props.mouseStrength, (v) => { if (props.mouseInteraction) uniforms.mouseStrength.value = v })
|
|
79
|
+
|
|
80
|
+
emit('node', colorNode)
|
|
81
|
+
defineExpose({ uniforms, colorNode })
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<slot />
|
|
86
|
+
</template>
|