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,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemePlasmaColorNode,
|
|
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 = createThemePlasmaColorNode(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,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createThemeWaveColorNode,
|
|
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 = createThemeWaveColorNode(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>
|
|
@@ -118,6 +118,12 @@ async function init() {
|
|
|
118
118
|
planeMesh = new Mesh(geometry, props.material ?? new MeshBasicMaterial({ color: 0x000000 }))
|
|
119
119
|
scene.add(planeMesh)
|
|
120
120
|
|
|
121
|
+
// Pre-compile the shader pipeline asynchronously before starting the render loop.
|
|
122
|
+
// Without this, the first render() call uses device.createRenderPipeline() which
|
|
123
|
+
// blocks the main thread for 1-5s on first visit (cold WebGPU pipeline cache).
|
|
124
|
+
// compileAsync() uses device.createRenderPipelineAsync() instead, which is non-blocking.
|
|
125
|
+
await renderer.compileAsync(scene, camera)
|
|
126
|
+
|
|
121
127
|
initialized = true
|
|
122
128
|
emit('ready', renderer)
|
|
123
129
|
animate()
|
|
@@ -132,6 +138,15 @@ watch(
|
|
|
132
138
|
}
|
|
133
139
|
)
|
|
134
140
|
|
|
141
|
+
watch(
|
|
142
|
+
() => props.clearColor,
|
|
143
|
+
(color) => {
|
|
144
|
+
if (renderer && initialized) {
|
|
145
|
+
renderer.setClearColor(new Color(color))
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
|
|
135
150
|
watch([width, height], ([w, h]) => {
|
|
136
151
|
if (!initialized) return
|
|
137
152
|
camera.aspect = w / (h || 1)
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
mix,
|
|
11
11
|
mul,
|
|
12
12
|
pow,
|
|
13
|
+
sign,
|
|
13
14
|
sin,
|
|
14
15
|
smoothstep,
|
|
15
16
|
sub,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
import { MeshBasicNodeMaterial } from 'three/webgpu'
|
|
23
24
|
import {
|
|
24
25
|
simplexNoise2D,
|
|
26
|
+
simplexNoise3d,
|
|
25
27
|
fbm2D,
|
|
26
28
|
fbm3dSimplex,
|
|
27
29
|
ridgedFbm2d,
|
|
@@ -277,6 +279,310 @@ export function createGradientMeshColorNode(uniforms: AmbientUniforms): any {
|
|
|
277
279
|
})()
|
|
278
280
|
}
|
|
279
281
|
|
|
282
|
+
export interface ThemeColorUniforms {
|
|
283
|
+
color1: any // TSL uniform node wrapping a THREE.Color
|
|
284
|
+
color2: any
|
|
285
|
+
color3: any
|
|
286
|
+
color4: any
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function createThemeGradientColorNode(
|
|
290
|
+
uniforms: AmbientUniforms,
|
|
291
|
+
colors: ThemeColorUniforms,
|
|
292
|
+
): any {
|
|
293
|
+
const { speed: uSpeed, intensity: uIntensity,
|
|
294
|
+
mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
295
|
+
|
|
296
|
+
return Fn(() => {
|
|
297
|
+
const t = mul(time, uSpeed, 0.2)
|
|
298
|
+
const uvCoord = uv()
|
|
299
|
+
|
|
300
|
+
// Gentle UV shift for p2-p4 area
|
|
301
|
+
const mouseOffset = vec2(
|
|
302
|
+
mul(sub(uMouseX, 0.5), uMouseStrength, 0.05),
|
|
303
|
+
mul(sub(uMouseY, 0.5), uMouseStrength, 0.05),
|
|
304
|
+
)
|
|
305
|
+
const adjustedUV = add(uvCoord, mouseOffset)
|
|
306
|
+
|
|
307
|
+
// p1 attracted toward mouse cursor
|
|
308
|
+
const p1Base = vec2(add(0.2, mul(sin(mul(t, 0.5)), 0.15)), add(0.3, mul(sin(add(mul(t, 0.4), 1.57)), 0.15)))
|
|
309
|
+
const mousePos = vec2(uMouseX, uMouseY)
|
|
310
|
+
const p1 = mix(p1Base, mousePos, mul(uMouseStrength, 0.5))
|
|
311
|
+
|
|
312
|
+
const p2 = vec2(add(0.8, mul(sin(add(mul(t, 0.6), 1.57)), 0.1)), add(0.2, mul(sin(mul(t, 0.5)), 0.1)))
|
|
313
|
+
const p3 = vec2(add(0.3, mul(sin(mul(t, 0.7)), 0.15)), add(0.8, mul(sin(add(mul(t, 0.3), 1.57)), 0.1)))
|
|
314
|
+
const p4 = vec2(add(0.7, mul(sin(add(mul(t, 0.4), 1.57)), 0.15)), add(0.7, mul(sin(mul(t, 0.6)), 0.15)))
|
|
315
|
+
|
|
316
|
+
const nm1 = simplexNoise2D(add(mul(adjustedUV, 3.0), mul(t, 0.3))).mul(0.5).add(0.5)
|
|
317
|
+
const nm2 = simplexNoise2D(add(mul(adjustedUV, 4.5), mul(t, -0.2), 8.0)).mul(0.5).add(0.5)
|
|
318
|
+
const nm3 = fbm2D(add(adjustedUV, mul(t, 0.1)), { octaves: 3, frequency: 2.0 }).mul(0.5).add(0.5)
|
|
319
|
+
const nm4 = simplexNoise2D(add(mul(adjustedUV, 7.0), mul(t, 0.5))).mul(0.5).add(0.5)
|
|
320
|
+
|
|
321
|
+
const d1 = mul(sub(1.0, smoothstep(0.0, 0.7, length(sub(adjustedUV, p1)))), add(0.7, mul(nm1, 0.3)))
|
|
322
|
+
const d2 = mul(sub(1.0, smoothstep(0.0, 0.7, length(sub(adjustedUV, p2)))), add(0.7, mul(nm2, 0.3)))
|
|
323
|
+
const d3 = mul(sub(1.0, smoothstep(0.0, 0.7, length(sub(adjustedUV, p3)))), add(0.7, mul(nm3, 0.3)))
|
|
324
|
+
const d4 = mul(sub(1.0, smoothstep(0.0, 0.7, length(sub(adjustedUV, p4)))), add(0.7, mul(nm4, 0.3)))
|
|
325
|
+
|
|
326
|
+
let colorNode = mul(colors.color1, d1)
|
|
327
|
+
colorNode = add(colorNode, mul(colors.color2, d2))
|
|
328
|
+
colorNode = add(colorNode, mul(colors.color3, d3))
|
|
329
|
+
colorNode = add(colorNode, mul(colors.color4, d4))
|
|
330
|
+
|
|
331
|
+
// Normalise first, then vignette, then intensity
|
|
332
|
+
const totalWeight = add(d1, d2, d3, d4, 0.01)
|
|
333
|
+
colorNode = colorNode.div(totalWeight)
|
|
334
|
+
|
|
335
|
+
const dist = length(sub(uvCoord, 0.5))
|
|
336
|
+
colorNode = mul(colorNode, sub(1.0, mul(dist, 0.25)))
|
|
337
|
+
colorNode = mul(colorNode, uIntensity)
|
|
338
|
+
|
|
339
|
+
return colorNode
|
|
340
|
+
})()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function createThemeFlowColorNode(
|
|
344
|
+
uniforms: AmbientUniforms,
|
|
345
|
+
colors: ThemeColorUniforms,
|
|
346
|
+
): any {
|
|
347
|
+
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
348
|
+
|
|
349
|
+
return Fn(() => {
|
|
350
|
+
const t = mul(time, uSpeed, 0.15)
|
|
351
|
+
const uvCoord = uv()
|
|
352
|
+
|
|
353
|
+
const mouseOffset = vec2(
|
|
354
|
+
mul(sub(uMouseX, 0.5), uMouseStrength, 0.3),
|
|
355
|
+
mul(sub(uMouseY, 0.5), uMouseStrength, 0.3),
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
const warpCoarse1 = simplexNoise2D(add(mul(uvCoord, 1.5), t))
|
|
359
|
+
const warpCoarse2 = simplexNoise2D(add(mul(uvCoord, 1.5), mul(t, -0.5), 7.0))
|
|
360
|
+
const warpedUV1 = add(uvCoord, mul(vec2(warpCoarse1, warpCoarse2), 0.25), mouseOffset)
|
|
361
|
+
|
|
362
|
+
const warpMed1 = simplexNoise2D(add(mul(warpedUV1, 3.0), mul(t, 0.7)))
|
|
363
|
+
const warpMed2 = simplexNoise2D(add(mul(warpedUV1, 3.0), mul(t, -0.3), 15.0))
|
|
364
|
+
const warpedUV2 = add(warpedUV1, mul(vec2(warpMed1, warpMed2), 0.12))
|
|
365
|
+
|
|
366
|
+
const warpFine1 = simplexNoise2D(add(mul(warpedUV2, 5.0), mul(t, 1.2)))
|
|
367
|
+
const warpFine2 = simplexNoise2D(add(mul(warpedUV2, 5.0), mul(t, -0.8), 25.0))
|
|
368
|
+
const warpedUV = add(warpedUV2, mul(vec2(warpFine1, warpFine2), 0.05))
|
|
369
|
+
|
|
370
|
+
const n1 = fbm2D(warpedUV, { octaves: 5, frequency: 2.0 }).mul(0.5).add(0.5)
|
|
371
|
+
const n2 = ridgedFbm2d(warpedUV, { octaves: 4, frequency: 1.5 })
|
|
372
|
+
|
|
373
|
+
let colorNode = mix(colors.color1, colors.color2, n1)
|
|
374
|
+
colorNode = mix(colorNode, colors.color3, mul(n2, 0.5))
|
|
375
|
+
|
|
376
|
+
const iridescence = mix(colors.color3, colors.color4, add(mul(n1, 0.6), mul(n2, 0.4)))
|
|
377
|
+
colorNode = mix(colorNode, iridescence, 0.3)
|
|
378
|
+
colorNode = mix(colorNode, colors.color4, mul(smoothstep(0.6, 0.9, n2), 0.25))
|
|
379
|
+
|
|
380
|
+
const brightness = add(0.85, mul(0.15, sin(add(mul(n1, 6.28), t))))
|
|
381
|
+
colorNode = mul(colorNode, brightness, uIntensity)
|
|
382
|
+
|
|
383
|
+
const dist = length(sub(uvCoord, 0.5))
|
|
384
|
+
colorNode = mul(colorNode, sub(1.0, mul(dist, 0.3)))
|
|
385
|
+
|
|
386
|
+
return colorNode
|
|
387
|
+
})()
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export function createThemeAuroraColorNode(
|
|
391
|
+
uniforms: AmbientUniforms,
|
|
392
|
+
colors: ThemeColorUniforms,
|
|
393
|
+
): any {
|
|
394
|
+
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
395
|
+
|
|
396
|
+
return Fn(() => {
|
|
397
|
+
const t = mul(time, uSpeed, 0.2)
|
|
398
|
+
const uvCoord = uv()
|
|
399
|
+
|
|
400
|
+
const mouseOffset = vec2(
|
|
401
|
+
mul(sub(uMouseX, 0.5), uMouseStrength),
|
|
402
|
+
mul(sub(uMouseY, 0.5), uMouseStrength),
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
const curtainCoord = add(
|
|
406
|
+
vec2(mul(uvCoord.x, 3.0), mul(uvCoord.y, 0.5)),
|
|
407
|
+
vec2(t, mul(t, 0.3)),
|
|
408
|
+
mouseOffset,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
const curtain1 = simplexNoise2D(curtainCoord).mul(0.5).add(0.5)
|
|
412
|
+
const curtain2 = simplexNoise2D(add(mul(curtainCoord, 1.5), vec2(mul(t, -0.2), 5.0))).mul(0.5).add(0.5)
|
|
413
|
+
const curtain3 = simplexNoise2D(add(mul(curtainCoord, 0.7), vec2(mul(t, 0.4), 12.0))).mul(0.5).add(0.5)
|
|
414
|
+
const detail = fbm2D(curtainCoord, { octaves: 4, frequency: 2.0 }).mul(0.5).add(0.5)
|
|
415
|
+
const curtain = mul(add(mul(curtain1, 0.4), mul(curtain2, 0.25), mul(curtain3, 0.2), mul(detail, 0.15)), 1.0)
|
|
416
|
+
|
|
417
|
+
const fade = mul(pow(sub(1.0, uvCoord.y), 1.2), smoothstep(0.0, 0.3, uvCoord.y))
|
|
418
|
+
const aurora = mul(smoothstep(0.2, 0.8, mul(curtain, fade)), uIntensity)
|
|
419
|
+
|
|
420
|
+
const shimmer = simplexNoise2D(add(mul(curtainCoord, 8.0), mul(t, 3.0))).mul(0.5).add(0.5)
|
|
421
|
+
|
|
422
|
+
const colorDriver = add(mul(curtain2, 0.6), mul(curtain3, 0.4))
|
|
423
|
+
const auroraColor = mix(colors.color1, colors.color2, colorDriver)
|
|
424
|
+
|
|
425
|
+
const skyColor = mul(colors.color1, 0.04)
|
|
426
|
+
const shimmerColor = mul(colors.color3, mul(shimmer, mul(aurora, 0.15)))
|
|
427
|
+
|
|
428
|
+
return add(mix(skyColor, auroraColor, aurora), shimmerColor)
|
|
429
|
+
})()
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export function createThemeWaveColorNode(
|
|
433
|
+
uniforms: AmbientUniforms,
|
|
434
|
+
colors: ThemeColorUniforms,
|
|
435
|
+
): any {
|
|
436
|
+
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
437
|
+
|
|
438
|
+
return Fn(() => {
|
|
439
|
+
const t = mul(time, uSpeed, 0.1)
|
|
440
|
+
const mouseOff = vec2(
|
|
441
|
+
mul(sub(uMouseX, 0.5), uMouseStrength),
|
|
442
|
+
mul(sub(uMouseY, 0.5), uMouseStrength),
|
|
443
|
+
)
|
|
444
|
+
const uvCoord = add(sub(uv(), 0.5), mouseOff)
|
|
445
|
+
|
|
446
|
+
// Noise-driven rotation
|
|
447
|
+
const degree = simplexNoise2D(vec2(t, uvCoord.x.mul(uvCoord.y))).mul(0.5).add(0.5)
|
|
448
|
+
const angle = degree.sub(0.5).mul(720.0 * Math.PI / 180.0).add(Math.PI)
|
|
449
|
+
const cosA = angle.cos()
|
|
450
|
+
const sinA = angle.sin()
|
|
451
|
+
const rx = uvCoord.x.mul(cosA).sub(uvCoord.y.mul(sinA))
|
|
452
|
+
const ry = uvCoord.x.mul(sinA).add(uvCoord.y.mul(cosA))
|
|
453
|
+
|
|
454
|
+
// Wave warp (order matters: warped x feeds into y)
|
|
455
|
+
const waveSpeed = mul(time, uSpeed, 2.0)
|
|
456
|
+
const wx = rx.add(sin(ry.mul(5.0).add(waveSpeed)).div(30.0))
|
|
457
|
+
const wy = ry.add(sin(wx.mul(7.5).add(waveSpeed)).div(15.0))
|
|
458
|
+
|
|
459
|
+
// -5° rotation for layer blend
|
|
460
|
+
const COS5 = Math.cos(-5 * Math.PI / 180)
|
|
461
|
+
const SIN5 = Math.sin(-5 * Math.PI / 180)
|
|
462
|
+
const rotated5x = wx.mul(COS5).sub(wy.mul(SIN5))
|
|
463
|
+
|
|
464
|
+
const layer1 = mix(colors.color1, colors.color2, smoothstep(-0.3, 0.2, rotated5x))
|
|
465
|
+
const layer2 = mix(colors.color3, colors.color4, smoothstep(-0.3, 0.2, rotated5x))
|
|
466
|
+
|
|
467
|
+
return mix(layer1, layer2, smoothstep(0.5, -0.3, wy)).mul(uIntensity)
|
|
468
|
+
})()
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export function createThemeLavaLampColorNode(
|
|
472
|
+
uniforms: AmbientUniforms,
|
|
473
|
+
colors: ThemeColorUniforms,
|
|
474
|
+
): any {
|
|
475
|
+
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
476
|
+
|
|
477
|
+
return Fn(() => {
|
|
478
|
+
const t = mul(time, uSpeed, 0.2)
|
|
479
|
+
const mouseOff = vec2(
|
|
480
|
+
mul(sub(uMouseX, 0.5), uMouseStrength),
|
|
481
|
+
mul(sub(uMouseY, 0.5), uMouseStrength),
|
|
482
|
+
)
|
|
483
|
+
const uvCoord = add(sub(uv(), 0.5), mouseOff)
|
|
484
|
+
|
|
485
|
+
// 4 blobs anchored to quadrants, oscillation wide enough to cross center and intersect
|
|
486
|
+
const b1 = vec2(sin(mul(t, 0.9)).mul(0.22).sub(0.20), sin(mul(t, 0.7)).mul(0.22).sub(0.18))
|
|
487
|
+
const b2 = vec2(sin(mul(t, 0.8).add(2.1)).mul(0.22).add(0.20), sin(mul(t, 1.0).add(1.5)).mul(0.22).sub(0.18))
|
|
488
|
+
const b3 = vec2(sin(mul(t, 0.6).add(4.2)).mul(0.22).sub(0.20), sin(mul(t, 0.9).add(3.1)).mul(0.22).add(0.18))
|
|
489
|
+
const b4 = vec2(sin(mul(t, 1.1).add(1.0)).mul(0.22).add(0.20), sin(mul(t, 0.5).add(2.8)).mul(0.22).add(0.18))
|
|
490
|
+
|
|
491
|
+
// Per-blob breathing k: oscillates between -3.5 (large) and -6.5 (tight)
|
|
492
|
+
const k1 = sin(mul(t, 0.4)).mul(1.5).sub(5.0)
|
|
493
|
+
const k2 = sin(add(mul(t, 0.35), 2.1)).mul(1.5).sub(5.0)
|
|
494
|
+
const k3 = sin(add(mul(t, 0.45), 4.2)).mul(1.5).sub(5.0)
|
|
495
|
+
const k4 = sin(add(mul(t, 0.3), 1.0)).mul(1.5).sub(5.0)
|
|
496
|
+
|
|
497
|
+
const w1 = exp(length(sub(uvCoord, b1)).mul(k1))
|
|
498
|
+
const w2 = exp(length(sub(uvCoord, b2)).mul(k2))
|
|
499
|
+
const w3 = exp(length(sub(uvCoord, b3)).mul(k3))
|
|
500
|
+
const w4 = exp(length(sub(uvCoord, b4)).mul(k4))
|
|
501
|
+
const wTotal = add(w1, w2, w3, w4)
|
|
502
|
+
|
|
503
|
+
// Weighted colour blend
|
|
504
|
+
const colorNode = add(
|
|
505
|
+
mul(colors.color1, w1),
|
|
506
|
+
mul(colors.color2, w2),
|
|
507
|
+
mul(colors.color3, w3),
|
|
508
|
+
mul(colors.color4, w4),
|
|
509
|
+
).div(wTotal.add(0.001))
|
|
510
|
+
|
|
511
|
+
// Darken space between blobs
|
|
512
|
+
const blobStrength = smoothstep(0.05, 0.9, wTotal)
|
|
513
|
+
const bg = mul(mix(colors.color1, colors.color2, 0.3), 0.15)
|
|
514
|
+
return mix(bg, colorNode, blobStrength).mul(uIntensity)
|
|
515
|
+
})()
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export function createThemeBubbleColorNode(
|
|
519
|
+
uniforms: AmbientUniforms,
|
|
520
|
+
colors: ThemeColorUniforms,
|
|
521
|
+
): any {
|
|
522
|
+
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
523
|
+
|
|
524
|
+
return Fn(() => {
|
|
525
|
+
const t = mul(time, uSpeed, 0.06)
|
|
526
|
+
const mouseOff = vec2(
|
|
527
|
+
mul(sub(uMouseX, 0.5), uMouseStrength),
|
|
528
|
+
mul(sub(uMouseY, 0.5), uMouseStrength),
|
|
529
|
+
)
|
|
530
|
+
const uvCoord = add(uv(), mouseOff)
|
|
531
|
+
|
|
532
|
+
const n1 = simplexNoise3d(vec3(uvCoord.x.mul(1.5), uvCoord.y.mul(1.5), t)).mul(0.5).add(0.5)
|
|
533
|
+
const n2 = simplexNoise3d(vec3(
|
|
534
|
+
uvCoord.x.mul(2.5).add(1.3), uvCoord.y.mul(2.5).add(0.7), t.mul(0.8),
|
|
535
|
+
)).mul(0.5).add(0.5)
|
|
536
|
+
|
|
537
|
+
const blend1 = mix(colors.color1, colors.color2, smoothstep(0.3, 0.7, n1))
|
|
538
|
+
const blend2 = mix(colors.color3, colors.color4, smoothstep(0.3, 0.7, n2))
|
|
539
|
+
return mix(blend1, blend2, smoothstep(0.35, 0.65, n2)).mul(uIntensity)
|
|
540
|
+
})()
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export function createThemePlasmaColorNode(
|
|
544
|
+
uniforms: AmbientUniforms,
|
|
545
|
+
colors: ThemeColorUniforms,
|
|
546
|
+
): any {
|
|
547
|
+
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
548
|
+
|
|
549
|
+
return Fn(() => {
|
|
550
|
+
const t = mul(time, uSpeed, 0.03)
|
|
551
|
+
const mouseOff = vec2(
|
|
552
|
+
mul(sub(uMouseX, 0.5), uMouseStrength, 0.2),
|
|
553
|
+
mul(sub(uMouseY, 0.5), uMouseStrength, 0.2),
|
|
554
|
+
)
|
|
555
|
+
const uvMut = add(sub(uv(), 0.5).mul(1.2), mouseOff).toVar()
|
|
556
|
+
|
|
557
|
+
const h = simplexNoise3d(vec3(uvMut.x.mul(2.0), uvMut.y.mul(2.0), t)).toVar()
|
|
558
|
+
|
|
559
|
+
// Unrolled distortion loop (n = 1..4)
|
|
560
|
+
for (let n = 1; n < 5; n++) {
|
|
561
|
+
const i = float(n)
|
|
562
|
+
uvMut.subAssign(vec2(
|
|
563
|
+
float(0.7).div(i).mul(sin(i.mul(uvMut.y).add(i).add(t.mul(1.5)).add(h.mul(i)))),
|
|
564
|
+
float(0.4).div(i).mul(sin(uvMut.x.add(4.0).sub(i).add(h).add(t.mul(1.5)).add(i.mul(0.3)))),
|
|
565
|
+
))
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Final UV shift
|
|
569
|
+
uvMut.subAssign(vec2(
|
|
570
|
+
float(1.2).mul(sin(uvMut.x.add(t).add(h))),
|
|
571
|
+
float(0.4).mul(sin(uvMut.y.add(t).add(h.mul(0.3)))),
|
|
572
|
+
))
|
|
573
|
+
|
|
574
|
+
const cx = sin(uvMut.x.mul(2.0)).mul(0.5).add(0.5)
|
|
575
|
+
const cxy = sin(uvMut.x.add(uvMut.y).mul(1.5)).mul(0.5).add(0.5)
|
|
576
|
+
const cy = sin(uvMut.y.mul(2.0)).mul(0.5).add(0.5)
|
|
577
|
+
|
|
578
|
+
const t12 = mix(colors.color1, colors.color2, cx)
|
|
579
|
+
const t34 = mix(colors.color3, colors.color4, cy)
|
|
580
|
+
const vivid = mix(t12, t34, cxy)
|
|
581
|
+
// Mix against near-black base so black/gray reads through between colour bands
|
|
582
|
+
return mix(vec3(0.03, 0.03, 0.03), vivid, float(0.65)).mul(uIntensity)
|
|
583
|
+
})()
|
|
584
|
+
}
|
|
585
|
+
|
|
280
586
|
export function createOceanColorNode(uniforms: AmbientUniforms): any {
|
|
281
587
|
const { speed: uSpeed, intensity: uIntensity, mouseX: uMouseX, mouseY: uMouseY, mouseStrength: uMouseStrength } = uniforms
|
|
282
588
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { parseOKLCH, oklchToColor } from '../utils/tsl/oklch'
|
|
2
|
+
|
|
3
|
+
export function useThemeColors() {
|
|
4
|
+
const { activeAccent } = useAccentColor()
|
|
5
|
+
const colorMode = useColorMode()
|
|
6
|
+
|
|
7
|
+
const primaryHex = ref('#8b5cf6')
|
|
8
|
+
const secondaryHex = ref('#6366f1')
|
|
9
|
+
const infoHex = ref('#38bdf8')
|
|
10
|
+
const primaryLightHex = ref('#a78bfa')
|
|
11
|
+
|
|
12
|
+
const clearColor = computed(() =>
|
|
13
|
+
colorMode.value === 'dark' ? '#0a0a0a' : '#f8f8f8'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
function cssVarToHex(varName: string): string {
|
|
17
|
+
const raw = getComputedStyle(document.documentElement)
|
|
18
|
+
.getPropertyValue(varName).trim()
|
|
19
|
+
try {
|
|
20
|
+
const [l, c, h] = parseOKLCH(raw)
|
|
21
|
+
return `#${oklchToColor(l, c, h).getHexString()}`
|
|
22
|
+
} catch {
|
|
23
|
+
return '#888888'
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function applyColors() {
|
|
28
|
+
const isDark = colorMode.value === 'dark'
|
|
29
|
+
const primary = cssVarToHex('--ui-color-primary-500')
|
|
30
|
+
// CSS vars not ready yet (returns fallback) — retry next frame
|
|
31
|
+
if (primary === '#888888') {
|
|
32
|
+
requestAnimationFrame(applyColors)
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
primaryHex.value = primary
|
|
36
|
+
secondaryHex.value = isDark ? cssVarToHex('--ui-color-neutral-700') : cssVarToHex('--ui-color-secondary-500')
|
|
37
|
+
primaryLightHex.value = isDark ? cssVarToHex('--ui-color-neutral-900') : cssVarToHex('--ui-color-primary-300')
|
|
38
|
+
infoHex.value = isDark ? cssVarToHex('--ui-color-secondary-500') : cssVarToHex('--ui-color-neutral-300')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function refresh() {
|
|
42
|
+
nextTick(applyColors)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (import.meta.client) {
|
|
46
|
+
watch(activeAccent, refresh, { immediate: true })
|
|
47
|
+
watch(() => colorMode.value, refresh)
|
|
48
|
+
onMounted(applyColors)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { primaryHex, secondaryHex, infoHex, primaryLightHex, clearColor, refresh }
|
|
52
|
+
}
|
|
@@ -23,15 +23,21 @@ export function oklchToLinearSRGB(l: TSLNode, c: TSLNode, h: TSLNode): TSLNode {
|
|
|
23
23
|
// OKLab -> linear sRGB (approximate matrix transform)
|
|
24
24
|
const l_ = l.add(mul(a, float(0.3963377774))).add(mul(b, float(0.2158037573)))
|
|
25
25
|
const m_ = l.sub(mul(a, float(0.1055613458))).sub(mul(b, float(0.0638541728)))
|
|
26
|
-
const s_ = l.sub(mul(a, float(0.0894841775))).sub(mul(b, float(1.
|
|
26
|
+
const s_ = l.sub(mul(a, float(0.0894841775))).sub(mul(b, float(1.291485548)))
|
|
27
27
|
|
|
28
28
|
const lCubed = pow(l_, 3)
|
|
29
29
|
const mCubed = pow(m_, 3)
|
|
30
30
|
const sCubed = pow(s_, 3)
|
|
31
31
|
|
|
32
|
-
const r = mul(lCubed, float(4.0767416621))
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const r = mul(lCubed, float(4.0767416621))
|
|
33
|
+
.sub(mul(mCubed, float(3.3077115913)))
|
|
34
|
+
.add(mul(sCubed, float(0.2309699292)))
|
|
35
|
+
const g = mul(lCubed, float(-1.2684380046))
|
|
36
|
+
.add(mul(mCubed, float(2.6097574011)))
|
|
37
|
+
.sub(mul(sCubed, float(0.3413193965)))
|
|
38
|
+
const bOut = mul(lCubed, float(-0.0041960863))
|
|
39
|
+
.sub(mul(mCubed, float(0.7034186147)))
|
|
40
|
+
.add(mul(sCubed, float(1.707614701)))
|
|
35
41
|
|
|
36
42
|
return vec3(r, g, bOut)
|
|
37
43
|
}
|
|
@@ -70,7 +76,7 @@ export function oklchToColor(l: number, c: number, h: number): Color {
|
|
|
70
76
|
// OKLab to linear sRGB (approximate)
|
|
71
77
|
const l_ = l + a * 0.3963377774 + b * 0.2158037573
|
|
72
78
|
const m_ = l - a * 0.1055613458 - b * 0.0638541728
|
|
73
|
-
const s_ = l - a * 0.0894841775 - b * 1.
|
|
79
|
+
const s_ = l - a * 0.0894841775 - b * 1.291485548
|
|
74
80
|
|
|
75
81
|
const lCubed = l_ * l_ * l_
|
|
76
82
|
const mCubed = m_ * m_ * m_
|
|
@@ -78,7 +84,7 @@ export function oklchToColor(l: number, c: number, h: number): Color {
|
|
|
78
84
|
|
|
79
85
|
const r = lCubed * 4.0767416621 - mCubed * 3.3077115913 + sCubed * 0.2309699292
|
|
80
86
|
const g = lCubed * -1.2684380046 + mCubed * 2.6097574011 - sCubed * 0.3413193965
|
|
81
|
-
const bOut = lCubed * -0.0041960863 - mCubed * 0.7034186147 + sCubed * 1.
|
|
87
|
+
const bOut = lCubed * -0.0041960863 - mCubed * 0.7034186147 + sCubed * 1.707614701
|
|
82
88
|
|
|
83
89
|
// Clamp to [0,1]
|
|
84
90
|
const color = new Color()
|
|
@@ -1,47 +1,52 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Theme Layer CSS
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* The
|
|
6
|
-
*
|
|
4
|
+
* Accessibility attributes are applied to <html> by the individual composables.
|
|
5
|
+
* The dark mode @custom-variant lives in core/main.css so it is defined in the
|
|
6
|
+
* same Tailwind pass as all utility generation (avoids HMR regeneration shift).
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/* --- Reduced Motion --- */
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
[data-theme-motion="reduced"] *,
|
|
11
|
+
[data-theme-motion="reduced"] *::before,
|
|
12
|
+
[data-theme-motion="reduced"] *::after {
|
|
13
13
|
animation-duration: 0.01ms !important;
|
|
14
14
|
animation-iteration-count: 1 !important;
|
|
15
15
|
transition-duration: 0.01ms !important;
|
|
16
16
|
scroll-behavior: auto !important;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
[data-theme-motion="reduced"] {
|
|
20
|
+
--duration-base: 0ms;
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
/* --- Reduced Transparency --- */
|
|
20
|
-
|
|
21
|
-
.reduce-transparency {
|
|
24
|
+
[data-theme-transparency="reduced"] {
|
|
22
25
|
--ui-bg-elevated: var(--ui-bg);
|
|
26
|
+
--opacity-glass: 1;
|
|
27
|
+
--backdrop-blur: 0px;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
[data-theme-transparency="reduced"] :where([class*='backdrop-blur']) {
|
|
26
31
|
backdrop-filter: none !important;
|
|
27
32
|
-webkit-backdrop-filter: none !important;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
[data-theme-transparency="reduced"] :where([class*='bg-default/'], [class*='bg-elevated/']) {
|
|
31
36
|
background-color: var(--ui-bg-elevated) !important;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
/* --- High Contrast --- */
|
|
35
|
-
|
|
40
|
+
[data-theme-contrast="high"] {
|
|
36
41
|
--ui-border: var(--ui-border-accented);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
[data-theme-contrast="high"] :where(button, a, [role='button']) {
|
|
40
45
|
outline-width: 2px;
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
[data-theme-contrast="high"] .text-muted,
|
|
49
|
+
[data-theme-contrast="high"] .text-dimmed {
|
|
45
50
|
opacity: 1;
|
|
46
51
|
filter: contrast(1.25);
|
|
47
52
|
}
|