kmcom-nuxt-layers 1.0.1

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 (380) hide show
  1. package/.claude/rules/nuxt-layers.md +23 -0
  2. package/.claude/rules/typescript.md +16 -0
  3. package/.claude/rules/vue-components.md +34 -0
  4. package/.claude/settings.local.json +81 -0
  5. package/.editorconfig +27 -0
  6. package/.github/workflows/npm-publish.yml +33 -0
  7. package/.oxlintrc.json +10 -0
  8. package/.prettierignore +87 -0
  9. package/CLAUDE.md +71 -0
  10. package/apps/playground/README.md +75 -0
  11. package/apps/playground/app/app.config.ts +10 -0
  12. package/apps/playground/app/app.vue +12 -0
  13. package/apps/playground/app/components/AmbientBackground.client.vue +795 -0
  14. package/apps/playground/app/components/ShaderDemoCanvas.client.vue +636 -0
  15. package/apps/playground/app/components/ShaderImageDemo.client.vue +211 -0
  16. package/apps/playground/app/pages/ambient.vue +387 -0
  17. package/apps/playground/app/pages/content.vue +200 -0
  18. package/apps/playground/app/pages/core.vue +560 -0
  19. package/apps/playground/app/pages/forms.vue +645 -0
  20. package/apps/playground/app/pages/index.vue +257 -0
  21. package/apps/playground/app/pages/layout.vue +591 -0
  22. package/apps/playground/app/pages/locomotive-scroll.vue +738 -0
  23. package/apps/playground/app/pages/motion.vue +848 -0
  24. package/apps/playground/app/pages/shader.vue +1701 -0
  25. package/apps/playground/app/pages/theme.vue +115 -0
  26. package/apps/playground/app/pages/ui.vue +656 -0
  27. package/apps/playground/content/blog/hello-world.md +127 -0
  28. package/apps/playground/content/blog/second-post.md +99 -0
  29. package/apps/playground/content/blog/third-post.md +33 -0
  30. package/apps/playground/content/gallery/autumn-collection.md +57 -0
  31. package/apps/playground/content/gallery/summer-collection.md +52 -0
  32. package/apps/playground/content/pages/index.md +132 -0
  33. package/apps/playground/content/portfolio/project-one.md +90 -0
  34. package/apps/playground/content/portfolio/project-two.md +96 -0
  35. package/apps/playground/content.config.ts +93 -0
  36. package/apps/playground/nuxt.config.ts +99 -0
  37. package/apps/playground/package.json +17 -0
  38. package/apps/playground/public/favicon.ico +0 -0
  39. package/apps/playground/public/robots.txt +2 -0
  40. package/apps/playground/tsconfig.json +25 -0
  41. package/eslint.config.mjs +223 -0
  42. package/eslint.configCOPY.mjs +216 -0
  43. package/eslintconfigCURRENT.mjs +244 -0
  44. package/eslintconfigOLD.mjs +178 -0
  45. package/files for claude/Scroller.vue +31 -0
  46. package/files for claude/TextMarquee.vue +255 -0
  47. package/files for claude/gsap.client.ts +18 -0
  48. package/files for claude/gsap.ts +10 -0
  49. package/files for claude/scroll.ts +28 -0
  50. package/layers/content/app/assets/css/main.css +1 -0
  51. package/layers/content/app/components/Blog/Article.vue +29 -0
  52. package/layers/content/app/components/Blog/Card.vue +40 -0
  53. package/layers/content/app/components/Blog/List.vue +35 -0
  54. package/layers/content/app/components/Gallery/AmbientImage.vue +52 -0
  55. package/layers/content/app/components/Gallery/Card.vue +39 -0
  56. package/layers/content/app/components/Gallery/Detail.vue +76 -0
  57. package/layers/content/app/components/Gallery/Grid.vue +48 -0
  58. package/layers/content/app/components/Gallery/ImageDetail.vue +92 -0
  59. package/layers/content/app/components/Gallery/Lightbox.vue +102 -0
  60. package/layers/content/app/components/NuxtContent/Detail.vue +53 -0
  61. package/layers/content/app/components/NuxtContent/List.vue +21 -0
  62. package/layers/content/app/components/NuxtContent/Renderer.vue +14 -0
  63. package/layers/content/app/components/NuxtContent/Surround.vue +15 -0
  64. package/layers/content/app/components/NuxtContent/Toc.vue +18 -0
  65. package/layers/content/app/components/Portfolio/Card.vue +39 -0
  66. package/layers/content/app/components/Portfolio/ColorPalette.vue +39 -0
  67. package/layers/content/app/components/Portfolio/Detail.vue +49 -0
  68. package/layers/content/app/components/Portfolio/List.vue +44 -0
  69. package/layers/content/app/components/Portfolio/Typography.vue +37 -0
  70. package/layers/content/app/components/content/Figure.vue +31 -0
  71. package/layers/content/app/composables/useBlogPost.ts +3 -0
  72. package/layers/content/app/composables/useBlogPosts.ts +23 -0
  73. package/layers/content/app/composables/useCollectionItem.ts +5 -0
  74. package/layers/content/app/composables/useCollectionSurround.ts +9 -0
  75. package/layers/content/app/composables/useContentPage.ts +3 -0
  76. package/layers/content/app/composables/useGalleryItem.ts +3 -0
  77. package/layers/content/app/composables/useGalleryItems.ts +19 -0
  78. package/layers/content/app/composables/usePortfolioItem.ts +3 -0
  79. package/layers/content/app/composables/usePortfolioItems.ts +23 -0
  80. package/layers/content/app/pages/blog/[slug].vue +10 -0
  81. package/layers/content/app/pages/blog/index.vue +15 -0
  82. package/layers/content/app/pages/gallery/[slug]/[imageId].vue +11 -0
  83. package/layers/content/app/pages/gallery/[slug]/index.vue +10 -0
  84. package/layers/content/app/pages/gallery/index.vue +15 -0
  85. package/layers/content/app/pages/portfolio/[slug].vue +10 -0
  86. package/layers/content/app/pages/portfolio/index.vue +15 -0
  87. package/layers/content/app/types/content.ts +84 -0
  88. package/layers/content/app.config.ts +12 -0
  89. package/layers/content/content.config.ts +93 -0
  90. package/layers/content/nuxt.config.ts +31 -0
  91. package/layers/content/package.json +31 -0
  92. package/layers/content/tsconfig.json +6 -0
  93. package/layers/core/app/assets/css/base.css +88 -0
  94. package/layers/core/app/assets/css/layout.css +36 -0
  95. package/layers/core/app/assets/css/main.css +7 -0
  96. package/layers/core/app/assets/css-backup.zip +0 -0
  97. package/layers/core/app/components/ErrorBoundary.vue +102 -0
  98. package/layers/core/app/components/LoadingScreen.vue +137 -0
  99. package/layers/core/app/composables/useBrowser.ts +161 -0
  100. package/layers/core/app/composables/useCache.ts +138 -0
  101. package/layers/core/app/composables/useDevice.ts +36 -0
  102. package/layers/core/app/composables/useEnv.ts +23 -0
  103. package/layers/core/app/composables/useErrorLog.ts +158 -0
  104. package/layers/core/app/composables/useFeatures.ts +269 -0
  105. package/layers/core/app/composables/useLoading.ts +109 -0
  106. package/layers/core/app/composables/useNetworkInfo.ts +83 -0
  107. package/layers/core/app/composables/usePWAInfo.ts +104 -0
  108. package/layers/core/app/composables/useRendering.ts +97 -0
  109. package/layers/core/app/composables/useScreen.ts +95 -0
  110. package/layers/core/app/composables/useScrollGuard.ts +266 -0
  111. package/layers/core/app/error.vue +103 -0
  112. package/layers/core/app/layouts/default.vue +4 -0
  113. package/layers/core/app/pages/[...slug].vue +168 -0
  114. package/layers/core/app/pages/diagnostics.vue +228 -0
  115. package/layers/core/app/plugins/error-handler.ts +47 -0
  116. package/layers/core/app/plugins/feature-detection.client.ts +32 -0
  117. package/layers/core/app/plugins/init.ts +188 -0
  118. package/layers/core/app/plugins/loading.client.ts +54 -0
  119. package/layers/core/app/plugins/scroll-guard.client.ts +53 -0
  120. package/layers/core/app/types/detection.ts +117 -0
  121. package/layers/core/app/types/index.ts +10 -0
  122. package/layers/core/app/types/loading.ts +47 -0
  123. package/layers/core/app/types/runtime-config.ts +31 -0
  124. package/layers/core/app/types/scroll-guard.ts +25 -0
  125. package/layers/core/app/utils/helpers.ts +246 -0
  126. package/layers/core/app/utils/index.ts +8 -0
  127. package/layers/core/app/utils/regex.ts +6 -0
  128. package/layers/core/app.config.ts +193 -0
  129. package/layers/core/nuxt.config.ts +84 -0
  130. package/layers/core/package.json +25 -0
  131. package/layers/core/tailwind.config.js +28 -0
  132. package/layers/core/tsconfig.json +6 -0
  133. package/layers/forms/app/components/Form/Contact.vue +78 -0
  134. package/layers/forms/app/components/Form/Field.vue +85 -0
  135. package/layers/forms/app/composables/useFormSchema.ts +35 -0
  136. package/layers/forms/app/config/fields.ts +104 -0
  137. package/layers/forms/app/types/fields.ts +60 -0
  138. package/layers/forms/app.config.ts +12 -0
  139. package/layers/forms/nuxt.config.ts +17 -0
  140. package/layers/forms/package.json +17 -0
  141. package/layers/forms/tsconfig.json +6 -0
  142. package/layers/layout/.nuxtrc +1 -0
  143. package/layers/layout/CLAUDE.MD +186 -0
  144. package/layers/layout/GRID_SYSTEM.md +993 -0
  145. package/layers/layout/README.md +73 -0
  146. package/layers/layout/app/assets/css/layout/grids.css +180 -0
  147. package/layers/layout/app/assets/css/main.css +1 -0
  148. package/layers/layout/app/components/Layout/Grid/Debug.vue +79 -0
  149. package/layers/layout/app/components/Layout/Grid/Item.vue +180 -0
  150. package/layers/layout/app/components/Layout/Page/Container.vue +100 -0
  151. package/layers/layout/app/components/Layout/Page/Header.vue +33 -0
  152. package/layers/layout/app/components/Layout/Section/Gallery.vue +68 -0
  153. package/layers/layout/app/components/Layout/Section/Hero.vue +71 -0
  154. package/layers/layout/app/components/Layout/Section/Split.vue +56 -0
  155. package/layers/layout/app/components/Layout/Section/index.vue +39 -0
  156. package/layers/layout/app/composables/GridPlacement.ts +31 -0
  157. package/layers/layout/app/composables/useGridConfig.ts +27 -0
  158. package/layers/layout/app/types/layouts.ts +37 -0
  159. package/layers/layout/app.config.ts +97 -0
  160. package/layers/layout/nuxt.config.ts +14 -0
  161. package/layers/layout/package.json +14 -0
  162. package/layers/layout/tailwind.config.js +28 -0
  163. package/layers/layout/tsconfig.json +6 -0
  164. package/layers/motion/README.md +107 -0
  165. package/layers/motion/TASKS.MD +16 -0
  166. package/layers/motion/app/assets/css/main.css +111 -0
  167. package/layers/motion/app/components/Motion/Marquee.vue +171 -0
  168. package/layers/motion/app/components/Motion/Parallax.vue +75 -0
  169. package/layers/motion/app/components/Motion/ScrollLink.vue +49 -0
  170. package/layers/motion/app/components/Motion/ScrollProgress.vue +127 -0
  171. package/layers/motion/app/components/Motion/ScrollStats.vue +102 -0
  172. package/layers/motion/app/components/Motion/Staggered.vue +73 -0
  173. package/layers/motion/app/components/Motion/TextReveal.vue +101 -0
  174. package/layers/motion/app/components/Motion/Transition.vue +89 -0
  175. package/layers/motion/app/components/Motion/VelocityEffect.vue +139 -0
  176. package/layers/motion/app/components/Motion/index.vue +16 -0
  177. package/layers/motion/app/composables/useGsap.ts +21 -0
  178. package/layers/motion/app/composables/useMotion.ts +137 -0
  179. package/layers/motion/app/composables/useSmoothScroll.ts +154 -0
  180. package/layers/motion/app/plugins/gsap.client.ts +15 -0
  181. package/layers/motion/app/plugins/locomotive-scroll.client.ts +49 -0
  182. package/layers/motion/app/utils/gsapAnimations.ts +122 -0
  183. package/layers/motion/app.config.ts +30 -0
  184. package/layers/motion/nuxt.config.ts +19 -0
  185. package/layers/motion/package.json +17 -0
  186. package/layers/motion/tsconfig.json +6 -0
  187. package/layers/shader/AGENTS.MD +195 -0
  188. package/layers/shader/additional-modular-tsl-shaders-for-claude/.prettierignore +6 -0
  189. package/layers/shader/additional-modular-tsl-shaders-for-claude/.prettierrc +18 -0
  190. package/layers/shader/additional-modular-tsl-shaders-for-claude/LICENSE +21 -0
  191. package/layers/shader/additional-modular-tsl-shaders-for-claude/README.md +100 -0
  192. package/layers/shader/additional-modular-tsl-shaders-for-claude/index.html +13 -0
  193. package/layers/shader/additional-modular-tsl-shaders-for-claude/jsconfig.json +30 -0
  194. package/layers/shader/additional-modular-tsl-shaders-for-claude/package.json +18 -0
  195. package/layers/shader/additional-modular-tsl-shaders-for-claude/pnpm-lock.yaml +633 -0
  196. package/layers/shader/additional-modular-tsl-shaders-for-claude/public/vite.svg +1 -0
  197. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/components/sketch/webgpu_sketch.js +128 -0
  198. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/components/sketches_dropdown/index.css +87 -0
  199. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/components/sketches_dropdown/sketches_dropdown.js +169 -0
  200. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/index.css +25 -0
  201. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/main.js +93 -0
  202. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/router.js +43 -0
  203. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/sketches/flare-1.js +68 -0
  204. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/sketches/noise/dawn-1.js +56 -0
  205. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/distortion/bulge_distortion.js +35 -0
  206. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/distortion/swirl_distortion.js +35 -0
  207. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/distortion/wave_distortion.js +43 -0
  208. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/common.js +145 -0
  209. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/curl_noise_3d.js +53 -0
  210. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/curl_noise_4d.js +55 -0
  211. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/fbm.js +163 -0
  212. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/perlin_noise_3d.js +70 -0
  213. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/simplex_noise_3d.js +59 -0
  214. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/simplex_noise_4d.js +72 -0
  215. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/noise/turbulence.js +41 -0
  216. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/patterns/canvas_weave_pattern.js +26 -0
  217. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/patterns/grain_texture_pattern.js +10 -0
  218. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/patterns/led_pattern.js +45 -0
  219. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/patterns/pixellation_pattern.js +15 -0
  220. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/patterns/speckled_noise_pattern.js +34 -0
  221. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/patterns/vignette_pattern.js +21 -0
  222. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/bulge_distortion_effect.js +27 -0
  223. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/chromatic_aberration_effect.js +45 -0
  224. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/crt_scanline_effect.js +45 -0
  225. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/dither_effect.js +126 -0
  226. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/grain_texture_effect.js +21 -0
  227. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/halftone_effect.js +44 -0
  228. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/led_effect.js +31 -0
  229. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/pixellation_effect.js +29 -0
  230. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/swirl_distortion_effect.js +25 -0
  231. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/vignette_effect.js +22 -0
  232. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/post_processing/wave_distortion_effect.js +27 -0
  233. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/color/cosine_palette.js +15 -0
  234. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/color/tonemapping.js +151 -0
  235. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/function/bloom.js +13 -0
  236. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/function/bloom_edge_pattern.js +20 -0
  237. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/function/domain_index.js +11 -0
  238. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/function/median3.js +22 -0
  239. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/function/repeating_pattern.js +13 -0
  240. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/function/screen_aspect_uv.js +14 -0
  241. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/lighting.js +60 -0
  242. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/math/complex.js +86 -0
  243. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/math/coordinates.js +119 -0
  244. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/sdf/operations.js +24 -0
  245. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/tsl/utils/sdf/shapes.js +182 -0
  246. package/layers/shader/additional-modular-tsl-shaders-for-claude/src/utils/math.js +33 -0
  247. package/layers/shader/additional-modular-tsl-shaders-for-claude/vite.config.js +23 -0
  248. package/layers/shader/app/assets/css/main.css +41 -0
  249. package/layers/shader/app/components/Effect/Bloom.vue +8 -0
  250. package/layers/shader/app/components/Effect/ChromaticAberration.vue +8 -0
  251. package/layers/shader/app/components/Effect/PostProcessing.vue +20 -0
  252. package/layers/shader/app/components/Material/AmbientAurora.vue +172 -0
  253. package/layers/shader/app/components/Material/AmbientFlow.vue +175 -0
  254. package/layers/shader/app/components/Material/AmbientGradientMesh.vue +173 -0
  255. package/layers/shader/app/components/Material/AmbientNebula.vue +181 -0
  256. package/layers/shader/app/components/Material/AmbientOcean.vue +161 -0
  257. package/layers/shader/app/components/Material/Fresnel.vue +89 -0
  258. package/layers/shader/app/components/Material/Gradient.vue +185 -0
  259. package/layers/shader/app/components/Material/Image.vue +232 -0
  260. package/layers/shader/app/components/Material/Node.vue +79 -0
  261. package/layers/shader/app/components/Material/Noise.vue +141 -0
  262. package/layers/shader/app/components/Mesh/Plane.vue +27 -0
  263. package/layers/shader/app/components/Shader/Background.vue +159 -0
  264. package/layers/shader/app/components/Shader/Canvas.vue +97 -0
  265. package/layers/shader/app/components/Shader/Debug.vue +66 -0
  266. package/layers/shader/app/components/WebGPUCanvas.client.vue +245 -0
  267. package/layers/shader/app/composables/useAmbientMaterials.ts +452 -0
  268. package/layers/shader/app/composables/useMousePosition.ts +94 -0
  269. package/layers/shader/app/composables/useRendererCapabilities.ts +111 -0
  270. package/layers/shader/app/composables/useShader.ts +148 -0
  271. package/layers/shader/app/composables/useShaderTime.ts +146 -0
  272. package/layers/shader/app/composables/useTSLNodes.ts +112 -0
  273. package/layers/shader/app/composables/useUniforms.ts +188 -0
  274. package/layers/shader/app/plugins/shader.client.ts +30 -0
  275. package/layers/shader/app/shaders/common/blend.ts +255 -0
  276. package/layers/shader/app/shaders/common/effects.ts +299 -0
  277. package/layers/shader/app/shaders/common/grain.ts +453 -0
  278. package/layers/shader/app/shaders/common/index.ts +22 -0
  279. package/layers/shader/app/shaders/common/lighting.ts +146 -0
  280. package/layers/shader/app/shaders/common/math.ts +250 -0
  281. package/layers/shader/app/shaders/common/noise.ts +823 -0
  282. package/layers/shader/app/shaders/common/noiseHelpers.ts +114 -0
  283. package/layers/shader/app/shaders/common/palette.ts +319 -0
  284. package/layers/shader/app/shaders/common/patterns.ts +216 -0
  285. package/layers/shader/app/shaders/common/sdf.ts +224 -0
  286. package/layers/shader/app/shaders/common/shapes.ts +366 -0
  287. package/layers/shader/app/shaders/common/tonemapping.ts +172 -0
  288. package/layers/shader/app/shaders/common/uv.ts +396 -0
  289. package/layers/shader/app/shaders/createMaterial.ts +314 -0
  290. package/layers/shader/app/shaders/index.ts +282 -0
  291. package/layers/shader/app/shaders/layers/aurora.ts +146 -0
  292. package/layers/shader/app/shaders/layers/index.ts +19 -0
  293. package/layers/shader/app/shaders/layers/meshGradient.ts +152 -0
  294. package/layers/shader/app/shaders/layers/paperShading.ts +148 -0
  295. package/layers/shader/app/shaders/layers/shaderGradient.ts +152 -0
  296. package/layers/shader/app/shaders/layers/stripe.ts +137 -0
  297. package/layers/shader/app/shaders/types.ts +12 -0
  298. package/layers/shader/app/types/index.ts +4 -0
  299. package/layers/shader/app/types/materials.ts +45 -0
  300. package/layers/shader/app/types/renderer.ts +50 -0
  301. package/layers/shader/app/types/tsl.ts +39 -0
  302. package/layers/shader/app/types/uniforms.ts +21 -0
  303. package/layers/shader/app/utils/tsl/animation.ts +251 -0
  304. package/layers/shader/app/utils/tsl/color.ts +189 -0
  305. package/layers/shader/app/utils/tsl/index.ts +84 -0
  306. package/layers/shader/app/utils/tsl/math.ts +111 -0
  307. package/layers/shader/app/utils/tsl/noise.ts +195 -0
  308. package/layers/shader/app/utils/tsl/patterns.ts +183 -0
  309. package/layers/shader/app/utils/tsl/uv.ts +145 -0
  310. package/layers/shader/app.config.ts +18 -0
  311. package/layers/shader/modular-tsl-shaders-for-claude/common/blend.tsl +1 -0
  312. package/layers/shader/modular-tsl-shaders-for-claude/common/noise.tsl +1 -0
  313. package/layers/shader/modular-tsl-shaders-for-claude/common/shapes.tsl +1 -0
  314. package/layers/shader/modular-tsl-shaders-for-claude/common/vertexFresnel.tsl +9 -0
  315. package/layers/shader/modular-tsl-shaders-for-claude/common/vertexPlane.tsl +6 -0
  316. package/layers/shader/modular-tsl-shaders-for-claude/effects/background.tsl +1 -0
  317. package/layers/shader/modular-tsl-shaders-for-claude/effects/gradient.tsl +1 -0
  318. package/layers/shader/modular-tsl-shaders-for-claude/effects/gradientLegend.tsl +1 -0
  319. package/layers/shader/modular-tsl-shaders-for-claude/effects/simpleGradient.tsl +1 -0
  320. package/layers/shader/modular-tsl-shaders-for-claude/layers/aurora.ts +1 -0
  321. package/layers/shader/modular-tsl-shaders-for-claude/layers/fragmentsTech.ts +1 -0
  322. package/layers/shader/modular-tsl-shaders-for-claude/layers/fresnel.ts +1 -0
  323. package/layers/shader/modular-tsl-shaders-for-claude/layers/linearGradient.ts +1 -0
  324. package/layers/shader/modular-tsl-shaders-for-claude/layers/meshGradient.ts +1 -0
  325. package/layers/shader/modular-tsl-shaders-for-claude/layers/noise.ts +1 -0
  326. package/layers/shader/modular-tsl-shaders-for-claude/layers/paperShading.ts +1 -0
  327. package/layers/shader/modular-tsl-shaders-for-claude/layers/radial.ts +1 -0
  328. package/layers/shader/modular-tsl-shaders-for-claude/layers/shaderGradient.ts +1 -0
  329. package/layers/shader/modular-tsl-shaders-for-claude/layers/stripe.ts +1 -0
  330. package/layers/shader/modular-tsl-shaders-for-claude/materials/createMaterial.ts +1 -0
  331. package/layers/shader/modular-tsl-shaders-for-claude/utils/glslUtils.ts +1 -0
  332. package/layers/shader/modular-tsl-shaders-for-claude/utils/palette.ts +1 -0
  333. package/layers/shader/nuxt.config.ts +48 -0
  334. package/layers/shader/package.json +17 -0
  335. package/layers/shader/tsconfig.json +6 -0
  336. package/layers/theme/app/assets/css/theme.css +47 -0
  337. package/layers/theme/app/components/ThemePicker/AccentButton.vue +51 -0
  338. package/layers/theme/app/components/ThemePicker/Colors.vue +22 -0
  339. package/layers/theme/app/components/ThemePicker/Menu.vue +108 -0
  340. package/layers/theme/app/components/ThemePicker/MenuButton.vue +9 -0
  341. package/layers/theme/app/composables/useThemePreferences.ts +158 -0
  342. package/layers/theme/app/plugins/theme.client.ts +5 -0
  343. package/layers/theme/app/types/theme.ts +34 -0
  344. package/layers/theme/app.config.ts +14 -0
  345. package/layers/theme/nuxt.config.ts +46 -0
  346. package/layers/theme/package.json +14 -0
  347. package/layers/theme/server/plugins/theme-fouc.ts +51 -0
  348. package/layers/theme/tsconfig.json +7 -0
  349. package/layers/ui/CLAUDE.MD +325 -0
  350. package/layers/ui/app/assets/css/main.css +4 -0
  351. package/layers/ui/app/components/Links/Group.vue +38 -0
  352. package/layers/ui/app/components/Links/Named.vue +32 -0
  353. package/layers/ui/app/components/Media/Picture.vue +41 -0
  354. package/layers/ui/app/components/Site/Title.vue +15 -0
  355. package/layers/ui/app/components/Typography/CodeBlock.vue +37 -0
  356. package/layers/ui/app/components/Typography/Headline.vue +73 -0
  357. package/layers/ui/app/components/Typography/QuoteBlock.vue +13 -0
  358. package/layers/ui/app/components/Typography/TextStroke.vue +109 -0
  359. package/layers/ui/app/components/Typography/index.vue +49 -0
  360. package/layers/ui/app/composables/color.ts +36 -0
  361. package/layers/ui/app/composables/picture.ts +145 -0
  362. package/layers/ui/app/composables/typography.ts +77 -0
  363. package/layers/ui/app/layouts/default.vue +4 -0
  364. package/layers/ui/app/pages/index.vue +236 -0
  365. package/layers/ui/app/types/breakpoints.ts +179 -0
  366. package/layers/ui/app/types/colors.ts +29 -0
  367. package/layers/ui/app/types/media.ts +185 -0
  368. package/layers/ui/app/types/typography.ts +108 -0
  369. package/layers/ui/app/utils/regex.ts +6 -0
  370. package/layers/ui/app.config.ts +12 -0
  371. package/layers/ui/nuxt.config.ts +38 -0
  372. package/layers/ui/package.json +14 -0
  373. package/layers/ui/tsconfig.json +6 -0
  374. package/package.json +128 -0
  375. package/playgroundOLD/app.config.ts +5 -0
  376. package/playgroundOLD/nuxt.config.ts +12 -0
  377. package/pnpm-workspace.yaml +6 -0
  378. package/prettier.config.cjs +19 -0
  379. package/stylelint.config.mjs +111 -0
  380. package/turbo.json +16 -0
@@ -0,0 +1,138 @@
1
+ /* eslint-disable no-console */
2
+ // composables/useCache.ts
3
+ import { useOnline } from '@vueuse/core'
4
+
5
+ /**
6
+ * Cache management composable for PWA
7
+ *
8
+ * Provides utilities for managing service worker cache,
9
+ * checking offline readiness, and clearing cached data.
10
+ *
11
+ * @returns Cache state and management functions
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const { isOnline, offlineReady, clearCache } = useCache()
16
+ *
17
+ * if (!isOnline && offlineReady) {
18
+ * // App works offline
19
+ * }
20
+ * ```
21
+ */
22
+ export function useCache() {
23
+ const isOnline = useOnline()
24
+ const offlineReady = ref(false)
25
+
26
+ /**
27
+ * Check if a specific URL is cached
28
+ * @param url - URL to check
29
+ */
30
+ async function isCached(url: string): Promise<boolean> {
31
+ if (!import.meta.client || !('caches' in window)) return false
32
+
33
+ try {
34
+ const cache = await caches.open('workbox-precache-v2')
35
+ const response = await cache.match(url)
36
+ return !!response
37
+ } catch (error) {
38
+ console.warn('[useCache] Failed to check cache:', error)
39
+ return false
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Get total cache size in bytes
45
+ */
46
+ async function getCacheSize(): Promise<number> {
47
+ if (!import.meta.client || !('caches' in window)) return 0
48
+
49
+ try {
50
+ const cacheNames = await caches.keys()
51
+ let totalSize = 0
52
+
53
+ for (const cacheName of cacheNames) {
54
+ const cache = await caches.open(cacheName)
55
+ const requests = await cache.keys()
56
+
57
+ for (const request of requests) {
58
+ const response = await cache.match(request)
59
+ if (response) {
60
+ const blob = await response.blob()
61
+ totalSize += blob.size
62
+ }
63
+ }
64
+ }
65
+
66
+ return totalSize
67
+ } catch (error) {
68
+ console.warn('[useCache] Failed to get cache size:', error)
69
+ return 0
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Clear all caches
75
+ */
76
+ async function clearCache(): Promise<void> {
77
+ if (!import.meta.client || !('caches' in window)) return
78
+
79
+ try {
80
+ const cacheNames = await caches.keys()
81
+ await Promise.all(cacheNames.map((name) => caches.delete(name)))
82
+
83
+ console.log('[useCache] All caches cleared')
84
+ } catch (error) {
85
+ console.error('[useCache] Failed to clear cache:', error)
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Get formatted cache size (human-readable)
91
+ */
92
+ async function getFormattedCacheSize(): Promise<string> {
93
+ const bytes = await getCacheSize()
94
+
95
+ if (bytes === 0) return '0 B'
96
+
97
+ const units = ['B', 'KB', 'MB', 'GB']
98
+ const k = 1024
99
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
100
+
101
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${units[i]}`
102
+ }
103
+
104
+ /**
105
+ * Check if service worker has cached essential resources
106
+ */
107
+ async function checkOfflineReady(): Promise<boolean> {
108
+ if (!import.meta.client || !('caches' in window)) return false
109
+
110
+ try {
111
+ const cacheNames = await caches.keys()
112
+ // If we have any caches, consider offline ready
113
+ offlineReady.value = cacheNames.length > 0
114
+ return offlineReady.value
115
+ } catch (error) {
116
+ console.warn('[useCache] Failed to check offline readiness:', error)
117
+ return false
118
+ }
119
+ }
120
+
121
+ // Check offline readiness on mount
122
+ if (import.meta.client) {
123
+ checkOfflineReady()
124
+ }
125
+
126
+ return {
127
+ // State
128
+ isOnline,
129
+ offlineReady: computed(() => offlineReady.value),
130
+
131
+ // Actions
132
+ isCached,
133
+ clearCache,
134
+ getCacheSize,
135
+ getFormattedCacheSize,
136
+ checkOfflineReady,
137
+ }
138
+ }
@@ -0,0 +1,36 @@
1
+ // composables/useDevice.ts
2
+ // Device detection composable for Nuxt layers
3
+ // Wraps @nuxtjs/device (if available) and provides SSR/client fallback
4
+
5
+ /**
6
+ * Device detection composable
7
+ *
8
+ * Returns booleans for isMobile, isTablet, isDesktop
9
+ * Uses @nuxtjs/device if available, otherwise falls back to user agent sniffing (client only)
10
+ */
11
+ export function useDevice() {
12
+ const nuxtApp = useNuxtApp()
13
+ // @nuxtjs/device injects $device into Nuxt app context
14
+ const device = nuxtApp.$device
15
+
16
+ // If @nuxtjs/device is present, use it
17
+ if (device) {
18
+ return {
19
+ isMobile: computed(() => device.isMobile),
20
+ isTablet: computed(() => device.isTablet),
21
+ isDesktop: computed(() => device.isDesktop),
22
+ }
23
+ }
24
+
25
+ // Fallback: basic user agent detection (client only)
26
+ const ua = typeof navigator !== 'undefined' ? navigator.userAgent : ''
27
+ const isMobile = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua)
28
+ const isTablet = /Tablet|iPad/i.test(ua)
29
+ const isDesktop = !isMobile && !isTablet
30
+
31
+ return {
32
+ isMobile: computed(() => isMobile),
33
+ isTablet: computed(() => isTablet),
34
+ isDesktop: computed(() => isDesktop),
35
+ }
36
+ }
@@ -0,0 +1,23 @@
1
+ // composables/useEnv.ts
2
+
3
+ /**
4
+ * Type-safe environment variable access
5
+ *
6
+ * Provides typed access to Nuxt runtime config with proper
7
+ * separation between public (client-accessible) and private
8
+ * (server-only) values.
9
+ *
10
+ * @returns Runtime configuration object
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const env = useEnv()
15
+ * const apiUrl = env.public.apiUrl // Client-accessible
16
+ * const secretKey = env.secretKey // Server-only
17
+ * ```
18
+ */
19
+ export function useEnv() {
20
+ const config = useRuntimeConfig()
21
+
22
+ return config
23
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Error logging composable for tracking and reporting errors
3
+ *
4
+ * Features:
5
+ * - Console logging in development
6
+ * - Optional external service integration (Sentry, LogRocket, etc.)
7
+ * - Type-safe error context
8
+ * - Client-side only (no SSR logging to external services)
9
+ * - Configurable via app.config
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const { logError } = useErrorLog()
14
+ *
15
+ * try {
16
+ * await riskyOperation()
17
+ * } catch (error) {
18
+ * logError(error, { context: 'riskyOperation', userId: '123' })
19
+ * }
20
+ * ```
21
+ */
22
+
23
+ export interface ErrorContext {
24
+ /** Component name where error occurred */
25
+ component?: string
26
+ /** Additional context information */
27
+ info?: string
28
+ /** User ID (if available) */
29
+ userId?: string
30
+ /** Route path where error occurred */
31
+ route?: string
32
+ /** Custom metadata */
33
+ [key: string]: unknown
34
+ }
35
+
36
+ export interface ErrorLogConfig {
37
+ /** Enable console logging in development */
38
+ logToConsole?: boolean
39
+ /** Enable external error service logging */
40
+ logToExternal?: boolean
41
+ /** External error service URL */
42
+ externalUrl?: string
43
+ /** External error service token/key */
44
+ externalToken?: string
45
+ }
46
+
47
+ export function useErrorLog() {
48
+ const appConfig = useAppConfig()
49
+ const route = useRoute()
50
+
51
+ // Get error log configuration from app.config
52
+ const config = computed(() => {
53
+ const coreLayer = appConfig.coreLayer as { errors?: ErrorLogConfig } | undefined
54
+ return {
55
+ logToConsole: coreLayer?.errors?.logToConsole ?? true,
56
+ logToExternal: coreLayer?.errors?.logToExternal ?? false,
57
+ externalUrl: coreLayer?.errors?.externalUrl,
58
+ externalToken: coreLayer?.errors?.externalToken,
59
+ }
60
+ })
61
+
62
+ /**
63
+ * Log an error with optional context
64
+ */
65
+ const logError = (error: unknown, context?: ErrorContext) => {
66
+ // Normalize error to Error object
67
+ const errorObj = error instanceof Error ? error : new Error(String(error))
68
+
69
+ // Build full context
70
+ const fullContext: ErrorContext = {
71
+ route: route.path,
72
+ timestamp: new Date().toISOString(),
73
+ userAgent: import.meta.client ? navigator.userAgent : 'SSR',
74
+ ...context,
75
+ }
76
+
77
+ // Console logging (development only by default)
78
+ if (config.value.logToConsole && import.meta.dev) {
79
+ // eslint-disable-next-line no-console
80
+ console.group('🔴 Error Logged')
81
+ // eslint-disable-next-line no-console
82
+ console.error('Error:', errorObj)
83
+ // eslint-disable-next-line no-console
84
+ console.log('Context:', fullContext)
85
+ // eslint-disable-next-line no-console
86
+ console.groupEnd()
87
+ }
88
+
89
+ // External logging (client-side only, production)
90
+ if (config.value.logToExternal && import.meta.client) {
91
+ sendToExternalService(errorObj, fullContext)
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Send error to external error tracking service
97
+ */
98
+ const sendToExternalService = async (error: Error, context: ErrorContext) => {
99
+ const { externalUrl, externalToken } = config.value
100
+
101
+ if (!externalUrl) {
102
+ // eslint-disable-next-line no-console
103
+ console.warn('Error logging enabled but no externalUrl configured')
104
+ return
105
+ }
106
+
107
+ try {
108
+ await $fetch(externalUrl, {
109
+ method: 'POST',
110
+ headers: {
111
+ 'Content-Type': 'application/json',
112
+ ...(externalToken ? { Authorization: `Bearer ${externalToken}` } : {}),
113
+ },
114
+ body: {
115
+ error: {
116
+ name: error.name,
117
+ message: error.message,
118
+ stack: error.stack,
119
+ },
120
+ context,
121
+ },
122
+ })
123
+ } catch (loggingError) {
124
+ // Don't let logging errors crash the app
125
+ if (import.meta.dev) {
126
+ // eslint-disable-next-line no-console
127
+ console.error('Failed to send error to external service:', loggingError)
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Log a warning (non-critical error)
134
+ */
135
+ const logWarning = (message: string, context?: ErrorContext) => {
136
+ if (config.value.logToConsole && import.meta.dev) {
137
+ // eslint-disable-next-line no-console
138
+ console.warn('⚠️ Warning:', message, context)
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Log info (for debugging)
144
+ */
145
+ const logInfo = (message: string, data?: unknown) => {
146
+ if (config.value.logToConsole && import.meta.dev) {
147
+ // eslint-disable-next-line no-console
148
+ console.log('ℹ️ Info:', message, data)
149
+ }
150
+ }
151
+
152
+ return {
153
+ logError,
154
+ logWarning,
155
+ logInfo,
156
+ config: readonly(config),
157
+ }
158
+ }
@@ -0,0 +1,269 @@
1
+ // composables/useFeatures.ts
2
+ import {
3
+ usePreferredContrast,
4
+ usePreferredDark,
5
+ usePreferredReducedMotion,
6
+ useSessionStorage,
7
+ } from '@vueuse/core'
8
+ import type { FeatureDetection } from '#layers/core/app/types/detection'
9
+
10
+ /**
11
+ * Check if CSS feature is supported
12
+ */
13
+ function checkCSSSupport(property: string, value?: string): boolean {
14
+ if (!import.meta.client || !window.CSS?.supports) return false
15
+ if (value === undefined) {
16
+ // Single-argument form (e.g., "display: flex")
17
+ return window.CSS.supports(property)
18
+ }
19
+ return window.CSS.supports(property, value)
20
+ }
21
+
22
+ /**
23
+ * Check if :has() selector is supported
24
+ * CSS.supports() doesn't reliably detect selector support, so we test directly
25
+ */
26
+ function checkHasSupport(): boolean {
27
+ if (!import.meta.client) return false
28
+ try {
29
+ document.querySelector(':has(*)')
30
+ return true
31
+ } catch {
32
+ return false
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Check if JS API is available
38
+ */
39
+ function checkAPI(api: string): boolean {
40
+ if (!import.meta.client) return false
41
+ return api in window
42
+ }
43
+
44
+ /**
45
+ * Get default/empty feature detection object
46
+ */
47
+ function getDefaultFeatures(): FeatureDetection {
48
+ return {
49
+ // CSS Features
50
+ grid: false,
51
+ subgrid: false,
52
+ containerQueries: false,
53
+ has: false,
54
+ aspectRatio: false,
55
+ logicalProperties: false,
56
+ backdropFilter: false,
57
+
58
+ // JS APIs
59
+ intersectionObserver: false,
60
+ resizeObserver: false,
61
+ serviceWorker: false,
62
+ webGL: false,
63
+
64
+ // User Preferences
65
+ darkMode: false,
66
+ reducedMotion: false,
67
+ highContrast: false,
68
+
69
+ // Image Formats
70
+ webp: false,
71
+ avif: false,
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Detect all features (client-side only)
77
+ */
78
+ function detectFeatures(): FeatureDetection {
79
+ // Return defaults if not on client
80
+ if (!import.meta.client) {
81
+ return getDefaultFeatures()
82
+ }
83
+
84
+ // Detect features
85
+ const features: FeatureDetection = {
86
+ // CSS Features
87
+ grid: checkCSSSupport('display', 'grid'),
88
+ subgrid: checkCSSSupport('grid-template-columns', 'subgrid'),
89
+ containerQueries: checkCSSSupport('container-type', 'inline-size'),
90
+ has: checkHasSupport(),
91
+ aspectRatio: checkCSSSupport('aspect-ratio', '1/1'),
92
+ logicalProperties: checkCSSSupport('margin-inline-start', '1px'),
93
+ backdropFilter: checkCSSSupport('backdrop-filter', 'blur(1px)'),
94
+
95
+ // JS APIs
96
+ intersectionObserver: checkAPI('IntersectionObserver'),
97
+ resizeObserver: checkAPI('ResizeObserver'),
98
+ serviceWorker: 'serviceWorker' in navigator,
99
+ webGL: !!(
100
+ document.createElement('canvas').getContext('webgl') ||
101
+ document.createElement('canvas').getContext('experimental-webgl')
102
+ ),
103
+
104
+ // User Preferences (will be set reactively)
105
+ darkMode: false,
106
+ reducedMotion: false,
107
+ highContrast: false,
108
+
109
+ // Image Formats (will be checked async)
110
+ webp: false,
111
+ avif: false,
112
+ }
113
+
114
+ return features
115
+ }
116
+
117
+ /**
118
+ * Check if image format is supported
119
+ */
120
+ async function checkImageFormat(format: 'webp' | 'avif'): Promise<boolean> {
121
+ if (!import.meta.client) return false
122
+
123
+ const testImages = {
124
+ webp: 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=',
125
+ avif: 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=',
126
+ }
127
+
128
+ return new Promise((resolve) => {
129
+ const img = new Image()
130
+ img.onload = () => resolve(img.width > 0 && img.height > 0)
131
+ img.onerror = () => resolve(false)
132
+ img.src = testImages[format]
133
+ })
134
+ }
135
+
136
+ /**
137
+ * Add feature classes to <html> element
138
+ */
139
+ function applyFeatureClasses(features: FeatureDetection) {
140
+ if (!import.meta.client || !document.documentElement) return
141
+
142
+ // Remove old classes first
143
+ const htmlClasses = document.documentElement.classList
144
+ const classesToRemove = Array.from(htmlClasses).filter(
145
+ (cls) => cls.startsWith('supports-') || cls.startsWith('no-') || cls.startsWith('has-')
146
+ )
147
+ htmlClasses.remove(...classesToRemove)
148
+
149
+ const classes: string[] = []
150
+
151
+ // CSS features
152
+ classes.push(features.grid ? 'supports-grid' : 'no-grid')
153
+ classes.push(features.subgrid ? 'supports-subgrid' : 'no-subgrid')
154
+ classes.push(features.containerQueries ? 'supports-container-queries' : 'no-container-queries')
155
+ classes.push(features.has ? 'supports-has' : 'no-has')
156
+ classes.push(features.aspectRatio ? 'supports-aspect-ratio' : 'no-aspect-ratio')
157
+ classes.push(features.backdropFilter ? 'supports-backdrop-filter' : 'no-backdrop-filter')
158
+
159
+ // JS APIs
160
+ if (features.intersectionObserver) classes.push('has-intersection-observer')
161
+ if (features.resizeObserver) classes.push('has-resize-observer')
162
+ if (features.serviceWorker) classes.push('has-service-worker')
163
+ if (features.webGL) classes.push('has-webgl')
164
+
165
+ // Image formats
166
+ if (features.webp) classes.push('supports-webp')
167
+ if (features.avif) classes.push('supports-avif')
168
+
169
+ htmlClasses.add(...classes)
170
+ }
171
+
172
+ /**
173
+ * Feature detection composable
174
+ *
175
+ * Detects CSS features, JS APIs, user preferences, and image format support.
176
+ * Results are cached in sessionStorage (reactive via VueUse) and CSS classes are added to <html>.
177
+ *
178
+ * @returns Feature detection state
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const { grid, subgrid, webp, darkMode } = useFeatures()
183
+ *
184
+ * if (!subgrid) {
185
+ * // Use fallback layout
186
+ * }
187
+ * ```
188
+ */
189
+ export function useFeatures() {
190
+ // Use VueUse's reactive sessionStorage with lazy initialization
191
+ const features = useSessionStorage<FeatureDetection>(
192
+ 'core-layer:features',
193
+ getDefaultFeatures(), // Start with defaults
194
+ {
195
+ mergeDefaults: true,
196
+ }
197
+ )
198
+
199
+ // User preferences (reactive via VueUse)
200
+ const prefersDark = usePreferredDark()
201
+ const prefersReducedMotion = usePreferredReducedMotion()
202
+ const prefersContrast = usePreferredContrast()
203
+
204
+ // Only run detection on client
205
+ if (import.meta.client) {
206
+ // Detect features immediately on client
207
+ const detected = detectFeatures()
208
+ features.value = detected
209
+
210
+ // Apply initial classes
211
+ applyFeatureClasses(features.value)
212
+
213
+ // Watch for changes and reapply classes
214
+ watch(
215
+ features,
216
+ (newFeatures) => {
217
+ applyFeatureClasses(newFeatures)
218
+ },
219
+ { deep: true }
220
+ )
221
+
222
+ // Detect image formats asynchronously
223
+ Promise.all([checkImageFormat('webp'), checkImageFormat('avif')]).then(([webp, avif]) => {
224
+ features.value.webp = webp
225
+ features.value.avif = avif
226
+ })
227
+ }
228
+
229
+ // Update user preference flags reactively
230
+ watch(
231
+ [prefersDark, prefersReducedMotion, prefersContrast],
232
+ () => {
233
+ features.value.darkMode = prefersDark.value
234
+ features.value.reducedMotion = prefersReducedMotion.value === 'reduce'
235
+ features.value.highContrast = prefersContrast.value === 'more'
236
+ },
237
+ { immediate: true }
238
+ )
239
+
240
+ // Return individual feature flags as computed refs
241
+ return {
242
+ // CSS Features
243
+ grid: computed(() => features.value.grid),
244
+ subgrid: computed(() => features.value.subgrid),
245
+ containerQueries: computed(() => features.value.containerQueries),
246
+ has: computed(() => features.value.has),
247
+ aspectRatio: computed(() => features.value.aspectRatio),
248
+ logicalProperties: computed(() => features.value.logicalProperties),
249
+ backdropFilter: computed(() => features.value.backdropFilter),
250
+
251
+ // JS APIs
252
+ intersectionObserver: computed(() => features.value.intersectionObserver),
253
+ resizeObserver: computed(() => features.value.resizeObserver),
254
+ serviceWorker: computed(() => features.value.serviceWorker),
255
+ webGL: computed(() => features.value.webGL),
256
+
257
+ // User Preferences (reactive)
258
+ darkMode: prefersDark,
259
+ reducedMotion: computed(() => prefersReducedMotion.value === 'reduce'),
260
+ highContrast: computed(() => prefersContrast.value === 'more'),
261
+
262
+ // Image Formats
263
+ webp: computed(() => features.value.webp),
264
+ avif: computed(() => features.value.avif),
265
+
266
+ // Expose the reactive storage for advanced use (e.g., clearing cache)
267
+ _storage: features,
268
+ }
269
+ }