kmcom-nuxt-layers 2.2.12 → 2.3.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.
Files changed (102) hide show
  1. package/docs/FEEDS.md +1 -2
  2. package/layers/animations/app/composables/useMagneticElement.ts +11 -9
  3. package/layers/animations/app/composables/useTiltEffect.ts +11 -9
  4. package/layers/animations/app/utils/pointerMotion.ts +31 -0
  5. package/layers/canvas/app/components/ShaderCanvas.vue +2 -2
  6. package/layers/content/app/composables/useCollectionItems.ts +28 -0
  7. package/layers/content/app/composables/useGalleryItems.ts +8 -14
  8. package/layers/content/app/composables/usePortfolioItems.ts +10 -18
  9. package/layers/core/app/composables/useBrowser.ts +9 -82
  10. package/layers/core/app/composables/useFeatures.ts +3 -27
  11. package/layers/core/app/plugins/init.ts +157 -135
  12. package/layers/core/app/utils/browserInfo.ts +115 -0
  13. package/layers/core/app/utils/featureClasses.ts +40 -0
  14. package/layers/core/app/utils/helpers.test.ts +51 -0
  15. package/layers/feeds/app/components/Feeds/Index.vue +1 -1
  16. package/layers/feeds/app/components/Feeds/RouteCard.vue +3 -9
  17. package/layers/feeds/app/utils/feed-catalog.ts +9 -4
  18. package/layers/feeds/nuxt.config.ts +0 -1
  19. package/layers/feeds/server/utils/content-adapter.test.ts +68 -0
  20. package/layers/feeds/server/utils/content-adapter.ts +2 -22
  21. package/layers/feeds/server/utils/feed-author.ts +32 -0
  22. package/layers/feeds/server/utils/feed-config.ts +88 -0
  23. package/layers/feeds/server/utils/feed-service.ts +11 -30
  24. package/layers/feeds/server/utils/feed-xml.ts +26 -0
  25. package/layers/feeds/server/utils/formats/rss.ts +10 -15
  26. package/layers/feeds/server/utils/formats.test.ts +71 -0
  27. package/layers/forms/app/components/Form/Field.vue +42 -30
  28. package/layers/forms/app/utils/fieldProps.ts +65 -0
  29. package/layers/layout/app/components/Layout/Grid/Item.vue +29 -146
  30. package/layers/layout/app/utils/gridPlacementStyle.ts +195 -0
  31. package/layers/mailer/app/types/mailer.ts +7 -25
  32. package/layers/mailer/server/utils/email.ts +28 -13
  33. package/layers/mailer/server/utils/hooks.ts +1 -20
  34. package/layers/navigation/app/composables/useSite.ts +2 -9
  35. package/layers/navigation/app/utils/site.ts +26 -0
  36. package/layers/routing/app/utils/resolveRoute.test.ts +47 -0
  37. package/layers/routing/app/utils/resolveRoute.ts +19 -10
  38. package/layers/scripts/app/composables/useAnalytics.ts +8 -41
  39. package/layers/scripts/app/composables/useGtm.ts +6 -13
  40. package/layers/scripts/app/utils/scriptClients.ts +70 -0
  41. package/layers/scroll/app/composables/useSmoothScroll.ts +9 -43
  42. package/layers/scroll/app/utils/scroll.ts +103 -0
  43. package/layers/seo/app/composables/useSeoConfig.ts +3 -9
  44. package/layers/seo/app/utils/seoConfig.ts +38 -0
  45. package/layers/shader/app/components/Material/AmbientAurora.client.vue +11 -33
  46. package/layers/shader/app/components/Material/AmbientFlow.client.vue +10 -37
  47. package/layers/shader/app/components/Material/AmbientGradientMesh.client.vue +10 -37
  48. package/layers/shader/app/components/Material/AmbientNebula.client.vue +12 -37
  49. package/layers/shader/app/components/Material/AmbientOcean.client.vue +9 -33
  50. package/layers/shader/app/components/Material/Gradient.client.vue +25 -46
  51. package/layers/shader/app/components/Material/Image.client.vue +10 -55
  52. package/layers/shader/app/components/Material/Node.client.vue +18 -5
  53. package/layers/shader/app/components/Material/Noise.client.vue +9 -43
  54. package/layers/shader/app/components/Preset/ThemeBubble.client.vue +2 -1
  55. package/layers/shader/app/components/Preset/ThemeFlow.client.vue +2 -1
  56. package/layers/shader/app/components/Preset/ThemeGradient.client.vue +2 -1
  57. package/layers/shader/app/components/Preset/ThemeLavaLamp.client.vue +2 -1
  58. package/layers/shader/app/components/Preset/ThemePlasma.client.vue +2 -1
  59. package/layers/shader/app/components/Preset/ThemeWave.client.vue +2 -1
  60. package/layers/shader/app/components/Shader/Background.client.vue +44 -24
  61. package/layers/shader/app/composables/useAmbientMaterials.ts +5 -1
  62. package/layers/shader/app/composables/useShader.ts +38 -23
  63. package/layers/shader/app/composables/useShaderGraph.ts +11 -6
  64. package/layers/shader/app/composables/useShaderMixBlend.ts +4 -4
  65. package/layers/shader/app/composables/useShaderRuntime.ts +0 -1
  66. package/layers/shader/app/composables/useShaderVec2.ts +2 -4
  67. package/layers/shader/app/composables/useThemePreset.ts +34 -8
  68. package/layers/shader/app/composables/useUniformWatchers.ts +15 -0
  69. package/layers/shader/app/composables/useUniforms.ts +0 -1
  70. package/layers/shader/app/shaders/common/blend.ts +4 -4
  71. package/layers/shader/app/shaders/common/effects.ts +38 -21
  72. package/layers/shader/app/shaders/common/grain.ts +46 -49
  73. package/layers/shader/app/shaders/common/lighting.ts +17 -15
  74. package/layers/shader/app/shaders/common/math.ts +2 -4
  75. package/layers/shader/app/shaders/common/nodes.ts +17 -0
  76. package/layers/shader/app/shaders/common/palette.ts +21 -11
  77. package/layers/shader/app/shaders/common/patterns.ts +25 -14
  78. package/layers/shader/app/shaders/common/shapes.ts +97 -88
  79. package/layers/shader/app/shaders/common/uv.ts +33 -34
  80. package/layers/shader/app/shaders/createMaterial.ts +92 -78
  81. package/layers/shader/app/shaders/layers/paperShading.ts +22 -10
  82. package/layers/shader/app/shaders/layers/shaderGradient.ts +46 -21
  83. package/layers/shader/app/utils/tsl/tween.ts +2 -4
  84. package/layers/shader/package.json +5 -1
  85. package/layers/starter/app/components/StarterDesignSystem.vue +1913 -0
  86. package/layers/starter/app/components/StarterHome.vue +407 -0
  87. package/layers/starter/nuxt.config.ts +15 -0
  88. package/layers/starter/package.json +10 -0
  89. package/layers/theme/app/components/ThemePicker/Menu.vue +3 -25
  90. package/layers/theme/app/composables/useThemePreferenceModels.ts +39 -0
  91. package/layers/theme/server/plugins/theme-fouc.ts +1 -92
  92. package/layers/theme/server/utils/accent-css.ts +75 -0
  93. package/layers/typography/app/composables/typography.ts +3 -7
  94. package/layers/visual/app/composables/accent.ts +2 -9
  95. package/layers/visual/app/composables/gradient.ts +33 -46
  96. package/layers/visual/app/composables/picture.ts +2 -79
  97. package/layers/visual/app/utils/colorTokens.ts +23 -0
  98. package/layers/visual/app/utils/gradientStyle.ts +41 -0
  99. package/layers/visual/app/utils/responsiveSizes.ts +49 -0
  100. package/package.json +17 -5
  101. package/layers/feeds/app/utils/feed-catalog.test.ts +0 -71
  102. package/layers/feeds/server/routes/feed/discovery.get.ts +0 -31
@@ -1,49 +1,16 @@
1
- type AnalyticsProxy = {
2
- track: (event: string, params?: Record<string, unknown>) => void
3
- load: () => void
4
- }
5
-
6
- function noop(): AnalyticsProxy {
7
- return { track: () => {}, load: () => {} }
8
- }
1
+ import {
2
+ createAnalyticsClient,
3
+ resolveScriptTrigger,
4
+ type AnalyticsClient,
5
+ } from '../utils/scriptClients'
9
6
 
10
- export function useAnalytics(): AnalyticsProxy {
7
+ export function useAnalytics(): AnalyticsClient {
11
8
  const { scriptsLayer } = useAppConfig()
12
9
  const { hasConsent, consentRequired } = useScriptsConsent()
13
10
 
14
11
  const provider = scriptsLayer?.analytics?.provider
15
12
  const id = scriptsLayer?.analytics?.id
13
+ const trigger = resolveScriptTrigger(consentRequired, hasConsent)
16
14
 
17
- if (!provider || !id) return noop()
18
-
19
- // Load on Nuxt ready unless consent is required and not yet granted
20
- const trigger = consentRequired.value
21
- ? useScriptTriggerConsent({ consent: hasConsent })
22
- : 'onNuxtReady'
23
-
24
- if (provider === 'ga4') {
25
- const ga = useScriptGoogleAnalytics({ id, scriptOptions: { trigger } })
26
- return {
27
- track: (event, params) => ga.proxy.gtag('event', event, params ?? {}),
28
- load: () => ga.load(),
29
- }
30
- }
31
-
32
- if (provider === 'plausible') {
33
- const pl = useScriptPlausibleAnalytics({ domain: id, scriptOptions: { trigger } })
34
- return {
35
- track: (event, params) => pl.proxy.plausible(event, { props: params ?? {} }),
36
- load: () => pl.load(),
37
- }
38
- }
39
-
40
- if (provider === 'fathom') {
41
- const fa = useScriptFathomAnalytics({ site: id, scriptOptions: { trigger } })
42
- return {
43
- track: (event) => fa.proxy.trackEvent(event, { _value: 0 }),
44
- load: () => fa.load(),
45
- }
46
- }
47
-
48
- return noop()
15
+ return createAnalyticsClient(provider, id ?? '', trigger)
49
16
  }
@@ -1,21 +1,14 @@
1
- export function useGtm() {
1
+ import { createGtmClient, resolveScriptTrigger, type GtmClient } from '../utils/scriptClients'
2
+
3
+ export function useGtm(): GtmClient {
2
4
  const { scriptsLayer } = useAppConfig()
3
5
  const { hasConsent, consentRequired } = useScriptsConsent()
4
6
 
5
7
  const gtmConfig = scriptsLayer?.gtm
6
- if (!gtmConfig?.enabled || !gtmConfig?.id) {
8
+ if (!gtmConfig?.enabled) {
7
9
  return { push: () => {}, load: () => {} }
8
10
  }
9
11
 
10
- // Load on Nuxt ready unless consent is required and not yet granted
11
- const trigger = consentRequired.value
12
- ? useScriptTriggerConsent({ consent: hasConsent })
13
- : 'onNuxtReady'
14
-
15
- const gtm = useScriptGoogleTagManager({ id: gtmConfig.id, scriptOptions: { trigger } })
16
-
17
- return {
18
- push: (data: Record<string, unknown>) => gtm.proxy.dataLayer.push(data),
19
- load: () => gtm.load(),
20
- }
12
+ const trigger = resolveScriptTrigger(consentRequired, hasConsent)
13
+ return createGtmClient(gtmConfig.id, trigger)
21
14
  }
@@ -0,0 +1,70 @@
1
+ import type { Ref } from 'vue'
2
+
3
+ export type ScriptTrigger = ReturnType<typeof useScriptTriggerConsent> | 'onNuxtReady'
4
+
5
+ export type AnalyticsClient = {
6
+ track: (event: string, params?: Record<string, unknown>) => void
7
+ load: () => void
8
+ }
9
+
10
+ export type GtmClient = {
11
+ push: (data: Record<string, unknown>) => void
12
+ load: () => void
13
+ }
14
+
15
+ export function resolveScriptTrigger(consentRequired: Ref<boolean>, consent: Ref<boolean>) {
16
+ return consentRequired.value ? useScriptTriggerConsent({ consent }) : 'onNuxtReady'
17
+ }
18
+
19
+ function noopAnalyticsClient(): AnalyticsClient {
20
+ return { track: () => {}, load: () => {} }
21
+ }
22
+
23
+ // fallow-ignore-next-line complexity
24
+ export function createAnalyticsClient(
25
+ provider: string | null | undefined,
26
+ id: string,
27
+ trigger: ScriptTrigger
28
+ ): AnalyticsClient {
29
+ if (!provider || !id) return noopAnalyticsClient()
30
+
31
+ if (provider === 'ga4') {
32
+ const ga = useScriptGoogleAnalytics({ id, scriptOptions: { trigger } })
33
+ return {
34
+ track: (event, params) => ga.proxy.gtag('event', event, params ?? {}),
35
+ load: () => ga.load(),
36
+ }
37
+ }
38
+
39
+ if (provider === 'plausible') {
40
+ const pl = useScriptPlausibleAnalytics({ domain: id, scriptOptions: { trigger } })
41
+ return {
42
+ track: (event, params) => pl.proxy.plausible(event, { props: params ?? {} }),
43
+ load: () => pl.load(),
44
+ }
45
+ }
46
+
47
+ if (provider === 'fathom') {
48
+ const fa = useScriptFathomAnalytics({ site: id, scriptOptions: { trigger } })
49
+ return {
50
+ track: (event) => fa.proxy.trackEvent(event, { _value: 0 }),
51
+ load: () => fa.load(),
52
+ }
53
+ }
54
+
55
+ return noopAnalyticsClient()
56
+ }
57
+
58
+ function noopGtmClient(): GtmClient {
59
+ return { push: () => {}, load: () => {} }
60
+ }
61
+
62
+ export function createGtmClient(id: string | undefined, trigger: ScriptTrigger): GtmClient {
63
+ if (!id) return noopGtmClient()
64
+
65
+ const gtm = useScriptGoogleTagManager({ id, scriptOptions: { trigger } })
66
+ return {
67
+ push: (data: Record<string, unknown>) => gtm.proxy.dataLayer.push(data),
68
+ load: () => gtm.load(),
69
+ }
70
+ }
@@ -1,13 +1,12 @@
1
1
  import type { Ref } from 'vue'
2
2
  import type LocomotiveScroll from 'locomotive-scroll'
3
3
 
4
- type ScrollToOptions = {
5
- offset?: number
6
- duration?: number
7
- immediate?: boolean
8
- lock?: boolean
9
- onComplete?: () => void
10
- }
4
+ import {
5
+ runLocomotiveScroll,
6
+ runNativeScroll,
7
+ type ScrollTarget,
8
+ type ScrollToOptions,
9
+ } from '../utils/scroll'
11
10
 
12
11
  /**
13
12
  * Unified scroll composable using Locomotive Scroll v5 smooth scrolling
@@ -60,20 +59,14 @@ export function useSmoothScroll() {
60
59
  locomotiveScroll.value?.start()
61
60
  }
62
61
 
63
- function scrollTo(target: string | number | HTMLElement, options?: ScrollToOptions) {
62
+ function scrollTo(target: ScrollTarget, options?: ScrollToOptions) {
64
63
  if (!import.meta.client) return
65
64
 
66
65
  if (locomotiveScroll.value) {
67
- locomotiveScroll.value.scrollTo(target, {
68
- offset: options?.offset ?? 0,
69
- duration: options?.duration ?? 1.2,
70
- immediate: options?.immediate ?? false,
71
- lock: options?.lock ?? false,
72
- ...(options?.onComplete !== undefined && { onComplete: options.onComplete }),
73
- })
66
+ runLocomotiveScroll(locomotiveScroll.value, target, options)
74
67
  return
75
68
  }
76
- nativeScrollTo(target, options)
69
+ runNativeScroll(target, options)
77
70
  }
78
71
 
79
72
  function scrollToTop(options?: { duration?: number; immediate?: boolean }) {
@@ -102,30 +95,3 @@ export function useSmoothScroll() {
102
95
  unlockScrolling,
103
96
  }
104
97
  }
105
-
106
- function resolveScrollTarget(target: string | number | HTMLElement): number | null {
107
- if (typeof target === 'number') return target
108
- if (typeof target === 'string') {
109
- const el = document.querySelector(target)
110
- if (!el) return null
111
- return el.getBoundingClientRect().top + window.scrollY
112
- }
113
- return target.getBoundingClientRect().top + window.scrollY
114
- }
115
-
116
- function nativeScrollTo(target: string | number | HTMLElement, options?: ScrollToOptions) {
117
- const base = resolveScrollTarget(target)
118
- if (base === null) return
119
-
120
- const targetPosition = base + (options?.offset ?? 0)
121
-
122
- if (options?.immediate) {
123
- window.scrollTo(0, targetPosition)
124
- options?.onComplete?.()
125
- return
126
- }
127
- window.scrollTo({ top: targetPosition, behavior: 'smooth' })
128
- if (options?.onComplete) {
129
- setTimeout(options.onComplete, options?.duration ?? 500)
130
- }
131
- }
@@ -0,0 +1,103 @@
1
+ import type LocomotiveScroll from 'locomotive-scroll'
2
+
3
+ export type ScrollTarget = string | number | HTMLElement
4
+
5
+ export type ScrollToOptions = {
6
+ offset?: number | undefined
7
+ duration?: number | undefined
8
+ immediate?: boolean | undefined
9
+ lock?: boolean | undefined
10
+ onComplete?: (() => void) | undefined
11
+ }
12
+
13
+ function resolveScrollOffset(options?: ScrollToOptions) {
14
+ return options?.offset ?? 0
15
+ }
16
+
17
+ function resolveScrollDuration(options?: ScrollToOptions) {
18
+ return options?.duration ?? 1.2
19
+ }
20
+
21
+ function resolveScrollImmediate(options?: ScrollToOptions) {
22
+ return options?.immediate ?? false
23
+ }
24
+
25
+ function resolveScrollLock(options?: ScrollToOptions) {
26
+ return options?.lock ?? false
27
+ }
28
+
29
+ function resolveScrollOnComplete(options?: ScrollToOptions) {
30
+ return options?.onComplete
31
+ }
32
+
33
+ function resolveNativeScrollDelay(options?: ScrollToOptions) {
34
+ return options?.duration ?? 500
35
+ }
36
+
37
+ type LocomotiveScrollOptions = Parameters<LocomotiveScroll['scrollTo']>[1]
38
+
39
+ export function normalizeScrollTarget(target: ScrollTarget): number | null {
40
+ if (typeof target === 'number') return target
41
+ const element = typeof target === 'string' ? document.querySelector(target) : target
42
+ if (!element) return null
43
+ return element.getBoundingClientRect().top + window.scrollY
44
+ }
45
+
46
+ export function normalizeScrollOptions(options?: ScrollToOptions) {
47
+ return {
48
+ offset: resolveScrollOffset(options),
49
+ duration: resolveScrollDuration(options),
50
+ immediate: resolveScrollImmediate(options),
51
+ lock: resolveScrollLock(options),
52
+ ...(resolveScrollOnComplete(options) ? { onComplete: resolveScrollOnComplete(options) } : {}),
53
+ }
54
+ }
55
+
56
+ function runImmediateScroll(targetPosition: number, onComplete?: () => void) {
57
+ window.scrollTo(0, targetPosition)
58
+ onComplete?.()
59
+ }
60
+
61
+ function runSmoothScroll(targetPosition: number, duration: number, onComplete?: () => void) {
62
+ window.scrollTo({ top: targetPosition, behavior: 'smooth' })
63
+ if (onComplete) {
64
+ setTimeout(onComplete, duration)
65
+ }
66
+ }
67
+
68
+ function buildLocomotiveScrollOptions(options?: ScrollToOptions): LocomotiveScrollOptions {
69
+ const scrollOptions: LocomotiveScrollOptions = {
70
+ offset: resolveScrollOffset(options),
71
+ duration: resolveScrollDuration(options),
72
+ immediate: resolveScrollImmediate(options),
73
+ lock: resolveScrollLock(options),
74
+ }
75
+
76
+ const onComplete = resolveScrollOnComplete(options)
77
+ if (onComplete) {
78
+ scrollOptions.onComplete = onComplete
79
+ }
80
+
81
+ return scrollOptions
82
+ }
83
+
84
+ export function runNativeScroll(target: ScrollTarget, options?: ScrollToOptions) {
85
+ const base = normalizeScrollTarget(target)
86
+ if (base === null) return
87
+
88
+ const targetPosition = base + resolveScrollOffset(options)
89
+ if (resolveScrollImmediate(options)) {
90
+ runImmediateScroll(targetPosition, resolveScrollOnComplete(options))
91
+ return
92
+ }
93
+
94
+ runSmoothScroll(targetPosition, resolveNativeScrollDelay(options), resolveScrollOnComplete(options))
95
+ }
96
+
97
+ export function runLocomotiveScroll(
98
+ scroll: LocomotiveScroll,
99
+ target: ScrollTarget,
100
+ options?: ScrollToOptions
101
+ ) {
102
+ scroll.scrollTo(target, buildLocomotiveScrollOptions(options))
103
+ }
@@ -1,13 +1,7 @@
1
+ import { resolveSeoConfig } from '../utils/seoConfig'
2
+
1
3
  export function useSeoConfig() {
2
4
  const site = useSiteConfig()
3
5
  const { seoLayer } = useAppConfig()
4
-
5
- return {
6
- site,
7
- ogImageComponent: seoLayer?.ogImage?.component ?? 'OgImageBasic',
8
- ogImageProps: seoLayer?.ogImage?.props ?? {},
9
- twitterCard: seoLayer?.twitterCard ?? 'summary_large_image',
10
- schemaOrgEnabled: seoLayer?.schemaOrg?.enabled ?? true,
11
- identity: seoLayer?.schemaOrg?.identity ?? null,
12
- }
6
+ return resolveSeoConfig(site, seoLayer)
13
7
  }
@@ -0,0 +1,38 @@
1
+ import type { SiteConfig } from '#layers/core/app/types/site'
2
+
3
+ type SeoLayerConfig = {
4
+ ogImage?: {
5
+ component?: string
6
+ props?: Record<string, unknown>
7
+ }
8
+ twitterCard?: string
9
+ schemaOrg?: {
10
+ enabled?: boolean
11
+ identity?: unknown
12
+ }
13
+ }
14
+
15
+ // fallow-ignore-next-line complexity
16
+ function resolveOgImageConfig(seoLayer?: SeoLayerConfig) {
17
+ return {
18
+ ogImageComponent: seoLayer?.ogImage?.component ?? 'OgImageBasic',
19
+ ogImageProps: seoLayer?.ogImage?.props ?? {},
20
+ }
21
+ }
22
+
23
+ // fallow-ignore-next-line complexity
24
+ function resolveSchemaOrgConfig(seoLayer?: SeoLayerConfig) {
25
+ return {
26
+ schemaOrgEnabled: seoLayer?.schemaOrg?.enabled ?? true,
27
+ identity: seoLayer?.schemaOrg?.identity ?? null,
28
+ }
29
+ }
30
+
31
+ export function resolveSeoConfig(site: SiteConfig, seoLayer?: SeoLayerConfig) {
32
+ return {
33
+ site,
34
+ ...resolveOgImageConfig(seoLayer),
35
+ twitterCard: seoLayer?.twitterCard ?? 'summary_large_image',
36
+ ...resolveSchemaOrgConfig(seoLayer),
37
+ }
38
+ }
@@ -18,6 +18,7 @@
18
18
  import { fbm2D, simplexNoise2D } from '../../shaders/common/noise'
19
19
  import { cosinePalette } from '../../shaders/common/palette'
20
20
  import type { TSLNode } from '../../shaders/types'
21
+ import { watchUniformProp } from '#layers/shader/app/composables/useUniformWatchers'
21
22
 
22
23
  const {
23
24
  speed = 1.0,
@@ -25,6 +26,7 @@
25
26
  color1 = '#0a0a20',
26
27
  color2 = '#00ff87',
27
28
  color3 = '#60efff',
29
+ // fallow-ignore-next-line code-duplication
28
30
  mouseX = 0.5,
29
31
  mouseY = 0.5,
30
32
  mouseInteraction = true,
@@ -51,39 +53,15 @@
51
53
  const color2Uniform: TSLNode = uniform(new Color(color2))
52
54
  const color3Uniform: TSLNode = uniform(new Color(color3))
53
55
 
54
- // Watch prop changes
55
- watch(
56
- () => speed,
57
- (val) => (speedUniform.value = val)
58
- )
59
- watch(
60
- () => intensity,
61
- (val) => (intensityUniform.value = val)
62
- )
63
- watch(
64
- () => mouseX,
65
- (val) => (mouseXUniform.value = val)
66
- )
67
- watch(
68
- () => mouseY,
69
- (val) => (mouseYUniform.value = val)
70
- )
71
- watch(
72
- () => mouseStrength,
73
- (val) => (mouseStrengthUniform.value = val)
74
- )
75
- watch(
76
- () => color1,
77
- (val) => (color1Uniform.value = new Color(val))
78
- )
79
- watch(
80
- () => color2,
81
- (val) => (color2Uniform.value = new Color(val))
82
- )
83
- watch(
84
- () => color3,
85
- (val) => (color3Uniform.value = new Color(val))
86
- )
56
+ watchUniformProp(() => speed, speedUniform)
57
+ watchUniformProp(() => intensity, intensityUniform)
58
+ watchUniformProp(() => mouseX, mouseXUniform)
59
+ watchUniformProp(() => mouseY, mouseYUniform)
60
+ watchUniformProp(() => mouseStrength, mouseStrengthUniform)
61
+ watchUniformProp(() => color1, color1Uniform, (val) => new Color(val))
62
+ watchUniformProp(() => color2, color2Uniform, (val) => new Color(val))
63
+ // fallow-ignore-next-line code-duplication
64
+ watchUniformProp(() => color3, color3Uniform, (val) => new Color(val))
87
65
 
88
66
  const material = computed(() => {
89
67
  const mat = new MeshBasicNodeMaterial()
@@ -18,6 +18,7 @@
18
18
  import { fbm2D, ridgedFbm2d, warpedFbmCoords } from '../../shaders/common/noise'
19
19
  import { cosinePalette } from '../../shaders/common/palette'
20
20
  import type { TSLNode } from '../../shaders/types'
21
+ import { watchUniformProp } from '#layers/shader/app/composables/useUniformWatchers'
21
22
 
22
23
  const {
23
24
  speed = 1.0,
@@ -54,43 +55,15 @@
54
55
  const color3Uniform: TSLNode = uniform(new Color(color3))
55
56
  const color4Uniform: TSLNode = uniform(new Color(color4))
56
57
 
57
- // Watch prop changes
58
- watch(
59
- () => speed,
60
- (val) => (speedUniform.value = val)
61
- )
62
- watch(
63
- () => intensity,
64
- (val) => (intensityUniform.value = val)
65
- )
66
- watch(
67
- () => mouseX,
68
- (val) => (mouseXUniform.value = val)
69
- )
70
- watch(
71
- () => mouseY,
72
- (val) => (mouseYUniform.value = val)
73
- )
74
- watch(
75
- () => mouseStrength,
76
- (val) => (mouseStrengthUniform.value = val)
77
- )
78
- watch(
79
- () => color1,
80
- (val) => (color1Uniform.value = new Color(val))
81
- )
82
- watch(
83
- () => color2,
84
- (val) => (color2Uniform.value = new Color(val))
85
- )
86
- watch(
87
- () => color3,
88
- (val) => (color3Uniform.value = new Color(val))
89
- )
90
- watch(
91
- () => color4,
92
- (val) => (color4Uniform.value = new Color(val))
93
- )
58
+ watchUniformProp(() => speed, speedUniform)
59
+ watchUniformProp(() => intensity, intensityUniform)
60
+ watchUniformProp(() => mouseX, mouseXUniform)
61
+ watchUniformProp(() => mouseY, mouseYUniform)
62
+ watchUniformProp(() => mouseStrength, mouseStrengthUniform)
63
+ watchUniformProp(() => color1, color1Uniform, (val) => new Color(val))
64
+ watchUniformProp(() => color2, color2Uniform, (val) => new Color(val))
65
+ watchUniformProp(() => color3, color3Uniform, (val) => new Color(val))
66
+ watchUniformProp(() => color4, color4Uniform, (val) => new Color(val))
94
67
 
95
68
  const material = computed(() => {
96
69
  const mat = new MeshBasicNodeMaterial()
@@ -19,6 +19,7 @@
19
19
 
20
20
  import { fbm2D, simplexNoise2D } from '../../shaders/common/noise'
21
21
  import type { TSLNode } from '../../shaders/types'
22
+ import { watchUniformProp } from '#layers/shader/app/composables/useUniformWatchers'
22
23
 
23
24
  const {
24
25
  speed = 1.0,
@@ -55,43 +56,15 @@
55
56
  const color3Uniform: TSLNode = uniform(new Color(color3))
56
57
  const color4Uniform: TSLNode = uniform(new Color(color4))
57
58
 
58
- // Watch prop changes
59
- watch(
60
- () => speed,
61
- (val) => (speedUniform.value = val)
62
- )
63
- watch(
64
- () => intensity,
65
- (val) => (intensityUniform.value = val)
66
- )
67
- watch(
68
- () => mouseX,
69
- (val) => (mouseXUniform.value = val)
70
- )
71
- watch(
72
- () => mouseY,
73
- (val) => (mouseYUniform.value = val)
74
- )
75
- watch(
76
- () => mouseStrength,
77
- (val) => (mouseStrengthUniform.value = val)
78
- )
79
- watch(
80
- () => color1,
81
- (val) => (color1Uniform.value = new Color(val))
82
- )
83
- watch(
84
- () => color2,
85
- (val) => (color2Uniform.value = new Color(val))
86
- )
87
- watch(
88
- () => color3,
89
- (val) => (color3Uniform.value = new Color(val))
90
- )
91
- watch(
92
- () => color4,
93
- (val) => (color4Uniform.value = new Color(val))
94
- )
59
+ watchUniformProp(() => speed, speedUniform)
60
+ watchUniformProp(() => intensity, intensityUniform)
61
+ watchUniformProp(() => mouseX, mouseXUniform)
62
+ watchUniformProp(() => mouseY, mouseYUniform)
63
+ watchUniformProp(() => mouseStrength, mouseStrengthUniform)
64
+ watchUniformProp(() => color1, color1Uniform, (val) => new Color(val))
65
+ watchUniformProp(() => color2, color2Uniform, (val) => new Color(val))
66
+ watchUniformProp(() => color3, color3Uniform, (val) => new Color(val))
67
+ watchUniformProp(() => color4, color4Uniform, (val) => new Color(val))
95
68
 
96
69
  const material = computed(() => {
97
70
  const mat = new MeshBasicNodeMaterial()
@@ -19,8 +19,10 @@
19
19
  import { fbm3D, hash21, ridgedFbm2d, voronoi2D } from '../../shaders/common/noise'
20
20
  import { cosinePalette } from '../../shaders/common/palette'
21
21
  import type { TSLNode } from '../../shaders/types'
22
+ import { watchUniformProp } from '#layers/shader/app/composables/useUniformWatchers'
22
23
 
23
24
  const {
25
+ // fallow-ignore-next-line code-duplication
24
26
  speed = 1.0,
25
27
  intensity = 1.0,
26
28
  color1 = '#1a0a2e',
@@ -55,43 +57,16 @@
55
57
  const color3Uniform: TSLNode = uniform(new Color(color3))
56
58
  const color4Uniform: TSLNode = uniform(new Color(color4))
57
59
 
58
- // Watch prop changes
59
- watch(
60
- () => speed,
61
- (val) => (speedUniform.value = val)
62
- )
63
- watch(
64
- () => intensity,
65
- (val) => (intensityUniform.value = val)
66
- )
67
- watch(
68
- () => mouseX,
69
- (val) => (mouseXUniform.value = val)
70
- )
71
- watch(
72
- () => mouseY,
73
- (val) => (mouseYUniform.value = val)
74
- )
75
- watch(
76
- () => mouseStrength,
77
- (val) => (mouseStrengthUniform.value = val)
78
- )
79
- watch(
80
- () => color1,
81
- (val) => (color1Uniform.value = new Color(val))
82
- )
83
- watch(
84
- () => color2,
85
- (val) => (color2Uniform.value = new Color(val))
86
- )
87
- watch(
88
- () => color3,
89
- (val) => (color3Uniform.value = new Color(val))
90
- )
91
- watch(
92
- () => color4,
93
- (val) => (color4Uniform.value = new Color(val))
94
- )
60
+ watchUniformProp(() => speed, speedUniform)
61
+ watchUniformProp(() => intensity, intensityUniform)
62
+ watchUniformProp(() => mouseX, mouseXUniform)
63
+ watchUniformProp(() => mouseY, mouseYUniform)
64
+ watchUniformProp(() => mouseStrength, mouseStrengthUniform)
65
+ watchUniformProp(() => color1, color1Uniform, (val) => new Color(val))
66
+ watchUniformProp(() => color2, color2Uniform, (val) => new Color(val))
67
+ watchUniformProp(() => color3, color3Uniform, (val) => new Color(val))
68
+ // fallow-ignore-next-line code-duplication
69
+ watchUniformProp(() => color4, color4Uniform, (val) => new Color(val))
95
70
 
96
71
  const material = computed(() => {
97
72
  const mat = new MeshBasicNodeMaterial()