kmcom-nuxt-layers 2.2.11 → 2.2.13
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/docs/FALLOW-COMPLEXITY-DUPLICATION-AUDIT.md +65 -0
- package/docs/FEEDS.md +1 -2
- package/docs/IMPROVE-AUDIT-README.md +30 -0
- package/docs/IMPROVE-AUDIT-RESULTS.md +52 -0
- package/docs/IMPROVE-DEEP-AUDIT-RESULTS.md +81 -0
- package/docs/fallow-refactor/apps-debug.md +27 -0
- package/docs/fallow-refactor/apps-playground.md +46 -0
- package/docs/fallow-refactor/apps-visual-identity.md +41 -0
- package/docs/fallow-refactor/layers-animations.md +34 -0
- package/docs/fallow-refactor/layers-canvas.md +32 -0
- package/docs/fallow-refactor/layers-content.md +33 -0
- package/docs/fallow-refactor/layers-core.md +39 -0
- package/docs/fallow-refactor/layers-feeds.md +39 -0
- package/docs/fallow-refactor/layers-forms.md +30 -0
- package/docs/fallow-refactor/layers-layout.md +42 -0
- package/docs/fallow-refactor/layers-mailer.md +32 -0
- package/docs/fallow-refactor/layers-motion.md +27 -0
- package/docs/fallow-refactor/layers-navigation.md +31 -0
- package/docs/fallow-refactor/layers-page-transitions.md +30 -0
- package/docs/fallow-refactor/layers-routing.md +33 -0
- package/docs/fallow-refactor/layers-scripts.md +35 -0
- package/docs/fallow-refactor/layers-scroll.md +38 -0
- package/docs/fallow-refactor/layers-seo.md +32 -0
- package/docs/fallow-refactor/layers-shader.md +53 -0
- package/docs/fallow-refactor/layers-theme.md +33 -0
- package/docs/fallow-refactor/layers-transitions.md +27 -0
- package/docs/fallow-refactor/layers-typography.md +29 -0
- package/docs/fallow-refactor/layers-ui.md +27 -0
- package/docs/fallow-refactor/layers-visual.md +34 -0
- package/layers/animations/app/composables/useMagneticElement.ts +11 -9
- package/layers/animations/app/composables/useTiltEffect.ts +11 -9
- package/layers/animations/app/utils/pointerMotion.ts +31 -0
- package/layers/canvas/app/components/ShaderCanvas.vue +2 -2
- package/layers/content/app/composables/useCollectionItems.ts +28 -0
- package/layers/content/app/composables/useGalleryItems.ts +8 -14
- package/layers/content/app/composables/usePortfolioItems.ts +10 -18
- package/layers/core/app/composables/useBrowser.ts +9 -82
- package/layers/core/app/composables/useFeatures.ts +3 -27
- package/layers/core/app/plugins/init.ts +157 -135
- package/layers/core/app/utils/browserInfo.ts +115 -0
- package/layers/core/app/utils/featureClasses.ts +40 -0
- package/layers/core/app/utils/helpers.test.ts +51 -0
- package/layers/feeds/app/app.config.ts +4 -2
- package/layers/feeds/app/components/Feeds/Index.vue +229 -0
- package/layers/feeds/app/components/Feeds/RouteCard.vue +75 -0
- package/layers/feeds/app/plugins/feed-head.ts +27 -49
- package/layers/feeds/app/utils/feed-catalog.ts +184 -0
- package/layers/feeds/nuxt.config.ts +0 -1
- package/layers/feeds/package.json +1 -0
- package/layers/feeds/server/utils/content-adapter.test.ts +68 -0
- package/layers/feeds/server/utils/content-adapter.ts +2 -22
- package/layers/feeds/server/utils/feed-author.ts +32 -0
- package/layers/feeds/server/utils/feed-config.ts +88 -0
- package/layers/feeds/server/utils/feed-service.ts +11 -30
- package/layers/feeds/server/utils/feed-xml.ts +26 -0
- package/layers/feeds/server/utils/formats/rss.ts +10 -15
- package/layers/feeds/server/utils/formats.test.ts +71 -0
- package/layers/forms/app/components/Form/Field.vue +42 -30
- package/layers/forms/app/utils/fieldProps.ts +65 -0
- package/layers/layout/app/components/Layout/Grid/Item.vue +29 -146
- package/layers/layout/app/utils/gridPlacementStyle.ts +195 -0
- package/layers/mailer/app/types/mailer.ts +7 -25
- package/layers/mailer/server/utils/email.ts +28 -13
- package/layers/mailer/server/utils/hooks.ts +1 -20
- package/layers/navigation/app/composables/useSite.ts +2 -9
- package/layers/navigation/app/utils/site.ts +26 -0
- package/layers/routing/app/utils/resolveRoute.test.ts +47 -0
- package/layers/routing/app/utils/resolveRoute.ts +19 -10
- package/layers/scripts/app/composables/useAnalytics.ts +8 -41
- package/layers/scripts/app/composables/useGtm.ts +6 -13
- package/layers/scripts/app/utils/scriptClients.ts +70 -0
- package/layers/scroll/app/composables/useSmoothScroll.ts +9 -43
- package/layers/scroll/app/utils/scroll.ts +103 -0
- package/layers/seo/app/composables/useSeoConfig.ts +3 -9
- package/layers/seo/app/utils/seoConfig.ts +38 -0
- package/layers/shader/app/components/Material/AmbientAurora.client.vue +11 -33
- package/layers/shader/app/components/Material/AmbientFlow.client.vue +10 -37
- package/layers/shader/app/components/Material/AmbientGradientMesh.client.vue +10 -37
- package/layers/shader/app/components/Material/AmbientNebula.client.vue +12 -37
- package/layers/shader/app/components/Material/AmbientOcean.client.vue +9 -33
- package/layers/shader/app/components/Material/Gradient.client.vue +25 -46
- package/layers/shader/app/components/Material/Image.client.vue +10 -55
- package/layers/shader/app/components/Material/Node.client.vue +18 -5
- package/layers/shader/app/components/Material/Noise.client.vue +9 -43
- package/layers/shader/app/components/Preset/ThemeBubble.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeFlow.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeGradient.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeLavaLamp.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemePlasma.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeWave.client.vue +2 -1
- package/layers/shader/app/components/Shader/Background.client.vue +44 -24
- package/layers/shader/app/composables/useAmbientMaterials.ts +5 -1
- package/layers/shader/app/composables/useShader.ts +38 -23
- package/layers/shader/app/composables/useShaderGraph.ts +11 -6
- package/layers/shader/app/composables/useShaderMixBlend.ts +4 -4
- package/layers/shader/app/composables/useShaderRuntime.ts +0 -1
- package/layers/shader/app/composables/useShaderVec2.ts +2 -4
- package/layers/shader/app/composables/useThemePreset.ts +34 -8
- package/layers/shader/app/composables/useUniformWatchers.ts +15 -0
- package/layers/shader/app/composables/useUniforms.ts +0 -1
- package/layers/shader/app/shaders/common/blend.ts +4 -4
- package/layers/shader/app/shaders/common/effects.ts +38 -21
- package/layers/shader/app/shaders/common/grain.ts +46 -49
- package/layers/shader/app/shaders/common/lighting.ts +17 -15
- package/layers/shader/app/shaders/common/math.ts +2 -4
- package/layers/shader/app/shaders/common/nodes.ts +17 -0
- package/layers/shader/app/shaders/common/palette.ts +21 -11
- package/layers/shader/app/shaders/common/patterns.ts +25 -14
- package/layers/shader/app/shaders/common/shapes.ts +97 -88
- package/layers/shader/app/shaders/common/uv.ts +33 -34
- package/layers/shader/app/shaders/createMaterial.ts +92 -78
- package/layers/shader/app/shaders/layers/paperShading.ts +22 -10
- package/layers/shader/app/shaders/layers/shaderGradient.ts +46 -21
- package/layers/shader/app/utils/tsl/tween.ts +2 -4
- package/layers/shader/package.json +5 -1
- package/layers/theme/app/components/ThemePicker/Menu.vue +3 -25
- package/layers/theme/app/composables/useThemePreferenceModels.ts +39 -0
- package/layers/theme/server/plugins/theme-fouc.ts +1 -92
- package/layers/theme/server/utils/accent-css.ts +75 -0
- package/layers/typography/app/composables/typography.ts +3 -7
- package/layers/visual/app/composables/accent.ts +2 -9
- package/layers/visual/app/composables/gradient.ts +33 -46
- package/layers/visual/app/composables/picture.ts +2 -79
- package/layers/visual/app/utils/colorTokens.ts +23 -0
- package/layers/visual/app/utils/gradientStyle.ts +41 -0
- package/layers/visual/app/utils/responsiveSizes.ts +49 -0
- package/package.json +17 -5
- package/layers/feeds/server/routes/feed/discovery.get.ts +0 -29
|
@@ -13,7 +13,10 @@ export type ShaderGraphEntry = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export type ShaderGraph = {
|
|
16
|
-
register: (
|
|
16
|
+
register: (
|
|
17
|
+
id: string,
|
|
18
|
+
...args: [node: TSLNode, order?: number, blend?: BlendMode, opacity?: number]
|
|
19
|
+
) => void
|
|
17
20
|
unregister: (id: string) => void
|
|
18
21
|
update: (id: string, node: TSLNode) => void
|
|
19
22
|
finalNode: ComputedRef<TSLNode | null>
|
|
@@ -33,11 +36,9 @@ export function useShaderGraph(): ShaderGraph {
|
|
|
33
36
|
|
|
34
37
|
function register(
|
|
35
38
|
id: string,
|
|
36
|
-
node: TSLNode,
|
|
37
|
-
order = 0,
|
|
38
|
-
blend: BlendMode = 'normal',
|
|
39
|
-
opacity = 1.0
|
|
39
|
+
...args: [node: TSLNode, order?: number, blend?: BlendMode, opacity?: number]
|
|
40
40
|
) {
|
|
41
|
+
const [node, order = 0, blend = 'normal', opacity = 1.0] = args
|
|
41
42
|
entries.set(id, { node, order, blend, opacity })
|
|
42
43
|
version.value++
|
|
43
44
|
}
|
|
@@ -99,7 +100,11 @@ export function useShaderGraphContext(): ShaderGraph {
|
|
|
99
100
|
return graph
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
function applyBlend(
|
|
103
|
+
function applyBlend(
|
|
104
|
+
base: TSLNode,
|
|
105
|
+
...args: [layer: TSLNode, mode: BlendMode, opacity?: number]
|
|
106
|
+
): TSLNode {
|
|
107
|
+
const [layer, mode, opacity = 1] = args
|
|
103
108
|
let blended: TSLNode
|
|
104
109
|
|
|
105
110
|
switch (mode) {
|
|
@@ -5,10 +5,9 @@ import type { TSLNode } from '../types/tsl'
|
|
|
5
5
|
|
|
6
6
|
export function useShaderMixBlend(
|
|
7
7
|
blendFn: (base: TSLNode, blend: TSLNode) => TSLNode,
|
|
8
|
-
colorGetter: () => string,
|
|
9
|
-
opacityGetter: () => number,
|
|
10
|
-
order: number = 0
|
|
8
|
+
...args: [colorGetter: () => string, opacityGetter: () => number, order?: number]
|
|
11
9
|
) {
|
|
10
|
+
const [colorGetter, opacityGetter, order = 0] = args
|
|
12
11
|
const colorNode = uniform(new Color(colorGetter()))
|
|
13
12
|
const opacityNode = uniform(opacityGetter())
|
|
14
13
|
|
|
@@ -20,7 +19,8 @@ export function useShaderMixBlend(
|
|
|
20
19
|
})
|
|
21
20
|
|
|
22
21
|
useShaderStage(
|
|
23
|
-
(prev) =>
|
|
22
|
+
(prev) =>
|
|
23
|
+
vec4(mix(prev.xyz, blendFn(prev.xyz, colorNode as unknown as TSLNode), opacityNode), prev.w),
|
|
24
24
|
order
|
|
25
25
|
)
|
|
26
26
|
}
|
|
@@ -28,11 +28,9 @@ export function useShaderVec2(initialX = 0, initialY = 0) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function tweenTo(
|
|
31
|
-
targetX: number,
|
|
32
|
-
targetY: number,
|
|
33
|
-
duration: number,
|
|
34
|
-
easing?: (t: number) => number
|
|
31
|
+
...args: [targetX: number, targetY: number, duration: number, easing?: (t: number) => number]
|
|
35
32
|
): TweenHandle {
|
|
33
|
+
const [targetX, targetY, duration, easing] = args
|
|
36
34
|
activeTween?.cancel()
|
|
37
35
|
|
|
38
36
|
const startX = vector.x
|
|
@@ -41,10 +41,22 @@ export function useThemePreset(
|
|
|
41
41
|
color4: c4.node,
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
watch(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
watch(
|
|
45
|
+
() => props.color1,
|
|
46
|
+
(hex) => c1.tweenTo(hex, 0.8)
|
|
47
|
+
)
|
|
48
|
+
watch(
|
|
49
|
+
() => props.color2,
|
|
50
|
+
(hex) => c2.tweenTo(hex, 0.8)
|
|
51
|
+
)
|
|
52
|
+
watch(
|
|
53
|
+
() => props.color3,
|
|
54
|
+
(hex) => c3.tweenTo(hex, 0.8)
|
|
55
|
+
)
|
|
56
|
+
watch(
|
|
57
|
+
() => props.color4,
|
|
58
|
+
(hex) => c4.tweenTo(hex, 0.8)
|
|
59
|
+
)
|
|
48
60
|
|
|
49
61
|
try {
|
|
50
62
|
const runtime = useShaderRuntimeContext()
|
|
@@ -60,15 +72,29 @@ export function useThemePreset(
|
|
|
60
72
|
// No runtime context
|
|
61
73
|
}
|
|
62
74
|
|
|
63
|
-
watch(
|
|
64
|
-
|
|
75
|
+
watch(
|
|
76
|
+
() => props.speed,
|
|
77
|
+
(v) => {
|
|
78
|
+
uniforms.speed.value = v
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
watch(
|
|
82
|
+
() => props.intensity,
|
|
83
|
+
(v) => {
|
|
84
|
+
uniforms.intensity.value = v
|
|
85
|
+
}
|
|
86
|
+
)
|
|
65
87
|
watch(
|
|
66
88
|
() => props.mouseInteraction,
|
|
67
|
-
(v) => {
|
|
89
|
+
(v) => {
|
|
90
|
+
uniforms.mouseStrength.value = v ? props.mouseStrength : 0
|
|
91
|
+
}
|
|
68
92
|
)
|
|
69
93
|
watch(
|
|
70
94
|
() => props.mouseStrength,
|
|
71
|
-
(v) => {
|
|
95
|
+
(v) => {
|
|
96
|
+
if (props.mouseInteraction) uniforms.mouseStrength.value = v
|
|
97
|
+
}
|
|
72
98
|
)
|
|
73
99
|
|
|
74
100
|
return { uniforms, colorNode }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { watch } from 'vue'
|
|
2
|
+
|
|
3
|
+
type WritableUniform<T> = {
|
|
4
|
+
value: T
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function watchUniformProp<T, U = T>(
|
|
8
|
+
source: () => T,
|
|
9
|
+
target: WritableUniform<U>,
|
|
10
|
+
transform?: (value: T) => U
|
|
11
|
+
) {
|
|
12
|
+
watch(source, (value) => {
|
|
13
|
+
target.value = transform ? transform(value) : (value as unknown as U)
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { abs, clamp, float, max, min, mix, step, vec3 } from 'three/tsl'
|
|
6
6
|
|
|
7
7
|
import type { TSLNode } from '../types'
|
|
8
|
+
import { toScalarNode } from './nodes'
|
|
8
9
|
|
|
9
10
|
// ============================================
|
|
10
11
|
// Basic Blending
|
|
@@ -168,11 +169,10 @@ export function blendPinLight(base: TSLNode, blend: TSLNode): TSLNode {
|
|
|
168
169
|
*/
|
|
169
170
|
export function blendWithOpacity(
|
|
170
171
|
base: TSLNode,
|
|
171
|
-
blend: TSLNode,
|
|
172
|
-
blendFn: (a: TSLNode, b: TSLNode) => TSLNode,
|
|
173
|
-
opacity: TSLNode | number = 1
|
|
172
|
+
...args: [blend: TSLNode, blendFn: (a: TSLNode, b: TSLNode) => TSLNode, opacity?: TSLNode | number]
|
|
174
173
|
): TSLNode {
|
|
175
|
-
const
|
|
174
|
+
const [blend, blendFn, opacity = 1] = args
|
|
175
|
+
const op = toScalarNode(opacity)
|
|
176
176
|
const blended = blendFn(base, blend)
|
|
177
177
|
return mix(base, blended, op)
|
|
178
178
|
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from 'three/tsl'
|
|
18
18
|
|
|
19
19
|
import type { TSLNode } from '../types'
|
|
20
|
+
import { toScalarNode, toVec2Node } from './nodes'
|
|
20
21
|
|
|
21
22
|
// ============================================
|
|
22
23
|
// LED Effect
|
|
@@ -29,6 +30,13 @@ export type LEDEffectOptions = {
|
|
|
29
30
|
edge?: TSLNode | number
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
const DEFAULT_LED_EFFECT_OPTIONS = {
|
|
34
|
+
scalar: 100,
|
|
35
|
+
zoom: 2,
|
|
36
|
+
exponent: 1.2,
|
|
37
|
+
edge: 0.1,
|
|
38
|
+
} as const
|
|
39
|
+
|
|
32
40
|
/**
|
|
33
41
|
* LED screen effect for post-processing
|
|
34
42
|
* Creates a grid of circular LED dots over the input texture
|
|
@@ -41,12 +49,15 @@ export function ledEffect(
|
|
|
41
49
|
inputUV: () => TSLNode = uv,
|
|
42
50
|
options: LEDEffectOptions = {}
|
|
43
51
|
): TSLNode {
|
|
44
|
-
const { scalar
|
|
52
|
+
const { scalar, zoom, exponent, edge } = {
|
|
53
|
+
...DEFAULT_LED_EFFECT_OPTIONS,
|
|
54
|
+
...options,
|
|
55
|
+
}
|
|
45
56
|
|
|
46
|
-
const _scalar =
|
|
47
|
-
const _zoom =
|
|
48
|
-
const _exponent =
|
|
49
|
-
const _edge =
|
|
57
|
+
const _scalar = toScalarNode(scalar)
|
|
58
|
+
const _zoom = toScalarNode(zoom)
|
|
59
|
+
const _exponent = toScalarNode(exponent)
|
|
60
|
+
const _edge = toScalarNode(edge)
|
|
50
61
|
|
|
51
62
|
const _uv = inputUV().toVar()
|
|
52
63
|
|
|
@@ -168,6 +179,13 @@ export type BulgeEffectOptions = {
|
|
|
168
179
|
center?: TSLNode | [number, number]
|
|
169
180
|
}
|
|
170
181
|
|
|
182
|
+
const DEFAULT_BULGE_EFFECT_OPTIONS = {
|
|
183
|
+
strength: 0.5,
|
|
184
|
+
radius: 0.5,
|
|
185
|
+
power: 1,
|
|
186
|
+
center: [0.5, 0.5] as [number, number],
|
|
187
|
+
} as const
|
|
188
|
+
|
|
171
189
|
/**
|
|
172
190
|
* Bulge/pinch distortion effect for post-processing
|
|
173
191
|
* @param input - Input texture
|
|
@@ -179,12 +197,12 @@ export function bulgeEffect(
|
|
|
179
197
|
inputUV: () => TSLNode = uv,
|
|
180
198
|
options: BulgeEffectOptions = {}
|
|
181
199
|
): TSLNode {
|
|
182
|
-
const { strength
|
|
200
|
+
const { strength, radius, power, center } = { ...DEFAULT_BULGE_EFFECT_OPTIONS, ...options }
|
|
183
201
|
|
|
184
|
-
const _strength =
|
|
185
|
-
const _radius =
|
|
186
|
-
const _power =
|
|
187
|
-
const _center =
|
|
202
|
+
const _strength = toScalarNode(strength)
|
|
203
|
+
const _radius = toScalarNode(radius)
|
|
204
|
+
const _power = toScalarNode(power)
|
|
205
|
+
const _center = toVec2Node(center)
|
|
188
206
|
|
|
189
207
|
const _uv = inputUV().toVar()
|
|
190
208
|
const offset = _uv.sub(_center).toVar()
|
|
@@ -226,24 +244,23 @@ export function waveDistortionEffect(
|
|
|
226
244
|
options: WaveDistortionOptions = {}
|
|
227
245
|
): TSLNode {
|
|
228
246
|
const { frequency = 10, amplitude = 0.02, time = 0, direction = 'both' } = options
|
|
247
|
+
type WaveDirection = NonNullable<WaveDistortionOptions['direction']>
|
|
229
248
|
|
|
230
|
-
const _freq =
|
|
231
|
-
const _amp =
|
|
232
|
-
const _time =
|
|
249
|
+
const _freq = toScalarNode(frequency)
|
|
250
|
+
const _amp = toScalarNode(amplitude)
|
|
251
|
+
const _time = toScalarNode(time)
|
|
233
252
|
|
|
234
253
|
const _uv = inputUV().toVar()
|
|
235
254
|
|
|
236
255
|
const _eX = _uv.y.mul(_freq).add(_time).sin().mul(_amp)
|
|
237
256
|
const _eY = _uv.x.mul(_freq).add(_time.mul(1.3)).sin().mul(_amp)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
distortedUV = vec2(_uv.x, _uv.y.add(_uv.x.mul(_freq).add(_time).sin().mul(_amp)))
|
|
244
|
-
}
|
|
257
|
+
const distortedUVMap = {
|
|
258
|
+
both: vec2(_uv.x.add(_eX), _uv.y.add(_eY)),
|
|
259
|
+
x: vec2(_uv.x.add(_eX), _uv.y),
|
|
260
|
+
y: vec2(_uv.x, _uv.y.add(_uv.x.mul(_freq).add(_time).sin().mul(_amp))),
|
|
261
|
+
} satisfies Record<WaveDirection, TSLNode>
|
|
245
262
|
|
|
246
|
-
return input.sample(
|
|
263
|
+
return input.sample(distortedUVMap[direction])
|
|
247
264
|
}
|
|
248
265
|
|
|
249
266
|
// ============================================
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { clamp, dot, float, floor, fract, mix, sin, smoothstep, vec2, vec3 } from 'three/tsl'
|
|
6
6
|
|
|
7
7
|
import type { TSLNode } from '../types'
|
|
8
|
+
import { toScalarNode } from './nodes'
|
|
8
9
|
|
|
9
10
|
// ============================================
|
|
10
11
|
// Basic Grain
|
|
@@ -31,11 +32,11 @@ export function grain(
|
|
|
31
32
|
export function animatedGrain(
|
|
32
33
|
uv: TSLNode,
|
|
33
34
|
time: TSLNode,
|
|
34
|
-
|
|
35
|
-
speed: TSLNode | number = 1
|
|
35
|
+
...args: [intensity?: TSLNode | number, speed?: TSLNode | number]
|
|
36
36
|
): TSLNode {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
37
|
+
const [intensity = 0.1, speed = 1] = args
|
|
38
|
+
const int = toScalarNode(intensity)
|
|
39
|
+
const spd = toScalarNode(speed)
|
|
39
40
|
|
|
40
41
|
// Use time as seed for animation
|
|
41
42
|
const seed = floor(time.mul(spd).mul(24)) // 24 fps grain
|
|
@@ -93,11 +94,11 @@ export function bayer4x4(uv: TSLNode, scale: TSLNode | number = 1): TSLNode {
|
|
|
93
94
|
export function ditherColor(
|
|
94
95
|
color: TSLNode,
|
|
95
96
|
uv: TSLNode,
|
|
96
|
-
|
|
97
|
-
strength: TSLNode | number = 1
|
|
97
|
+
...args: [levels?: TSLNode | number, strength?: TSLNode | number]
|
|
98
98
|
): TSLNode {
|
|
99
|
-
const
|
|
100
|
-
const
|
|
99
|
+
const [levels = 16, strength = 1] = args
|
|
100
|
+
const lvl = toScalarNode(levels)
|
|
101
|
+
const str = toScalarNode(strength)
|
|
101
102
|
|
|
102
103
|
const threshold = bayer4x4(uv, 4).mul(str).div(lvl)
|
|
103
104
|
const dithered = floor(color.mul(lvl).add(threshold)).div(lvl)
|
|
@@ -114,13 +115,12 @@ export function ditherColor(
|
|
|
114
115
|
*/
|
|
115
116
|
export function scanlines(
|
|
116
117
|
uv: TSLNode,
|
|
117
|
-
|
|
118
|
-
intensity: TSLNode | number = 0.25,
|
|
119
|
-
offset: TSLNode | number = 0
|
|
118
|
+
...args: [density?: TSLNode | number, intensity?: TSLNode | number, offset?: TSLNode | number]
|
|
120
119
|
): TSLNode {
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
120
|
+
const [density = 400, intensity = 0.25, offset = 0] = args
|
|
121
|
+
const d = toScalarNode(density)
|
|
122
|
+
const int = toScalarNode(intensity)
|
|
123
|
+
const off = toScalarNode(offset)
|
|
124
124
|
|
|
125
125
|
const line = sin(uv.y.add(off).mul(d).mul(Math.PI)).mul(0.5).add(0.5)
|
|
126
126
|
return float(1).sub(line.mul(int))
|
|
@@ -131,13 +131,12 @@ export function scanlines(
|
|
|
131
131
|
*/
|
|
132
132
|
export function interlace(
|
|
133
133
|
uv: TSLNode,
|
|
134
|
-
|
|
135
|
-
intensity: TSLNode | number = 0.5,
|
|
136
|
-
frame: TSLNode | number = 0
|
|
134
|
+
...args: [density?: TSLNode | number, intensity?: TSLNode | number, frame?: TSLNode | number]
|
|
137
135
|
): TSLNode {
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const
|
|
136
|
+
const [density = 400, intensity = 0.5, frame = 0] = args
|
|
137
|
+
const d = toScalarNode(density)
|
|
138
|
+
const int = toScalarNode(intensity)
|
|
139
|
+
const f = toScalarNode(frame)
|
|
141
140
|
|
|
142
141
|
const line = floor(uv.y.mul(d)).add(f).mod(2)
|
|
143
142
|
return float(1).sub(line.mul(int))
|
|
@@ -152,13 +151,12 @@ export function interlace(
|
|
|
152
151
|
*/
|
|
153
152
|
export function vignette(
|
|
154
153
|
uv: TSLNode,
|
|
155
|
-
|
|
156
|
-
smoothness: TSLNode | number = 0.5,
|
|
157
|
-
roundness: TSLNode | number = 1
|
|
154
|
+
...args: [intensity?: TSLNode | number, smoothness?: TSLNode | number, roundness?: TSLNode | number]
|
|
158
155
|
): TSLNode {
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
156
|
+
const [intensity = 0.5, smoothness = 0.5, roundness = 1] = args
|
|
157
|
+
const int = toScalarNode(intensity)
|
|
158
|
+
const smooth = toScalarNode(smoothness)
|
|
159
|
+
const round = toScalarNode(roundness)
|
|
162
160
|
|
|
163
161
|
const center = uv.sub(0.5)
|
|
164
162
|
const dist = center.length().mul(round)
|
|
@@ -192,13 +190,12 @@ export function rectVignette(
|
|
|
192
190
|
*/
|
|
193
191
|
export function paperTexture(
|
|
194
192
|
uv: TSLNode,
|
|
195
|
-
|
|
196
|
-
intensity: TSLNode | number = 0.1,
|
|
197
|
-
seed: TSLNode | number = 0
|
|
193
|
+
...args: [scale?: TSLNode | number, intensity?: TSLNode | number, seed?: TSLNode | number]
|
|
198
194
|
): TSLNode {
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
const
|
|
195
|
+
const [scale = 10, intensity = 0.1, seed = 0] = args
|
|
196
|
+
const s = toScalarNode(scale)
|
|
197
|
+
const int = toScalarNode(intensity)
|
|
198
|
+
const sd = toScalarNode(seed)
|
|
202
199
|
|
|
203
200
|
// Multi-octave noise for paper texture
|
|
204
201
|
const noise1 = grain(uv.mul(s), 1, sd)
|
|
@@ -214,11 +211,11 @@ export function paperTexture(
|
|
|
214
211
|
export function halftone(
|
|
215
212
|
uv: TSLNode,
|
|
216
213
|
value: TSLNode,
|
|
217
|
-
|
|
218
|
-
angle: TSLNode | number = 0
|
|
214
|
+
...args: [scale?: TSLNode | number, angle?: TSLNode | number]
|
|
219
215
|
): TSLNode {
|
|
220
|
-
const
|
|
221
|
-
const
|
|
216
|
+
const [scale = 50, angle = 0] = args
|
|
217
|
+
const s = toScalarNode(scale)
|
|
218
|
+
const a = toScalarNode(angle)
|
|
222
219
|
|
|
223
220
|
// Rotate UV
|
|
224
221
|
const cosA = a.cos()
|
|
@@ -245,9 +242,9 @@ export function halftone(
|
|
|
245
242
|
export function applyGrain(
|
|
246
243
|
color: TSLNode,
|
|
247
244
|
uv: TSLNode,
|
|
248
|
-
|
|
249
|
-
seed: TSLNode | number = 0
|
|
245
|
+
...args: [intensity?: TSLNode | number, seed?: TSLNode | number]
|
|
250
246
|
): TSLNode {
|
|
247
|
+
const [intensity = 0.05, seed = 0] = args
|
|
251
248
|
const grainValue = grain(uv, intensity, seed)
|
|
252
249
|
return clamp(color.add(grainValue), 0, 1)
|
|
253
250
|
}
|
|
@@ -258,9 +255,9 @@ export function applyGrain(
|
|
|
258
255
|
export function applyColoredGrain(
|
|
259
256
|
color: TSLNode,
|
|
260
257
|
uv: TSLNode,
|
|
261
|
-
|
|
262
|
-
seed: TSLNode | number = 0
|
|
258
|
+
...args: [intensity?: TSLNode | number, seed?: TSLNode | number]
|
|
263
259
|
): TSLNode {
|
|
260
|
+
const [intensity = 0.05, seed = 0] = args
|
|
264
261
|
const grainValue = coloredGrain(uv, intensity, seed)
|
|
265
262
|
return clamp(color.add(grainValue), 0, 1)
|
|
266
263
|
}
|
|
@@ -271,8 +268,9 @@ export function applyColoredGrain(
|
|
|
271
268
|
export function applyVignette(
|
|
272
269
|
color: TSLNode,
|
|
273
270
|
uv: TSLNode,
|
|
274
|
-
|
|
271
|
+
...args: [intensity?: TSLNode | number]
|
|
275
272
|
): TSLNode {
|
|
273
|
+
const [intensity = 0.5] = args
|
|
276
274
|
const vignetteValue = vignette(uv, intensity)
|
|
277
275
|
return color.mul(vignetteValue)
|
|
278
276
|
}
|
|
@@ -283,9 +281,9 @@ export function applyVignette(
|
|
|
283
281
|
export function applyScanlines(
|
|
284
282
|
color: TSLNode,
|
|
285
283
|
uv: TSLNode,
|
|
286
|
-
|
|
287
|
-
intensity: TSLNode | number = 0.25
|
|
284
|
+
...args: [density?: TSLNode | number, intensity?: TSLNode | number]
|
|
288
285
|
): TSLNode {
|
|
286
|
+
const [density = 400, intensity = 0.25] = args
|
|
289
287
|
const scanlineValue = scanlines(uv, density, intensity)
|
|
290
288
|
return color.mul(scanlineValue)
|
|
291
289
|
}
|
|
@@ -437,13 +435,12 @@ export function bayer8x8(uv: TSLNode, scale: TSLNode | number = 1): TSLNode {
|
|
|
437
435
|
export function dither8x8Color(
|
|
438
436
|
color: TSLNode,
|
|
439
437
|
uv: TSLNode,
|
|
440
|
-
|
|
441
|
-
strength: TSLNode | number = 1,
|
|
442
|
-
bias: TSLNode | number = 0.5
|
|
438
|
+
...args: [levels?: TSLNode | number, strength?: TSLNode | number, bias?: TSLNode | number]
|
|
443
439
|
): TSLNode {
|
|
444
|
-
const
|
|
445
|
-
const
|
|
446
|
-
const
|
|
440
|
+
const [levels = 16, strength = 1, bias = 0.5] = args
|
|
441
|
+
const lvl = toScalarNode(levels)
|
|
442
|
+
const str = toScalarNode(strength)
|
|
443
|
+
const b = toScalarNode(bias)
|
|
447
444
|
|
|
448
445
|
const threshold = bayer8x8(uv, 8).sub(b).mul(str).div(lvl)
|
|
449
446
|
const dithered = floor(color.mul(lvl).add(threshold)).div(lvl)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { dot, float, max, mix, normalize, pow, reflect, vec3 } from 'three/tsl'
|
|
6
6
|
|
|
7
7
|
import type { TSLNode } from '../types'
|
|
8
|
+
import { toScalarNode } from './nodes'
|
|
8
9
|
|
|
9
10
|
// ============================================
|
|
10
11
|
// Fresnel Effect
|
|
@@ -72,11 +73,10 @@ export function diffuse(lightDir: TSLNode, normal: TSLNode, lightColor: TSLNode)
|
|
|
72
73
|
*/
|
|
73
74
|
export function phongSpecular(
|
|
74
75
|
viewDir: TSLNode,
|
|
75
|
-
normal: TSLNode,
|
|
76
|
-
lightDir: TSLNode,
|
|
77
|
-
shininess: TSLNode | number = 32
|
|
76
|
+
...args: [normal: TSLNode, lightDir: TSLNode, shininess?: TSLNode | number]
|
|
78
77
|
): TSLNode {
|
|
79
|
-
const
|
|
78
|
+
const [normal, lightDir, shininess = 32] = args
|
|
79
|
+
const p = toScalarNode(shininess)
|
|
80
80
|
const reflectDir = normalize(reflect(lightDir.negate(), normal))
|
|
81
81
|
const phongValue = max(0, dot(viewDir, reflectDir)).pow(p)
|
|
82
82
|
return vec3(phongValue)
|
|
@@ -96,11 +96,10 @@ export function phongSpecular(
|
|
|
96
96
|
*/
|
|
97
97
|
export function blinnPhongSpecular(
|
|
98
98
|
viewDir: TSLNode,
|
|
99
|
-
normal: TSLNode,
|
|
100
|
-
lightDir: TSLNode,
|
|
101
|
-
shininess: TSLNode | number = 32
|
|
99
|
+
...args: [normal: TSLNode, lightDir: TSLNode, shininess?: TSLNode | number]
|
|
102
100
|
): TSLNode {
|
|
103
|
-
const
|
|
101
|
+
const [normal, lightDir, shininess = 32] = args
|
|
102
|
+
const p = toScalarNode(shininess)
|
|
104
103
|
const halfDir = normalize(lightDir.add(viewDir))
|
|
105
104
|
const specAngle = max(0, dot(halfDir, normal))
|
|
106
105
|
return vec3(pow(specAngle, p))
|
|
@@ -127,16 +126,19 @@ export type LightingOptions = {
|
|
|
127
126
|
*/
|
|
128
127
|
export function phongLighting(
|
|
129
128
|
viewDir: TSLNode,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
...args: [
|
|
130
|
+
normal: TSLNode,
|
|
131
|
+
lightDir: TSLNode,
|
|
132
|
+
lightColor: TSLNode,
|
|
133
|
+
options?: LightingOptions,
|
|
134
|
+
]
|
|
134
135
|
): TSLNode {
|
|
136
|
+
const [normal, lightDir, lightColor, options = {}] = args
|
|
135
137
|
const { ambient = 0.1, diffuseStrength = 1.0, specularStrength = 0.5, shininess = 32 } = options
|
|
136
138
|
|
|
137
|
-
const ambientVal =
|
|
138
|
-
const diffStr =
|
|
139
|
-
const specStr =
|
|
139
|
+
const ambientVal = toScalarNode(ambient)
|
|
140
|
+
const diffStr = toScalarNode(diffuseStrength)
|
|
141
|
+
const specStr = toScalarNode(specularStrength)
|
|
140
142
|
|
|
141
143
|
const ambientLight = lightColor.mul(ambientVal)
|
|
142
144
|
const diffuseLight = diffuse(lightDir, normal, lightColor).mul(diffStr)
|
|
@@ -167,11 +167,9 @@ export function complexTan(a: TSLNode): TSLNode {
|
|
|
167
167
|
*/
|
|
168
168
|
export function grad(
|
|
169
169
|
st: TSLNode,
|
|
170
|
-
color1: TSLNode,
|
|
171
|
-
color2: TSLNode,
|
|
172
|
-
color3: TSLNode,
|
|
173
|
-
color4: TSLNode
|
|
170
|
+
...colors: [color1: TSLNode, color2: TSLNode, color3: TSLNode, color4: TSLNode]
|
|
174
171
|
): TSLNode {
|
|
172
|
+
const [color1, color2, color3, color4] = colors
|
|
175
173
|
const _uv = vec2(st).toVar()
|
|
176
174
|
const _color0 = vec4(color1, 1.0).toVar()
|
|
177
175
|
const _color1 = vec4(color2, 1.0).toVar()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { float, vec2, vec3 } from 'three/tsl'
|
|
2
|
+
|
|
3
|
+
import type { TSLNode } from '../types'
|
|
4
|
+
|
|
5
|
+
export function toScalarNode(value: TSLNode | number): TSLNode {
|
|
6
|
+
return typeof value === 'number' ? float(value) : value
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function toVec2Node(value: TSLNode | number | [number, number]): TSLNode {
|
|
10
|
+
if (typeof value === 'number') return vec2(value, value)
|
|
11
|
+
if (Array.isArray(value)) return vec2(value[0], value[1])
|
|
12
|
+
return value
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function toVec3Node(value: TSLNode | [number, number, number]): TSLNode {
|
|
16
|
+
return Array.isArray(value) ? vec3(value[0], value[1], value[2]) : value
|
|
17
|
+
}
|
|
@@ -48,10 +48,9 @@ export function gradient2(t: TSLNode, color1: TSLNode | string, color2: TSLNode
|
|
|
48
48
|
*/
|
|
49
49
|
export function gradient3(
|
|
50
50
|
t: TSLNode,
|
|
51
|
-
color1: TSLNode | string,
|
|
52
|
-
color2: TSLNode | string,
|
|
53
|
-
color3: TSLNode | string
|
|
51
|
+
...colors: [color1: TSLNode | string, color2: TSLNode | string, color3: TSLNode | string]
|
|
54
52
|
): TSLNode {
|
|
53
|
+
const [color1, color2, color3] = colors
|
|
55
54
|
const c1 = typeof color1 === 'string' ? hexToVec3(color1) : color1
|
|
56
55
|
const c2 = typeof color2 === 'string' ? hexToVec3(color2) : color2
|
|
57
56
|
const c3 = typeof color3 === 'string' ? hexToVec3(color3) : color3
|
|
@@ -68,11 +67,14 @@ export function gradient3(
|
|
|
68
67
|
*/
|
|
69
68
|
export function gradient4(
|
|
70
69
|
t: TSLNode,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
...colors: [
|
|
71
|
+
color1: TSLNode | string,
|
|
72
|
+
color2: TSLNode | string,
|
|
73
|
+
color3: TSLNode | string,
|
|
74
|
+
color4: TSLNode | string,
|
|
75
|
+
]
|
|
75
76
|
): TSLNode {
|
|
77
|
+
const [color1, color2, color3, color4] = colors
|
|
76
78
|
const c1 = typeof color1 === 'string' ? hexToVec3(color1) : color1
|
|
77
79
|
const c2 = typeof color2 === 'string' ? hexToVec3(color2) : color2
|
|
78
80
|
const c3 = typeof color3 === 'string' ? hexToVec3(color3) : color3
|
|
@@ -133,11 +135,19 @@ export function gradientMulti(t: TSLNode, stops: ColorStop[]): TSLNode {
|
|
|
133
135
|
*/
|
|
134
136
|
export function cosinePalette(
|
|
135
137
|
t: TSLNode,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
...args: [
|
|
139
|
+
brightness?: TSLNode | [number, number, number],
|
|
140
|
+
contrast?: TSLNode | [number, number, number],
|
|
141
|
+
frequency?: TSLNode | [number, number, number],
|
|
142
|
+
phase?: TSLNode | [number, number, number],
|
|
143
|
+
]
|
|
140
144
|
): TSLNode {
|
|
145
|
+
const [
|
|
146
|
+
brightness = [0.5, 0.5, 0.5],
|
|
147
|
+
contrast = [0.5, 0.5, 0.5],
|
|
148
|
+
frequency = [1.0, 1.0, 1.0],
|
|
149
|
+
phase = [0.0, 0.33, 0.67],
|
|
150
|
+
] = args
|
|
141
151
|
const a = Array.isArray(brightness) ? vec3(...brightness) : brightness
|
|
142
152
|
const b = Array.isArray(contrast) ? vec3(...contrast) : contrast
|
|
143
153
|
const c = Array.isArray(frequency) ? vec3(...frequency) : frequency
|