kmcom-nuxt-layers 1.1.4 → 1.1.6
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/.DS_Store +0 -0
- package/layers/core/app/.DS_Store +0 -0
- package/layers/forms/app/.DS_Store +0 -0
- package/layers/layout/app/.DS_Store +0 -0
- package/layers/layout/app/assets/css/layout/grids.css +2 -6
- package/layers/layout/app/components/Layout/Grid/Item.vue +61 -36
- package/layers/motion/app/.DS_Store +0 -0
- package/layers/shader/app/.DS_Store +0 -0
- package/layers/shader/app/components/Node/Color.client.vue +51 -0
- package/layers/shader/app/components/Node/Fresnel.client.vue +53 -0
- package/layers/shader/app/components/Node/Gradient.client.vue +87 -0
- package/layers/shader/app/components/Node/Mix.client.vue +50 -0
- package/layers/shader/app/components/Node/Noise.client.vue +101 -0
- package/layers/shader/app/components/Preset/Aurora.client.vue +67 -0
- package/layers/shader/app/components/Preset/Flow.client.vue +61 -0
- package/layers/shader/app/components/Preset/GradientMesh.client.vue +61 -0
- package/layers/shader/app/components/Preset/Nebula.client.vue +61 -0
- package/layers/shader/app/components/Preset/Ocean.client.vue +61 -0
- package/layers/shader/app/components/Shader/Background.client.vue +168 -0
- package/layers/shader/app/components/Shader/Host.client.vue +149 -0
- package/layers/shader/app/components/Shader/Material.client.vue +49 -0
- package/layers/shader/app/components/Shader/Runtime.client.vue +47 -0
- package/layers/shader/app/composables/useAmbientMaterials.ts +283 -344
- package/layers/shader/app/composables/useShaderColor.ts +103 -0
- package/layers/shader/app/composables/useShaderFloat.ts +62 -0
- package/layers/shader/app/composables/useShaderGraph.ts +131 -0
- package/layers/shader/app/composables/useShaderRuntime.ts +96 -0
- package/layers/shader/app/composables/useShaderVec2.ts +99 -0
- package/layers/shader/app/shaders/common/palette.ts +1 -0
- package/layers/shader/app/utils/tsl/index.ts +2 -84
- package/layers/shader/app/utils/tsl/oklch.ts +91 -0
- package/layers/shader/app/utils/tsl/tween.ts +58 -0
- package/layers/shader/nuxt.config.ts +93 -14
- package/layers/theme/app/.DS_Store +0 -0
- package/layers/ui/app/.DS_Store +0 -0
- package/layers/ui/app/components/Typography/CodeBlock.vue +4 -1
- package/layers/ui/app/components/Typography/Headline.vue +6 -0
- package/layers/ui/app/components/Typography/QuoteBlock.vue +4 -2
- package/layers/ui/app/components/Typography/index.vue +3 -0
- package/layers/ui/app/composables/typography.ts +8 -0
- package/layers/ui/app/layouts/default.vue +12 -2
- package/layers/ui/app/types/typography.ts +22 -0
- package/package.json +70 -68
- package/layers/shader/app/components/Shader/Background.vue +0 -159
- package/layers/shader/app/components/WebGPUCanvas.client.vue +0 -245
- /package/layers/shader/app/components/Material/{AmbientAurora.vue → AmbientAurora.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{AmbientFlow.vue → AmbientFlow.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{AmbientGradientMesh.vue → AmbientGradientMesh.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{AmbientNebula.vue → AmbientNebula.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{AmbientOcean.vue → AmbientOcean.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{Fresnel.vue → Fresnel.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{Gradient.vue → Gradient.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{Image.vue → Image.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{Node.vue → Node.client.vue} +0 -0
- /package/layers/shader/app/components/Material/{Noise.vue → Noise.client.vue} +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -48,16 +48,12 @@
|
|
|
48
48
|
|
|
49
49
|
/* Tablet: 12 columns */
|
|
50
50
|
@media (width >= 48rem) {
|
|
51
|
-
:
|
|
52
|
-
--grid-cols: 12;
|
|
53
|
-
}
|
|
51
|
+
--grid-cols: 12;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
/* Desktop: 18 columns */
|
|
57
55
|
@media (width >= 80rem) {
|
|
58
|
-
:
|
|
59
|
-
--grid-cols: 18;
|
|
60
|
-
}
|
|
56
|
+
--grid-cols: 18;
|
|
61
57
|
}
|
|
62
58
|
}
|
|
63
59
|
|
|
@@ -94,17 +94,27 @@ const getDefaultValue = <T,>(value: T | ResponsiveValue<T> | undefined, defaultV
|
|
|
94
94
|
return value as T
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
const getResponsiveValue = <T,>(
|
|
98
|
+
value: T | ResponsiveValue<T> | undefined,
|
|
99
|
+
breakpoint: 'md' | 'lg',
|
|
100
|
+
): T | undefined => {
|
|
101
|
+
if (value === undefined) return undefined
|
|
102
|
+
if (typeof value === 'object' && value !== null && 'default' in value) {
|
|
103
|
+
return value[breakpoint]
|
|
104
|
+
}
|
|
105
|
+
return undefined
|
|
106
|
+
}
|
|
107
|
+
|
|
97
108
|
const style = computed(() => {
|
|
98
109
|
const styles: Record<string, string> = {}
|
|
99
110
|
|
|
100
|
-
// Grid placement - use computed merged values
|
|
101
111
|
const colStartVal = getDefaultValue(colStart.value, undefined)
|
|
102
112
|
const colSpanVal = getDefaultValue(colSpan.value, 1)
|
|
103
113
|
const rowStartVal = getDefaultValue(rowStart.value, undefined)
|
|
104
114
|
const rowSpanVal = getDefaultValue(rowSpan.value, 1)
|
|
105
115
|
|
|
106
116
|
if (bleed) {
|
|
107
|
-
// Bleed
|
|
117
|
+
// Bleed is non-responsive — keep as direct inline style
|
|
108
118
|
if (bleed === 'both') {
|
|
109
119
|
styles.gridColumn = '1 / -1'
|
|
110
120
|
} else if (bleed === 'left') {
|
|
@@ -112,19 +122,40 @@ const style = computed(() => {
|
|
|
112
122
|
} else if (bleed === 'right') {
|
|
113
123
|
styles.gridColumn = `${colStartVal ?? 'auto'} / -1`
|
|
114
124
|
}
|
|
125
|
+
styles.gridRow = `${rowStartVal ?? 'auto'} / span ${rowSpanVal}`
|
|
115
126
|
} else {
|
|
116
|
-
|
|
127
|
+
// Set CSS custom properties instead of grid-column/grid-row directly.
|
|
128
|
+
// The <style> block below reads these vars and applies them at each breakpoint,
|
|
129
|
+
// which correctly cascades without inline-style specificity conflicts.
|
|
130
|
+
styles['--_cs'] = String(colStartVal ?? 'auto')
|
|
131
|
+
styles['--_ce'] = String(colSpanVal)
|
|
132
|
+
styles['--_rs'] = String(rowStartVal ?? 'auto')
|
|
133
|
+
styles['--_re'] = String(rowSpanVal)
|
|
134
|
+
|
|
135
|
+
const mdColStart = getResponsiveValue(colStart.value, 'md')
|
|
136
|
+
const lgColStart = getResponsiveValue(colStart.value, 'lg')
|
|
137
|
+
const mdColSpan = getResponsiveValue(colSpan.value, 'md')
|
|
138
|
+
const lgColSpan = getResponsiveValue(colSpan.value, 'lg')
|
|
139
|
+
const mdRowStart = getResponsiveValue(rowStart.value, 'md')
|
|
140
|
+
const lgRowStart = getResponsiveValue(rowStart.value, 'lg')
|
|
141
|
+
const mdRowSpan = getResponsiveValue(rowSpan.value, 'md')
|
|
142
|
+
const lgRowSpan = getResponsiveValue(rowSpan.value, 'lg')
|
|
143
|
+
|
|
144
|
+
if (mdColStart !== undefined) styles['--_md-cs'] = String(mdColStart)
|
|
145
|
+
if (lgColStart !== undefined) styles['--_lg-cs'] = String(lgColStart)
|
|
146
|
+
if (mdColSpan !== undefined) styles['--_md-ce'] = String(mdColSpan)
|
|
147
|
+
if (lgColSpan !== undefined) styles['--_lg-ce'] = String(lgColSpan)
|
|
148
|
+
if (mdRowStart !== undefined) styles['--_md-rs'] = String(mdRowStart)
|
|
149
|
+
if (lgRowStart !== undefined) styles['--_lg-rs'] = String(lgRowStart)
|
|
150
|
+
if (mdRowSpan !== undefined) styles['--_md-re'] = String(mdRowSpan)
|
|
151
|
+
if (lgRowSpan !== undefined) styles['--_lg-re'] = String(lgRowSpan)
|
|
117
152
|
}
|
|
118
153
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// Content alignment - make this element a grid container to center its children
|
|
154
|
+
// Content alignment
|
|
122
155
|
if (align || justify) {
|
|
123
156
|
styles.display = 'grid'
|
|
124
157
|
styles.width = '100%'
|
|
125
158
|
styles.height = '100%'
|
|
126
|
-
// Use place-items to control how children fill the cell
|
|
127
|
-
// align controls vertical, justify controls horizontal
|
|
128
159
|
styles.placeItems = `${align ?? 'stretch'} ${justify ?? 'stretch'}`
|
|
129
160
|
}
|
|
130
161
|
|
|
@@ -135,36 +166,9 @@ const style = computed(() => {
|
|
|
135
166
|
return styles
|
|
136
167
|
})
|
|
137
168
|
|
|
138
|
-
const getResponsiveClasses = <T,>(
|
|
139
|
-
value: T | ResponsiveValue<T> | undefined,
|
|
140
|
-
classGenerator: (val: T) => string
|
|
141
|
-
): string[] => {
|
|
142
|
-
if (value === undefined) return []
|
|
143
|
-
if (typeof value === 'object' && value !== null && 'default' in value) {
|
|
144
|
-
const classes: string[] = []
|
|
145
|
-
if (value.md !== undefined) classes.push(`md:${classGenerator(value.md)}`)
|
|
146
|
-
if (value.lg !== undefined) classes.push(`lg:${classGenerator(value.lg)}`)
|
|
147
|
-
return classes
|
|
148
|
-
}
|
|
149
|
-
return []
|
|
150
|
-
}
|
|
151
|
-
|
|
152
169
|
const classes = computed(() => {
|
|
153
|
-
const classList: string[] = ['@container', '@container/item']
|
|
154
|
-
|
|
155
|
-
// Responsive column start - use merged values
|
|
156
|
-
classList.push(...getResponsiveClasses(colStart.value, (val) => `col-start-${val}`))
|
|
170
|
+
const classList: string[] = ['gi-placed', '@container', '@container/item']
|
|
157
171
|
|
|
158
|
-
// Responsive column span
|
|
159
|
-
classList.push(...getResponsiveClasses(colSpan.value, (val) => `col-span-${val}`))
|
|
160
|
-
|
|
161
|
-
// Responsive row start
|
|
162
|
-
classList.push(...getResponsiveClasses(rowStart.value, (val) => `row-start-${val}`))
|
|
163
|
-
|
|
164
|
-
// Responsive row span
|
|
165
|
-
classList.push(...getResponsiveClasses(rowSpan.value, (val) => `row-span-${val}`))
|
|
166
|
-
|
|
167
|
-
// Aspect ratio
|
|
168
172
|
if (aspect) {
|
|
169
173
|
classList.push(aspectClasses[aspect])
|
|
170
174
|
}
|
|
@@ -178,3 +182,24 @@ const classes = computed(() => {
|
|
|
178
182
|
<slot />
|
|
179
183
|
</component>
|
|
180
184
|
</template>
|
|
185
|
+
|
|
186
|
+
<style>
|
|
187
|
+
.gi-placed {
|
|
188
|
+
grid-column: var(--_cs, auto) / span var(--_ce, 1);
|
|
189
|
+
grid-row: var(--_rs, auto) / span var(--_re, 1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@media (width >= 48rem) {
|
|
193
|
+
.gi-placed {
|
|
194
|
+
grid-column: var(--_md-cs, var(--_cs, auto)) / span var(--_md-ce, var(--_ce, 1));
|
|
195
|
+
grid-row: var(--_md-rs, var(--_rs, auto)) / span var(--_md-re, var(--_re, 1));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@media (width >= 80rem) {
|
|
200
|
+
.gi-placed {
|
|
201
|
+
grid-column: var(--_lg-cs, var(--_md-cs, var(--_cs, auto))) / span var(--_lg-ce, var(--_md-ce, var(--_ce, 1)));
|
|
202
|
+
grid-row: var(--_lg-rs, var(--_md-rs, var(--_rs, auto))) / span var(--_lg-re, var(--_md-re, var(--_re, 1)));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
</style>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import { Color } from 'three'
|
|
4
|
+
import { uniform, vec3 } from 'three/tsl'
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(
|
|
7
|
+
defineProps<{
|
|
8
|
+
id?: string
|
|
9
|
+
color?: string
|
|
10
|
+
order?: number
|
|
11
|
+
blend?: 'normal' | 'add' | 'multiply' | 'screen' | 'overlay' | 'mix'
|
|
12
|
+
opacity?: number
|
|
13
|
+
}>(),
|
|
14
|
+
{
|
|
15
|
+
id: 'color',
|
|
16
|
+
color: '#ffffff',
|
|
17
|
+
order: 0,
|
|
18
|
+
blend: 'normal',
|
|
19
|
+
opacity: 1.0,
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const graph = useShaderGraphContext()
|
|
24
|
+
|
|
25
|
+
// Create uniform once
|
|
26
|
+
const colorValue = new Color(props.color)
|
|
27
|
+
const colorNode = uniform(colorValue)
|
|
28
|
+
|
|
29
|
+
// Build TSL node once (references uniform by pointer)
|
|
30
|
+
const node = vec3(colorNode)
|
|
31
|
+
|
|
32
|
+
// Register in graph
|
|
33
|
+
graph.register(props.id, node, props.order, props.blend, props.opacity)
|
|
34
|
+
|
|
35
|
+
// Watch props to update uniform value (no recompilation)
|
|
36
|
+
watch(
|
|
37
|
+
() => props.color,
|
|
38
|
+
(hex) => {
|
|
39
|
+
colorValue.set(hex)
|
|
40
|
+
colorNode.value = colorValue
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
onUnmounted(() => {
|
|
45
|
+
graph.unregister(props.id)
|
|
46
|
+
})
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<slot />
|
|
51
|
+
</template>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
cameraPosition,
|
|
5
|
+
normalView,
|
|
6
|
+
positionWorld,
|
|
7
|
+
pow,
|
|
8
|
+
sub,
|
|
9
|
+
uniform,
|
|
10
|
+
vec3,
|
|
11
|
+
} from 'three/tsl'
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(
|
|
14
|
+
defineProps<{
|
|
15
|
+
id?: string
|
|
16
|
+
power?: number
|
|
17
|
+
color?: string
|
|
18
|
+
order?: number
|
|
19
|
+
blend?: 'normal' | 'add' | 'multiply' | 'screen' | 'overlay' | 'mix'
|
|
20
|
+
opacity?: number
|
|
21
|
+
}>(),
|
|
22
|
+
{
|
|
23
|
+
id: 'fresnel',
|
|
24
|
+
power: 2.0,
|
|
25
|
+
color: '#ffffff',
|
|
26
|
+
order: 0,
|
|
27
|
+
blend: 'add',
|
|
28
|
+
opacity: 1.0,
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const graph = useShaderGraphContext()
|
|
33
|
+
|
|
34
|
+
// Create uniforms once
|
|
35
|
+
const uPower = uniform(props.power)
|
|
36
|
+
|
|
37
|
+
// Build fresnel node
|
|
38
|
+
const viewDirection = positionWorld.sub(cameraPosition).normalize()
|
|
39
|
+
const fresnelFactor = pow(sub(1.0, normalView.dot(viewDirection.negate()).abs()), uPower)
|
|
40
|
+
const node = vec3(fresnelFactor, fresnelFactor, fresnelFactor)
|
|
41
|
+
|
|
42
|
+
graph.register(props.id, node, props.order, props.blend, props.opacity)
|
|
43
|
+
|
|
44
|
+
watch(() => props.power, (v) => { uPower.value = v })
|
|
45
|
+
|
|
46
|
+
onUnmounted(() => {
|
|
47
|
+
graph.unregister(props.id)
|
|
48
|
+
})
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<template>
|
|
52
|
+
<slot />
|
|
53
|
+
</template>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import { add, mul, time, uniform, uv } from 'three/tsl'
|
|
4
|
+
import { cosinePalette } from '#layers/shader/app/shaders/common/palette'
|
|
5
|
+
|
|
6
|
+
const props = withDefaults(
|
|
7
|
+
defineProps<{
|
|
8
|
+
id?: string
|
|
9
|
+
/** Cosine palette type or 'linear' for UV-based gradient */
|
|
10
|
+
type?: 'rainbow' | 'sunset' | 'ocean' | 'fire' | 'ice' | 'neon' | 'pastel' | 'custom'
|
|
11
|
+
speed?: number
|
|
12
|
+
/** Custom brightness for cosine palette [r,g,b] */
|
|
13
|
+
brightness?: [number, number, number]
|
|
14
|
+
/** Custom contrast for cosine palette [r,g,b] */
|
|
15
|
+
contrast?: [number, number, number]
|
|
16
|
+
/** Custom frequency for cosine palette [r,g,b] */
|
|
17
|
+
frequency?: [number, number, number]
|
|
18
|
+
/** Custom phase for cosine palette [r,g,b] */
|
|
19
|
+
phase?: [number, number, number]
|
|
20
|
+
order?: number
|
|
21
|
+
blend?: 'normal' | 'add' | 'multiply' | 'screen' | 'overlay' | 'mix'
|
|
22
|
+
opacity?: number
|
|
23
|
+
}>(),
|
|
24
|
+
{
|
|
25
|
+
id: 'gradient',
|
|
26
|
+
type: 'rainbow',
|
|
27
|
+
speed: 0.1,
|
|
28
|
+
brightness: () => [0.5, 0.5, 0.5],
|
|
29
|
+
contrast: () => [0.5, 0.5, 0.5],
|
|
30
|
+
frequency: () => [1.0, 1.0, 1.0],
|
|
31
|
+
phase: () => [0.0, 0.33, 0.67],
|
|
32
|
+
order: 0,
|
|
33
|
+
blend: 'normal',
|
|
34
|
+
opacity: 1.0,
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
const graph = useShaderGraphContext()
|
|
39
|
+
|
|
40
|
+
const uSpeed = uniform(props.speed)
|
|
41
|
+
|
|
42
|
+
// Palette presets
|
|
43
|
+
const palettePresets: Record<string, [[number, number, number], [number, number, number], [number, number, number], [number, number, number]]> = {
|
|
44
|
+
rainbow: [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.0, 0.33, 0.67]],
|
|
45
|
+
sunset: [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 0.7, 0.4], [0.0, 0.15, 0.2]],
|
|
46
|
+
ocean: [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0], [0.3, 0.2, 0.2]],
|
|
47
|
+
fire: [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [1.0, 0.5, 0.0], [0.0, 0.1, 0.2]],
|
|
48
|
+
ice: [[0.5, 0.5, 0.5], [0.4, 0.4, 0.5], [0.0, 0.1, 0.2], [0.0, 0.0, 0.0]],
|
|
49
|
+
neon: [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], [2.0, 1.0, 0.0], [0.5, 0.2, 0.25]],
|
|
50
|
+
pastel: [[0.8, 0.8, 0.8], [0.2, 0.2, 0.2], [1.0, 1.0, 1.0], [0.0, 0.33, 0.67]],
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildNode() {
|
|
54
|
+
const uvCoord = uv()
|
|
55
|
+
const t = add(uvCoord.x, mul(time, uSpeed))
|
|
56
|
+
|
|
57
|
+
const preset = palettePresets[props.type]
|
|
58
|
+
if (preset) {
|
|
59
|
+
return cosinePalette(t, preset[0], preset[1], preset[2], preset[3])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Custom
|
|
63
|
+
return cosinePalette(t, props.brightness, props.contrast, props.frequency, props.phase)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let node = buildNode()
|
|
67
|
+
graph.register(props.id, node, props.order, props.blend, props.opacity)
|
|
68
|
+
|
|
69
|
+
watch(() => props.speed, (v) => { uSpeed.value = v })
|
|
70
|
+
|
|
71
|
+
// Rebuild on type or custom param changes
|
|
72
|
+
watch(
|
|
73
|
+
() => [props.type, props.brightness, props.contrast, props.frequency, props.phase] as const,
|
|
74
|
+
() => {
|
|
75
|
+
node = buildNode()
|
|
76
|
+
graph.update(props.id, node)
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
onUnmounted(() => {
|
|
81
|
+
graph.unregister(props.id)
|
|
82
|
+
})
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<slot />
|
|
87
|
+
</template>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
/**
|
|
4
|
+
* Mix node -- combines child nodes registered in a nested shader graph.
|
|
5
|
+
* Children register into this component's own sub-graph, which is then
|
|
6
|
+
* composed and registered as a single node in the parent graph.
|
|
7
|
+
*/
|
|
8
|
+
import { vec3 } from 'three/tsl'
|
|
9
|
+
|
|
10
|
+
const props = withDefaults(
|
|
11
|
+
defineProps<{
|
|
12
|
+
id?: string
|
|
13
|
+
order?: number
|
|
14
|
+
blend?: 'normal' | 'add' | 'multiply' | 'screen' | 'overlay' | 'mix'
|
|
15
|
+
opacity?: number
|
|
16
|
+
}>(),
|
|
17
|
+
{
|
|
18
|
+
id: 'mix',
|
|
19
|
+
order: 0,
|
|
20
|
+
blend: 'normal',
|
|
21
|
+
opacity: 1.0,
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
const parentGraph = useShaderGraphContext()
|
|
26
|
+
|
|
27
|
+
// Create a sub-graph for children
|
|
28
|
+
const subGraph = useShaderGraph()
|
|
29
|
+
|
|
30
|
+
// Watch sub-graph and register its composite into parent
|
|
31
|
+
watch(
|
|
32
|
+
subGraph.version,
|
|
33
|
+
() => {
|
|
34
|
+
const node = subGraph.finalNode.value || vec3(0, 0, 0)
|
|
35
|
+
if (parentGraph) {
|
|
36
|
+
// Re-register with updated composite node
|
|
37
|
+
parentGraph.register(props.id, node, props.order, props.blend, props.opacity)
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{ immediate: true }
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
onUnmounted(() => {
|
|
44
|
+
parentGraph.unregister(props.id)
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<slot />
|
|
50
|
+
</template>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import { add, mul, time, uniform, uv, vec2, vec3 } from 'three/tsl'
|
|
4
|
+
import {
|
|
5
|
+
simplexNoise2D,
|
|
6
|
+
fbm2D,
|
|
7
|
+
ridgedFbm2d,
|
|
8
|
+
voronoi2D,
|
|
9
|
+
fbm3dSimplex,
|
|
10
|
+
} from '#layers/shader/app/shaders/common/noise'
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(
|
|
13
|
+
defineProps<{
|
|
14
|
+
id?: string
|
|
15
|
+
type?: 'simplex' | 'fbm' | 'voronoi' | 'ridged' | 'fbm3d'
|
|
16
|
+
scale?: number
|
|
17
|
+
speed?: number
|
|
18
|
+
octaves?: number
|
|
19
|
+
order?: number
|
|
20
|
+
blend?: 'normal' | 'add' | 'multiply' | 'screen' | 'overlay' | 'mix'
|
|
21
|
+
opacity?: number
|
|
22
|
+
}>(),
|
|
23
|
+
{
|
|
24
|
+
id: 'noise',
|
|
25
|
+
type: 'simplex',
|
|
26
|
+
scale: 3.0,
|
|
27
|
+
speed: 0.2,
|
|
28
|
+
octaves: 4,
|
|
29
|
+
order: 0,
|
|
30
|
+
blend: 'normal',
|
|
31
|
+
opacity: 1.0,
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const graph = useShaderGraphContext()
|
|
36
|
+
|
|
37
|
+
// Create uniforms once
|
|
38
|
+
const uScale = uniform(props.scale)
|
|
39
|
+
const uSpeed = uniform(props.speed)
|
|
40
|
+
|
|
41
|
+
// Build TSL node
|
|
42
|
+
function buildNode() {
|
|
43
|
+
const uvCoord = uv()
|
|
44
|
+
const t = mul(time, uSpeed)
|
|
45
|
+
const scaledUV = mul(uvCoord, uScale)
|
|
46
|
+
const animatedUV = add(scaledUV, vec2(t, mul(t, 0.3)))
|
|
47
|
+
|
|
48
|
+
let noiseValue
|
|
49
|
+
|
|
50
|
+
switch (props.type) {
|
|
51
|
+
case 'fbm':
|
|
52
|
+
noiseValue = fbm2D(animatedUV, { octaves: props.octaves, frequency: 1.0 })
|
|
53
|
+
.mul(0.5)
|
|
54
|
+
.add(0.5)
|
|
55
|
+
break
|
|
56
|
+
case 'voronoi': {
|
|
57
|
+
const { distance } = voronoi2D(animatedUV, 1.0)
|
|
58
|
+
noiseValue = distance
|
|
59
|
+
break
|
|
60
|
+
}
|
|
61
|
+
case 'ridged':
|
|
62
|
+
noiseValue = ridgedFbm2d(animatedUV, { octaves: props.octaves, frequency: 1.0 })
|
|
63
|
+
break
|
|
64
|
+
case 'fbm3d':
|
|
65
|
+
noiseValue = fbm3dSimplex(vec3(scaledUV, t), { octaves: props.octaves })
|
|
66
|
+
.mul(0.5)
|
|
67
|
+
.add(0.5)
|
|
68
|
+
break
|
|
69
|
+
case 'simplex':
|
|
70
|
+
default:
|
|
71
|
+
noiseValue = simplexNoise2D(animatedUV).mul(0.5).add(0.5)
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return vec3(noiseValue, noiseValue, noiseValue)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const node = buildNode()
|
|
79
|
+
graph.register(props.id, node, props.order, props.blend, props.opacity)
|
|
80
|
+
|
|
81
|
+
// Watch uniform-driven props (no recompilation)
|
|
82
|
+
watch(() => props.scale, (v) => { uScale.value = v })
|
|
83
|
+
watch(() => props.speed, (v) => { uSpeed.value = v })
|
|
84
|
+
|
|
85
|
+
// Watch topology-changing props (requires graph update)
|
|
86
|
+
watch(
|
|
87
|
+
() => [props.type, props.octaves] as const,
|
|
88
|
+
() => {
|
|
89
|
+
const newNode = buildNode()
|
|
90
|
+
graph.update(props.id, newNode)
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
onUnmounted(() => {
|
|
95
|
+
graph.unregister(props.id)
|
|
96
|
+
})
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<template>
|
|
100
|
+
<slot />
|
|
101
|
+
</template>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import { uniform } from 'three/tsl'
|
|
4
|
+
import {
|
|
5
|
+
createAmbientUniforms,
|
|
6
|
+
createAuroraColorNode,
|
|
7
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(
|
|
10
|
+
defineProps<{
|
|
11
|
+
speed?: number
|
|
12
|
+
intensity?: number
|
|
13
|
+
mouseInteraction?: boolean
|
|
14
|
+
}>(),
|
|
15
|
+
{
|
|
16
|
+
speed: 1.0,
|
|
17
|
+
intensity: 1.0,
|
|
18
|
+
mouseInteraction: true,
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const emit = defineEmits<{
|
|
23
|
+
node: [colorNode: any]
|
|
24
|
+
}>()
|
|
25
|
+
|
|
26
|
+
// Create uniforms once
|
|
27
|
+
const uniforms = createAmbientUniforms({
|
|
28
|
+
speed: props.speed,
|
|
29
|
+
intensity: props.intensity,
|
|
30
|
+
mouseInteraction: props.mouseInteraction,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Build the TSL color node (references uniforms by pointer)
|
|
34
|
+
const colorNode = createAuroraColorNode(uniforms)
|
|
35
|
+
|
|
36
|
+
// Wire mouse from runtime if available
|
|
37
|
+
try {
|
|
38
|
+
const runtime = useShaderRuntimeContext()
|
|
39
|
+
watch(
|
|
40
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
41
|
+
([mx, my]) => {
|
|
42
|
+
uniforms.mouseX.value = mx
|
|
43
|
+
uniforms.mouseY.value = my
|
|
44
|
+
},
|
|
45
|
+
{ immediate: true }
|
|
46
|
+
)
|
|
47
|
+
} catch {
|
|
48
|
+
// No runtime -- mouse can be set externally
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Watch props to update uniforms (no recompilation)
|
|
52
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
53
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
54
|
+
watch(
|
|
55
|
+
() => props.mouseInteraction,
|
|
56
|
+
(v) => { uniforms.mouseStrength.value = v ? 0.5 : 0 }
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
// Emit the node for parent (ShaderHost) to consume
|
|
60
|
+
emit('node', colorNode)
|
|
61
|
+
|
|
62
|
+
defineExpose({ uniforms, colorNode })
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<slot />
|
|
67
|
+
</template>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// @ts-nocheck - TSL types
|
|
3
|
+
import {
|
|
4
|
+
createAmbientUniforms,
|
|
5
|
+
createFlowColorNode,
|
|
6
|
+
} from '#layers/shader/app/composables/useAmbientMaterials'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
speed?: number
|
|
11
|
+
intensity?: number
|
|
12
|
+
mouseInteraction?: boolean
|
|
13
|
+
}>(),
|
|
14
|
+
{
|
|
15
|
+
speed: 1.0,
|
|
16
|
+
intensity: 1.0,
|
|
17
|
+
mouseInteraction: true,
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const emit = defineEmits<{
|
|
22
|
+
node: [colorNode: any]
|
|
23
|
+
}>()
|
|
24
|
+
|
|
25
|
+
const uniforms = createAmbientUniforms({
|
|
26
|
+
speed: props.speed,
|
|
27
|
+
intensity: props.intensity,
|
|
28
|
+
mouseInteraction: props.mouseInteraction,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const colorNode = createFlowColorNode(uniforms)
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const runtime = useShaderRuntimeContext()
|
|
35
|
+
watch(
|
|
36
|
+
() => [runtime.mouse.mouseX.value, runtime.mouse.mouseY.value],
|
|
37
|
+
([mx, my]) => {
|
|
38
|
+
uniforms.mouseX.value = mx
|
|
39
|
+
uniforms.mouseY.value = my
|
|
40
|
+
},
|
|
41
|
+
{ immediate: true }
|
|
42
|
+
)
|
|
43
|
+
} catch {
|
|
44
|
+
// No runtime
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
watch(() => props.speed, (v) => { uniforms.speed.value = v })
|
|
48
|
+
watch(() => props.intensity, (v) => { uniforms.intensity.value = v })
|
|
49
|
+
watch(
|
|
50
|
+
() => props.mouseInteraction,
|
|
51
|
+
(v) => { uniforms.mouseStrength.value = v ? 0.5 : 0 }
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
emit('node', colorNode)
|
|
55
|
+
|
|
56
|
+
defineExpose({ uniforms, colorNode })
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<slot />
|
|
61
|
+
</template>
|