bsmnt 0.0.2 → 0.1.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 (430) hide show
  1. package/.github/workflows/release.yml +2 -0
  2. package/CHANGELOG.md +21 -0
  3. package/CLAUDE.md +42 -23
  4. package/README.md +33 -11
  5. package/biome.json +1 -0
  6. package/bun.lock +1 -1
  7. package/docs/architecture.drawio +266 -0
  8. package/docs/architecture.mermaid +91 -0
  9. package/package.json +1 -1
  10. package/{bin → packages/cli/bin}/index.js +28 -27
  11. package/packages/cli/package.json +16 -0
  12. package/{src → packages/cli/src}/commands/add-integration.js +23 -25
  13. package/{src → packages/cli/src}/commands/create.js +104 -133
  14. package/packages/create-basement-app/integrations/basehub/config.js +21 -0
  15. package/packages/create-basement-app/integrations/sanity/config.js +46 -0
  16. package/{src → packages/create-basement-app/integrations/sanity}/mergers/check-integration-merger.js +1 -1
  17. package/{src → packages/create-basement-app/integrations/sanity}/mergers/layout-merger.js +1 -1
  18. package/{src → packages/create-basement-app/integrations/sanity}/mergers/sitemap-merger.js +1 -1
  19. package/packages/create-basement-app/package.json +10 -0
  20. package/packages/create-basement-app/src/configs/animations.js +28 -0
  21. package/packages/create-basement-app/src/index.js +15 -0
  22. package/packages/create-basement-app/src/mergers/check-integration-merger.js +105 -0
  23. package/{src → packages/create-basement-app/src}/mergers/config.js +1 -7
  24. package/{src → packages/create-basement-app/src}/mergers/index.js +87 -93
  25. package/packages/create-basement-app/src/mergers/layout-merger.js +223 -0
  26. package/packages/create-basement-app/src/mergers/sitemap-merger.js +121 -0
  27. package/packages/create-basement-app/template-hooks/config.js +38 -0
  28. package/packages/create-basement-app/templates/default/.biome/plugins/README.md +21 -0
  29. package/packages/create-basement-app/templates/default/.biome/plugins/no-anchor-element.grit +12 -0
  30. package/packages/create-basement-app/templates/default/.biome/plugins/no-relative-parent-imports.grit +10 -0
  31. package/packages/create-basement-app/templates/default/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
  32. package/packages/create-basement-app/templates/default/.cursor/rules/README.md +184 -0
  33. package/packages/create-basement-app/templates/default/.cursor/rules/architecture.mdc +437 -0
  34. package/packages/create-basement-app/templates/default/.cursor/rules/components.mdc +436 -0
  35. package/packages/create-basement-app/templates/default/.cursor/rules/integrations.mdc +447 -0
  36. package/packages/create-basement-app/templates/default/.cursor/rules/main.mdc +278 -0
  37. package/packages/create-basement-app/templates/default/.cursor/rules/styling.mdc +433 -0
  38. package/packages/create-basement-app/templates/default/.editorconfig +40 -0
  39. package/packages/create-basement-app/templates/default/.env.example +81 -0
  40. package/packages/create-basement-app/templates/default/.gitattributes +19 -0
  41. package/packages/create-basement-app/templates/default/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  42. package/packages/create-basement-app/templates/default/.github/workflows/lighthouse-to-slack.yml +136 -0
  43. package/packages/create-basement-app/templates/default/.vscode/extensions.json +20 -0
  44. package/packages/create-basement-app/templates/default/.vscode/settings.json +105 -0
  45. package/packages/create-basement-app/templates/default/README.md +221 -0
  46. package/packages/create-basement-app/templates/default/_gitignore +67 -0
  47. package/packages/create-basement-app/templates/default/app/favicon.ico +0 -0
  48. package/packages/create-basement-app/templates/default/app/layout.tsx +104 -0
  49. package/packages/create-basement-app/templates/default/app/page.tsx +275 -0
  50. package/packages/create-basement-app/templates/default/app/robots.ts +15 -0
  51. package/packages/create-basement-app/templates/default/app/sitemap.ts +16 -0
  52. package/packages/create-basement-app/templates/default/biome.json +250 -0
  53. package/packages/create-basement-app/templates/default/components/basement.svg +1 -0
  54. package/packages/create-basement-app/templates/default/components/layout/footer/index.tsx +27 -0
  55. package/packages/create-basement-app/templates/default/components/layout/header/index.tsx +11 -0
  56. package/packages/create-basement-app/templates/default/components/layout/theme/index.tsx +66 -0
  57. package/packages/create-basement-app/templates/default/components/layout/wrapper/index.tsx +65 -0
  58. package/packages/create-basement-app/templates/default/components/ui/README.md +77 -0
  59. package/packages/create-basement-app/templates/default/components/ui/image/README.md +37 -0
  60. package/packages/create-basement-app/templates/default/components/ui/image/index.tsx +224 -0
  61. package/packages/create-basement-app/templates/default/components/ui/link/index.tsx +146 -0
  62. package/packages/create-basement-app/templates/default/lib/README.md +33 -0
  63. package/packages/create-basement-app/templates/default/lib/hooks/index.ts +12 -0
  64. package/packages/create-basement-app/templates/default/lib/hooks/use-device-detection.ts +81 -0
  65. package/packages/create-basement-app/templates/default/lib/hooks/use-media-breakpoint.ts +15 -0
  66. package/packages/create-basement-app/templates/default/lib/hooks/use-prefetch.ts +74 -0
  67. package/packages/create-basement-app/templates/default/lib/scripts/dev.ts +52 -0
  68. package/packages/create-basement-app/templates/default/lib/scripts/generate-component.ts +322 -0
  69. package/packages/create-basement-app/templates/default/lib/scripts/generate-page.ts +193 -0
  70. package/packages/create-basement-app/templates/default/lib/scripts/generate.ts +79 -0
  71. package/packages/create-basement-app/templates/default/lib/scripts/utils.ts +246 -0
  72. package/packages/create-basement-app/templates/default/lib/store/app.ts +11 -0
  73. package/packages/create-basement-app/templates/default/lib/store/index.ts +11 -0
  74. package/packages/create-basement-app/templates/default/lib/styles/README.md +64 -0
  75. package/packages/create-basement-app/templates/default/lib/styles/cn.ts +7 -0
  76. package/packages/create-basement-app/templates/default/lib/styles/colors.ts +63 -0
  77. package/packages/create-basement-app/templates/default/lib/styles/config.ts +34 -0
  78. package/packages/create-basement-app/templates/default/lib/styles/css/global.css +85 -0
  79. package/packages/create-basement-app/templates/default/lib/styles/css/index.css +6 -0
  80. package/packages/create-basement-app/templates/default/lib/styles/css/reset.css +166 -0
  81. package/packages/create-basement-app/templates/default/lib/styles/css/root.css +68 -0
  82. package/packages/create-basement-app/templates/default/lib/styles/css/tailwind.css +132 -0
  83. package/packages/create-basement-app/templates/default/lib/styles/easings.ts +21 -0
  84. package/packages/create-basement-app/templates/default/lib/styles/fonts.ts +28 -0
  85. package/packages/create-basement-app/templates/default/lib/styles/index.ts +12 -0
  86. package/packages/create-basement-app/templates/default/lib/styles/layout.mjs +27 -0
  87. package/packages/create-basement-app/templates/default/lib/styles/scripts/README.md +29 -0
  88. package/packages/create-basement-app/templates/default/lib/styles/scripts/generate-root.ts +57 -0
  89. package/packages/create-basement-app/templates/default/lib/styles/scripts/generate-tailwind.ts +162 -0
  90. package/packages/create-basement-app/templates/default/lib/styles/scripts/postcss-functions.mjs +168 -0
  91. package/packages/create-basement-app/templates/default/lib/styles/scripts/setup-styles.ts +24 -0
  92. package/packages/create-basement-app/templates/default/lib/styles/scripts/utils.ts +20 -0
  93. package/packages/create-basement-app/templates/default/lib/styles/typography.ts +36 -0
  94. package/packages/create-basement-app/templates/default/lib/utils/README.md +40 -0
  95. package/packages/create-basement-app/templates/default/lib/utils/css.d.ts +21 -0
  96. package/packages/create-basement-app/templates/default/lib/utils/easings.ts +240 -0
  97. package/packages/create-basement-app/templates/default/lib/utils/fetch.ts +84 -0
  98. package/packages/create-basement-app/templates/default/lib/utils/math.test.ts +221 -0
  99. package/packages/create-basement-app/templates/default/lib/utils/math.ts +236 -0
  100. package/packages/create-basement-app/templates/default/lib/utils/metadata.ts +126 -0
  101. package/packages/create-basement-app/templates/default/lib/utils/strings.test.ts +166 -0
  102. package/packages/create-basement-app/templates/default/lib/utils/strings.ts +246 -0
  103. package/packages/create-basement-app/templates/default/lib/utils/types.d.ts +15 -0
  104. package/packages/create-basement-app/templates/default/lib/utils/viewport.test.ts +256 -0
  105. package/packages/create-basement-app/templates/default/lib/utils/viewport.ts +193 -0
  106. package/packages/create-basement-app/templates/default/next.config.ts +142 -0
  107. package/packages/create-basement-app/templates/default/package.json +62 -0
  108. package/packages/create-basement-app/templates/default/postcss.config.mjs +42 -0
  109. package/packages/create-basement-app/templates/default/public/fonts/geist/Geist-Mono.woff2 +0 -0
  110. package/packages/create-basement-app/templates/default/tsconfig.json +43 -0
  111. package/packages/create-basement-app/templates/experiment/.biome/plugins/README.md +21 -0
  112. package/packages/create-basement-app/templates/experiment/.biome/plugins/no-anchor-element.grit +12 -0
  113. package/packages/create-basement-app/templates/experiment/.biome/plugins/no-relative-parent-imports.grit +10 -0
  114. package/packages/create-basement-app/templates/experiment/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
  115. package/packages/create-basement-app/templates/experiment/.cursor/rules/README.md +184 -0
  116. package/packages/create-basement-app/templates/experiment/.cursor/rules/architecture.mdc +437 -0
  117. package/packages/create-basement-app/templates/experiment/.cursor/rules/components.mdc +436 -0
  118. package/packages/create-basement-app/templates/experiment/.cursor/rules/integrations.mdc +447 -0
  119. package/packages/create-basement-app/templates/experiment/.cursor/rules/main.mdc +278 -0
  120. package/packages/create-basement-app/templates/experiment/.cursor/rules/styling.mdc +433 -0
  121. package/packages/create-basement-app/templates/experiment/.editorconfig +40 -0
  122. package/packages/create-basement-app/templates/experiment/.env.example +81 -0
  123. package/packages/create-basement-app/templates/experiment/.gitattributes +19 -0
  124. package/packages/create-basement-app/templates/experiment/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  125. package/packages/create-basement-app/templates/experiment/.github/workflows/lighthouse-to-slack.yml +136 -0
  126. package/packages/create-basement-app/templates/experiment/.vscode/extensions.json +20 -0
  127. package/packages/create-basement-app/templates/experiment/.vscode/settings.json +105 -0
  128. package/packages/create-basement-app/templates/experiment/README.md +221 -0
  129. package/packages/create-basement-app/templates/experiment/_gitignore +67 -0
  130. package/packages/create-basement-app/templates/experiment/app/favicon.ico +0 -0
  131. package/packages/create-basement-app/templates/experiment/app/layout.tsx +104 -0
  132. package/packages/create-basement-app/templates/experiment/app/page.tsx +275 -0
  133. package/packages/create-basement-app/templates/experiment/app/robots.ts +15 -0
  134. package/packages/create-basement-app/templates/experiment/app/sitemap.ts +16 -0
  135. package/packages/create-basement-app/templates/experiment/biome.json +250 -0
  136. package/packages/create-basement-app/templates/experiment/components/basement.svg +1 -0
  137. package/packages/create-basement-app/templates/experiment/components/layout/footer/index.tsx +27 -0
  138. package/packages/create-basement-app/templates/experiment/components/layout/header/index.tsx +58 -0
  139. package/packages/create-basement-app/templates/experiment/components/layout/navigation-menu.tsx +127 -0
  140. package/packages/create-basement-app/templates/experiment/components/layout/theme/index.tsx +66 -0
  141. package/packages/create-basement-app/templates/experiment/components/layout/wrapper/index.tsx +65 -0
  142. package/packages/create-basement-app/templates/experiment/components/ui/README.md +77 -0
  143. package/packages/create-basement-app/templates/experiment/components/ui/image/README.md +37 -0
  144. package/packages/create-basement-app/templates/experiment/components/ui/image/index.tsx +224 -0
  145. package/packages/create-basement-app/templates/experiment/components/ui/link/index.tsx +146 -0
  146. package/packages/create-basement-app/templates/experiment/lib/README.md +33 -0
  147. package/packages/create-basement-app/templates/experiment/lib/constants.ts +12 -0
  148. package/packages/create-basement-app/templates/experiment/lib/hooks/index.ts +12 -0
  149. package/packages/create-basement-app/templates/experiment/lib/hooks/use-device-detection.ts +81 -0
  150. package/packages/create-basement-app/templates/experiment/lib/hooks/use-media-breakpoint.ts +15 -0
  151. package/packages/create-basement-app/templates/experiment/lib/hooks/use-prefetch.ts +74 -0
  152. package/packages/create-basement-app/templates/experiment/lib/integrations/.gitkeep +0 -0
  153. package/packages/create-basement-app/templates/experiment/lib/scripts/dev.ts +52 -0
  154. package/packages/create-basement-app/templates/experiment/lib/scripts/generate-component.ts +322 -0
  155. package/packages/create-basement-app/templates/experiment/lib/scripts/generate-page.ts +193 -0
  156. package/packages/create-basement-app/templates/experiment/lib/scripts/generate.ts +79 -0
  157. package/packages/create-basement-app/templates/experiment/lib/scripts/utils.ts +246 -0
  158. package/packages/create-basement-app/templates/experiment/lib/store/app.ts +11 -0
  159. package/packages/create-basement-app/templates/experiment/lib/store/index.ts +11 -0
  160. package/packages/create-basement-app/templates/experiment/lib/styles/README.md +64 -0
  161. package/packages/create-basement-app/templates/experiment/lib/styles/cn.ts +7 -0
  162. package/packages/create-basement-app/templates/experiment/lib/styles/colors.ts +63 -0
  163. package/packages/create-basement-app/templates/experiment/lib/styles/config.ts +34 -0
  164. package/packages/create-basement-app/templates/experiment/lib/styles/css/global.css +85 -0
  165. package/packages/create-basement-app/templates/experiment/lib/styles/css/index.css +6 -0
  166. package/packages/create-basement-app/templates/experiment/lib/styles/css/reset.css +166 -0
  167. package/packages/create-basement-app/templates/experiment/lib/styles/css/root.css +68 -0
  168. package/packages/create-basement-app/templates/experiment/lib/styles/css/tailwind.css +132 -0
  169. package/packages/create-basement-app/templates/experiment/lib/styles/easings.ts +21 -0
  170. package/packages/create-basement-app/templates/experiment/lib/styles/fonts.ts +28 -0
  171. package/packages/create-basement-app/templates/experiment/lib/styles/index.ts +12 -0
  172. package/packages/create-basement-app/templates/experiment/lib/styles/layout.mjs +27 -0
  173. package/packages/create-basement-app/templates/experiment/lib/styles/scripts/README.md +29 -0
  174. package/packages/create-basement-app/templates/experiment/lib/styles/scripts/generate-root.ts +57 -0
  175. package/packages/create-basement-app/templates/experiment/lib/styles/scripts/generate-tailwind.ts +162 -0
  176. package/packages/create-basement-app/templates/experiment/lib/styles/scripts/postcss-functions.mjs +168 -0
  177. package/packages/create-basement-app/templates/experiment/lib/styles/scripts/setup-styles.ts +24 -0
  178. package/packages/create-basement-app/templates/experiment/lib/styles/scripts/utils.ts +20 -0
  179. package/packages/create-basement-app/templates/experiment/lib/styles/typography.ts +36 -0
  180. package/packages/create-basement-app/templates/experiment/lib/utils/README.md +40 -0
  181. package/packages/create-basement-app/templates/experiment/lib/utils/css.d.ts +21 -0
  182. package/packages/create-basement-app/templates/experiment/lib/utils/easings.ts +240 -0
  183. package/packages/create-basement-app/templates/experiment/lib/utils/fetch.ts +84 -0
  184. package/packages/create-basement-app/templates/experiment/lib/utils/math.test.ts +221 -0
  185. package/packages/create-basement-app/templates/experiment/lib/utils/math.ts +236 -0
  186. package/packages/create-basement-app/templates/experiment/lib/utils/metadata.ts +126 -0
  187. package/packages/create-basement-app/templates/experiment/lib/utils/strings.test.ts +166 -0
  188. package/packages/create-basement-app/templates/experiment/lib/utils/strings.ts +246 -0
  189. package/packages/create-basement-app/templates/experiment/lib/utils/types.d.ts +15 -0
  190. package/packages/create-basement-app/templates/experiment/lib/utils/viewport.test.ts +256 -0
  191. package/packages/create-basement-app/templates/experiment/lib/utils/viewport.ts +193 -0
  192. package/packages/create-basement-app/templates/experiment/next.config.ts +142 -0
  193. package/packages/create-basement-app/templates/experiment/package.json +69 -0
  194. package/packages/create-basement-app/templates/experiment/postcss.config.mjs +42 -0
  195. package/packages/create-basement-app/templates/experiment/public/fonts/geist/Geist-Mono.woff2 +0 -0
  196. package/packages/create-basement-app/templates/experiment/tsconfig.json +43 -0
  197. package/packages/create-basement-app/templates/webgl/.biome/plugins/README.md +21 -0
  198. package/packages/create-basement-app/templates/webgl/.biome/plugins/no-anchor-element.grit +12 -0
  199. package/packages/create-basement-app/templates/webgl/.biome/plugins/no-relative-parent-imports.grit +10 -0
  200. package/packages/create-basement-app/templates/webgl/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
  201. package/packages/create-basement-app/templates/webgl/.cursor/rules/README.md +184 -0
  202. package/packages/create-basement-app/templates/webgl/.cursor/rules/architecture.mdc +437 -0
  203. package/packages/create-basement-app/templates/webgl/.cursor/rules/components.mdc +436 -0
  204. package/packages/create-basement-app/templates/webgl/.cursor/rules/integrations.mdc +447 -0
  205. package/packages/create-basement-app/templates/webgl/.cursor/rules/main.mdc +278 -0
  206. package/packages/create-basement-app/templates/webgl/.cursor/rules/styling.mdc +433 -0
  207. package/packages/create-basement-app/templates/webgl/.editorconfig +40 -0
  208. package/packages/create-basement-app/templates/webgl/.env.example +81 -0
  209. package/packages/create-basement-app/templates/webgl/.gitattributes +19 -0
  210. package/packages/create-basement-app/templates/webgl/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  211. package/packages/create-basement-app/templates/webgl/.github/workflows/lighthouse-to-slack.yml +136 -0
  212. package/packages/create-basement-app/templates/webgl/.vscode/extensions.json +20 -0
  213. package/packages/create-basement-app/templates/webgl/.vscode/settings.json +105 -0
  214. package/packages/create-basement-app/templates/webgl/README.md +221 -0
  215. package/packages/create-basement-app/templates/webgl/_gitignore +67 -0
  216. package/packages/create-basement-app/templates/webgl/app/favicon.ico +0 -0
  217. package/packages/create-basement-app/templates/webgl/app/layout.tsx +104 -0
  218. package/packages/create-basement-app/templates/webgl/app/page.tsx +10 -0
  219. package/packages/create-basement-app/templates/webgl/app/robots.ts +15 -0
  220. package/packages/create-basement-app/templates/webgl/app/sitemap.ts +16 -0
  221. package/packages/create-basement-app/templates/webgl/biome.json +250 -0
  222. package/packages/create-basement-app/templates/webgl/components/basement.svg +1 -0
  223. package/packages/create-basement-app/templates/webgl/components/layout/footer/index.tsx +27 -0
  224. package/packages/create-basement-app/templates/webgl/components/layout/header/index.tsx +11 -0
  225. package/packages/create-basement-app/templates/webgl/components/layout/theme/index.tsx +66 -0
  226. package/packages/create-basement-app/templates/webgl/components/layout/wrapper/index.tsx +65 -0
  227. package/packages/create-basement-app/templates/webgl/components/ui/README.md +77 -0
  228. package/packages/create-basement-app/templates/webgl/components/ui/image/README.md +37 -0
  229. package/packages/create-basement-app/templates/webgl/components/ui/image/index.tsx +224 -0
  230. package/packages/create-basement-app/templates/webgl/components/ui/link/index.tsx +146 -0
  231. package/packages/create-basement-app/templates/webgl/components/webgl/canvas/dynamic.tsx +34 -0
  232. package/packages/create-basement-app/templates/webgl/components/webgl/canvas/index.tsx +43 -0
  233. package/packages/create-basement-app/templates/webgl/components/webgl/components/scene/index.tsx +21 -0
  234. package/packages/create-basement-app/templates/webgl/lib/README.md +33 -0
  235. package/packages/create-basement-app/templates/webgl/lib/hooks/index.ts +12 -0
  236. package/packages/create-basement-app/templates/webgl/lib/hooks/use-device-detection.ts +81 -0
  237. package/packages/create-basement-app/templates/webgl/lib/hooks/use-media-breakpoint.ts +15 -0
  238. package/packages/create-basement-app/templates/webgl/lib/hooks/use-prefetch.ts +74 -0
  239. package/packages/create-basement-app/templates/webgl/lib/integrations/.gitkeep +0 -0
  240. package/packages/create-basement-app/templates/webgl/lib/scripts/dev.ts +52 -0
  241. package/packages/create-basement-app/templates/webgl/lib/scripts/generate-component.ts +322 -0
  242. package/packages/create-basement-app/templates/webgl/lib/scripts/generate-page.ts +193 -0
  243. package/packages/create-basement-app/templates/webgl/lib/scripts/generate.ts +79 -0
  244. package/packages/create-basement-app/templates/webgl/lib/scripts/utils.ts +246 -0
  245. package/packages/create-basement-app/templates/webgl/lib/store/app.ts +11 -0
  246. package/packages/create-basement-app/templates/webgl/lib/store/index.ts +11 -0
  247. package/packages/create-basement-app/templates/webgl/lib/styles/README.md +64 -0
  248. package/packages/create-basement-app/templates/webgl/lib/styles/cn.ts +7 -0
  249. package/packages/create-basement-app/templates/webgl/lib/styles/colors.ts +63 -0
  250. package/packages/create-basement-app/templates/webgl/lib/styles/config.ts +34 -0
  251. package/packages/create-basement-app/templates/webgl/lib/styles/css/global.css +85 -0
  252. package/packages/create-basement-app/templates/webgl/lib/styles/css/index.css +6 -0
  253. package/packages/create-basement-app/templates/webgl/lib/styles/css/reset.css +166 -0
  254. package/packages/create-basement-app/templates/webgl/lib/styles/css/root.css +68 -0
  255. package/packages/create-basement-app/templates/webgl/lib/styles/css/tailwind.css +132 -0
  256. package/packages/create-basement-app/templates/webgl/lib/styles/easings.ts +21 -0
  257. package/packages/create-basement-app/templates/webgl/lib/styles/fonts.ts +28 -0
  258. package/packages/create-basement-app/templates/webgl/lib/styles/index.ts +12 -0
  259. package/packages/create-basement-app/templates/webgl/lib/styles/layout.mjs +27 -0
  260. package/packages/create-basement-app/templates/webgl/lib/styles/scripts/README.md +29 -0
  261. package/packages/create-basement-app/templates/webgl/lib/styles/scripts/generate-root.ts +57 -0
  262. package/packages/create-basement-app/templates/webgl/lib/styles/scripts/generate-tailwind.ts +162 -0
  263. package/packages/create-basement-app/templates/webgl/lib/styles/scripts/postcss-functions.mjs +168 -0
  264. package/packages/create-basement-app/templates/webgl/lib/styles/scripts/setup-styles.ts +24 -0
  265. package/packages/create-basement-app/templates/webgl/lib/styles/scripts/utils.ts +20 -0
  266. package/packages/create-basement-app/templates/webgl/lib/styles/typography.ts +36 -0
  267. package/packages/create-basement-app/templates/webgl/lib/utils/README.md +40 -0
  268. package/packages/create-basement-app/templates/webgl/lib/utils/css.d.ts +21 -0
  269. package/packages/create-basement-app/templates/webgl/lib/utils/easings.ts +240 -0
  270. package/packages/create-basement-app/templates/webgl/lib/utils/fetch.ts +84 -0
  271. package/packages/create-basement-app/templates/webgl/lib/utils/math.test.ts +221 -0
  272. package/packages/create-basement-app/templates/webgl/lib/utils/math.ts +236 -0
  273. package/packages/create-basement-app/templates/webgl/lib/utils/metadata.ts +126 -0
  274. package/packages/create-basement-app/templates/webgl/lib/utils/strings.test.ts +166 -0
  275. package/packages/create-basement-app/templates/webgl/lib/utils/strings.ts +246 -0
  276. package/packages/create-basement-app/templates/webgl/lib/utils/types.d.ts +15 -0
  277. package/packages/create-basement-app/templates/webgl/lib/utils/viewport.test.ts +256 -0
  278. package/packages/create-basement-app/templates/webgl/lib/utils/viewport.ts +193 -0
  279. package/packages/create-basement-app/templates/webgl/next.config.ts +142 -0
  280. package/packages/create-basement-app/templates/webgl/package.json +68 -0
  281. package/packages/create-basement-app/templates/webgl/postcss.config.mjs +42 -0
  282. package/packages/create-basement-app/templates/webgl/public/fonts/geist/Geist-Mono.woff2 +0 -0
  283. package/packages/create-basement-app/templates/webgl/tsconfig.json +43 -0
  284. package/packages/create-basement-app/templates/webgpu/.biome/plugins/README.md +21 -0
  285. package/packages/create-basement-app/templates/webgpu/.biome/plugins/no-anchor-element.grit +12 -0
  286. package/packages/create-basement-app/templates/webgpu/.biome/plugins/no-relative-parent-imports.grit +10 -0
  287. package/packages/create-basement-app/templates/webgpu/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
  288. package/packages/create-basement-app/templates/webgpu/.cursor/rules/README.md +184 -0
  289. package/packages/create-basement-app/templates/webgpu/.cursor/rules/architecture.mdc +437 -0
  290. package/packages/create-basement-app/templates/webgpu/.cursor/rules/components.mdc +436 -0
  291. package/packages/create-basement-app/templates/webgpu/.cursor/rules/integrations.mdc +447 -0
  292. package/packages/create-basement-app/templates/webgpu/.cursor/rules/main.mdc +278 -0
  293. package/packages/create-basement-app/templates/webgpu/.cursor/rules/styling.mdc +433 -0
  294. package/packages/create-basement-app/templates/webgpu/.editorconfig +40 -0
  295. package/packages/create-basement-app/templates/webgpu/.env.example +81 -0
  296. package/packages/create-basement-app/templates/webgpu/.gitattributes +19 -0
  297. package/packages/create-basement-app/templates/webgpu/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  298. package/packages/create-basement-app/templates/webgpu/.github/workflows/lighthouse-to-slack.yml +136 -0
  299. package/packages/create-basement-app/templates/webgpu/.vscode/extensions.json +20 -0
  300. package/packages/create-basement-app/templates/webgpu/.vscode/settings.json +105 -0
  301. package/packages/create-basement-app/templates/webgpu/README.md +221 -0
  302. package/packages/create-basement-app/templates/webgpu/_gitignore +67 -0
  303. package/packages/create-basement-app/templates/webgpu/app/favicon.ico +0 -0
  304. package/packages/create-basement-app/templates/webgpu/app/layout.tsx +104 -0
  305. package/packages/create-basement-app/templates/webgpu/app/page.tsx +275 -0
  306. package/packages/create-basement-app/templates/webgpu/app/robots.ts +15 -0
  307. package/packages/create-basement-app/templates/webgpu/app/sitemap.ts +16 -0
  308. package/packages/create-basement-app/templates/webgpu/biome.json +250 -0
  309. package/packages/create-basement-app/templates/webgpu/components/basement.svg +1 -0
  310. package/packages/create-basement-app/templates/webgpu/components/layout/footer/index.tsx +27 -0
  311. package/packages/create-basement-app/templates/webgpu/components/layout/header/index.tsx +11 -0
  312. package/packages/create-basement-app/templates/webgpu/components/layout/theme/index.tsx +66 -0
  313. package/packages/create-basement-app/templates/webgpu/components/layout/wrapper/index.tsx +65 -0
  314. package/packages/create-basement-app/templates/webgpu/components/ui/README.md +77 -0
  315. package/packages/create-basement-app/templates/webgpu/components/ui/image/README.md +37 -0
  316. package/packages/create-basement-app/templates/webgpu/components/ui/image/index.tsx +224 -0
  317. package/packages/create-basement-app/templates/webgpu/components/ui/link/index.tsx +146 -0
  318. package/packages/create-basement-app/templates/webgpu/lib/README.md +33 -0
  319. package/packages/create-basement-app/templates/webgpu/lib/hooks/index.ts +12 -0
  320. package/packages/create-basement-app/templates/webgpu/lib/hooks/use-device-detection.ts +81 -0
  321. package/packages/create-basement-app/templates/webgpu/lib/hooks/use-media-breakpoint.ts +15 -0
  322. package/packages/create-basement-app/templates/webgpu/lib/hooks/use-prefetch.ts +74 -0
  323. package/packages/create-basement-app/templates/webgpu/lib/integrations/.gitkeep +0 -0
  324. package/packages/create-basement-app/templates/webgpu/lib/scripts/dev.ts +52 -0
  325. package/packages/create-basement-app/templates/webgpu/lib/scripts/generate-component.ts +322 -0
  326. package/packages/create-basement-app/templates/webgpu/lib/scripts/generate-page.ts +193 -0
  327. package/packages/create-basement-app/templates/webgpu/lib/scripts/generate.ts +79 -0
  328. package/packages/create-basement-app/templates/webgpu/lib/scripts/utils.ts +246 -0
  329. package/packages/create-basement-app/templates/webgpu/lib/store/app.ts +11 -0
  330. package/packages/create-basement-app/templates/webgpu/lib/store/index.ts +11 -0
  331. package/packages/create-basement-app/templates/webgpu/lib/styles/README.md +64 -0
  332. package/packages/create-basement-app/templates/webgpu/lib/styles/cn.ts +7 -0
  333. package/packages/create-basement-app/templates/webgpu/lib/styles/colors.ts +63 -0
  334. package/packages/create-basement-app/templates/webgpu/lib/styles/config.ts +34 -0
  335. package/packages/create-basement-app/templates/webgpu/lib/styles/css/global.css +85 -0
  336. package/packages/create-basement-app/templates/webgpu/lib/styles/css/index.css +6 -0
  337. package/packages/create-basement-app/templates/webgpu/lib/styles/css/reset.css +166 -0
  338. package/packages/create-basement-app/templates/webgpu/lib/styles/css/root.css +68 -0
  339. package/packages/create-basement-app/templates/webgpu/lib/styles/css/tailwind.css +132 -0
  340. package/packages/create-basement-app/templates/webgpu/lib/styles/easings.ts +21 -0
  341. package/packages/create-basement-app/templates/webgpu/lib/styles/fonts.ts +28 -0
  342. package/packages/create-basement-app/templates/webgpu/lib/styles/index.ts +12 -0
  343. package/packages/create-basement-app/templates/webgpu/lib/styles/layout.mjs +27 -0
  344. package/packages/create-basement-app/templates/webgpu/lib/styles/scripts/README.md +29 -0
  345. package/packages/create-basement-app/templates/webgpu/lib/styles/scripts/generate-root.ts +57 -0
  346. package/packages/create-basement-app/templates/webgpu/lib/styles/scripts/generate-tailwind.ts +162 -0
  347. package/packages/create-basement-app/templates/webgpu/lib/styles/scripts/postcss-functions.mjs +168 -0
  348. package/packages/create-basement-app/templates/webgpu/lib/styles/scripts/setup-styles.ts +24 -0
  349. package/packages/create-basement-app/templates/webgpu/lib/styles/scripts/utils.ts +20 -0
  350. package/packages/create-basement-app/templates/webgpu/lib/styles/typography.ts +36 -0
  351. package/packages/create-basement-app/templates/webgpu/lib/utils/README.md +40 -0
  352. package/packages/create-basement-app/templates/webgpu/lib/utils/css.d.ts +21 -0
  353. package/packages/create-basement-app/templates/webgpu/lib/utils/easings.ts +240 -0
  354. package/packages/create-basement-app/templates/webgpu/lib/utils/fetch.ts +84 -0
  355. package/packages/create-basement-app/templates/webgpu/lib/utils/math.test.ts +221 -0
  356. package/packages/create-basement-app/templates/webgpu/lib/utils/math.ts +236 -0
  357. package/packages/create-basement-app/templates/webgpu/lib/utils/metadata.ts +126 -0
  358. package/packages/create-basement-app/templates/webgpu/lib/utils/strings.test.ts +166 -0
  359. package/packages/create-basement-app/templates/webgpu/lib/utils/strings.ts +246 -0
  360. package/packages/create-basement-app/templates/webgpu/lib/utils/types.d.ts +15 -0
  361. package/packages/create-basement-app/templates/webgpu/lib/utils/viewport.test.ts +256 -0
  362. package/packages/create-basement-app/templates/webgpu/lib/utils/viewport.ts +193 -0
  363. package/packages/create-basement-app/templates/webgpu/next.config.ts +142 -0
  364. package/packages/create-basement-app/templates/webgpu/package.json +69 -0
  365. package/packages/create-basement-app/templates/webgpu/postcss.config.mjs +42 -0
  366. package/packages/create-basement-app/templates/webgpu/public/fonts/geist/Geist-Mono.woff2 +0 -0
  367. package/packages/create-basement-app/templates/webgpu/tsconfig.json +43 -0
  368. package/tasks/.last-branch +1 -0
  369. package/tasks/CLAUDE.md +104 -0
  370. package/tasks/archive/2026-02-09-next-starter-dynamic-layers/prd.json +153 -0
  371. package/tasks/archive/2026-02-09-next-starter-dynamic-layers/progress.txt +115 -0
  372. package/tasks/prd-project-restructure.md +375 -0
  373. package/tasks/prd.json +227 -91
  374. package/tasks/progress.txt +281 -87
  375. package/tasks/ralph.sh +113 -0
  376. package/layers/experiment/components/layout/header/index.tsx +0 -58
  377. package/layers/experiment/components/layout/navigation-menu.tsx +0 -127
  378. package/layers/experiment/lib/constants.ts +0 -12
  379. package/layers/webgl/app/page.tsx +0 -10
  380. package/layers/webgl/components/webgl/canvas/dynamic.tsx +0 -34
  381. package/layers/webgl/components/webgl/canvas/index.tsx +0 -43
  382. package/layers/webgl/components/webgl/components/scene/index.tsx +0 -21
  383. package/src/mergers/next-config-merger.js +0 -63
  384. /package/{src → packages/cli/src}/commands/setup-sanity.js +0 -0
  385. /package/{src → packages/cli/src}/commands/worktree.js +0 -0
  386. /package/{integrations/basehub → packages/create-basement-app/integrations/basehub/files}/README.md +0 -0
  387. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/api/draft-mode/disable/route.ts +0 -0
  388. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/api/draft-mode/enable/route.ts +0 -0
  389. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/api/revalidate/route.ts +0 -0
  390. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/layout.tsx +0 -0
  391. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/sitemap.ts +0 -0
  392. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/studio/[[...tool]]/page.tsx +0 -0
  393. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/app/studio/layout.tsx +0 -0
  394. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/components/ui/sanity-image/index.tsx +0 -0
  395. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/README.md +0 -0
  396. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/check-integration.ts +0 -0
  397. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/README.md +0 -0
  398. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/client.ts +0 -0
  399. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/components/disable-draft-mode.tsx +0 -0
  400. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/components/rich-text.tsx +0 -0
  401. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/env.ts +0 -0
  402. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/live/index.tsx +0 -0
  403. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/queries.ts +0 -0
  404. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/sanity.cli.ts +0 -0
  405. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/sanity.config.ts +0 -0
  406. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/sanity.types.ts +0 -0
  407. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schema.json +0 -0
  408. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/article.ts +0 -0
  409. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/example.ts +0 -0
  410. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/index.ts +0 -0
  411. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/link.ts +0 -0
  412. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/metadata.ts +0 -0
  413. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/navigation.ts +0 -0
  414. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/page.ts +0 -0
  415. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/schemas/richText.ts +0 -0
  416. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/structure.ts +0 -0
  417. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/utils/image.ts +0 -0
  418. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/integrations/sanity/utils/link.ts +0 -0
  419. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/scripts/copy-sanity-mcp.ts +0 -0
  420. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/scripts/generate-page.ts +0 -0
  421. /package/{integrations/sanity → packages/create-basement-app/integrations/sanity/files}/lib/utils/metadata.ts +0 -0
  422. /package/{plugins → packages/create-basement-app/plugins}/README.md +0 -0
  423. /package/{plugins → packages/create-basement-app/plugins}/no-anchor-element.grit +0 -0
  424. /package/{plugins → packages/create-basement-app/plugins}/no-relative-parent-imports.grit +0 -0
  425. /package/{plugins → packages/create-basement-app/plugins}/no-unnecessary-forwardref.grit +0 -0
  426. /package/{template-hooks → packages/create-basement-app/template-hooks}/use-battery.ts +0 -0
  427. /package/{template-hooks → packages/create-basement-app/template-hooks}/use-device-perf.ts +0 -0
  428. /package/{template-hooks → packages/create-basement-app/template-hooks}/use-intersection-observer.ts +0 -0
  429. /package/{template-hooks → packages/create-basement-app/template-hooks}/use-media.ts +0 -0
  430. /package/{layers/webgpu → packages/create-basement-app/templates/default/lib/integrations}/.gitkeep +0 -0
@@ -0,0 +1,37 @@
1
+ # Image Component
2
+
3
+ Optimized images with smart loading, blur placeholders, and responsive sizing.
4
+
5
+ ## Usage
6
+
7
+ ```tsx
8
+ import { Image } from '@/components/ui/image'
9
+
10
+ // Basic
11
+ <Image src="/hero.jpg" alt="Hero" aspectRatio={16/9} />
12
+
13
+ // Priority (LCP images)
14
+ <Image src="/hero.jpg" alt="Hero" aspectRatio={16/9} priority />
15
+
16
+ // Responsive
17
+ <Image
18
+ src="/product.jpg"
19
+ alt="Product"
20
+ mobileSize="100vw"
21
+ desktopSize="33vw"
22
+ />
23
+ ```
24
+
25
+ ## Props
26
+
27
+ | Prop | Description |
28
+ |------|-------------|
29
+ | `aspectRatio` | Prevents layout shift, enables blur placeholder |
30
+ | `priority` | Eager loading for above-the-fold images |
31
+ | `mobileSize` / `desktopSize` | Responsive sizing |
32
+
33
+ ## Best Practices
34
+
35
+ - Always provide `aspectRatio` (prevents CLS)
36
+ - Use `priority` for LCP images
37
+ - Never use `next/image` directly
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Enhanced Image Component
3
+ *
4
+ * Next.js Image wrapper with optimized defaults and error handling.
5
+ * Always use this component instead of next/image directly.
6
+ */
7
+ "use client"
8
+
9
+ import cn from "clsx"
10
+ import NextImage, { type ImageProps as NextImageProps } from "next/image"
11
+ import type { CSSProperties, Ref } from "react"
12
+ import { breakpoints } from "@/lib/styles/config"
13
+ import s from "./image.module.css"
14
+
15
+ /**
16
+ * Enhanced Image component props extending Next.js Image.
17
+ *
18
+ * Adds responsive sizing, aspect ratio support, and automatic blur placeholders.
19
+ * Always use this component instead of next/image directly.
20
+ */
21
+ export type ImageProps = Omit<NextImageProps, "objectFit" | "alt"> & {
22
+ /** CSS object-fit property for image positioning */
23
+ objectFit?: CSSProperties["objectFit"]
24
+ /** Display as block element (adds display: block) */
25
+ block?: boolean
26
+ /** Size on mobile devices (e.g., "100vw", "50vw") */
27
+ mobileSize?: `${number}vw`
28
+ /** Size on desktop devices (e.g., "33vw", "25vw") */
29
+ desktopSize?: `${number}vw`
30
+ /** Ref for accessing the underlying img element */
31
+ ref?: Ref<HTMLImageElement>
32
+ /** Alt text for accessibility (required for meaningful images) */
33
+ alt?: string
34
+ /** Aspect ratio for automatic placeholder and layout stability */
35
+ aspectRatio?: number
36
+ }
37
+
38
+ // Memoize helper functions to avoid recreation
39
+ const toBase64 = (str: string) =>
40
+ typeof window === "undefined"
41
+ ? Buffer.from(str).toString("base64")
42
+ : window.btoa(str)
43
+
44
+ // Helper to generate blur placeholder with transparent background by default
45
+ const generateShimmer = (w: number, h: number) => `
46
+ <svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
47
+ <defs>
48
+ <linearGradient id="g">
49
+ <stop stop-color="rgba(255,255,255,0.1)" offset="20%" />
50
+ <stop stop-color="rgba(255,255,255,0.2)" offset="50%" />
51
+ <stop stop-color="rgba(255,255,255,0.1)" offset="70%" />
52
+ </linearGradient>
53
+ </defs>
54
+ <rect width="${w}" height="${h}" fill="rgba(0,0,0,0)" />
55
+ <rect id="r" width="${w}" height="${h}" fill="url(#g)" />
56
+ <animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
57
+ </svg>`
58
+
59
+ // Helper to determine if blur placeholder should be used
60
+ const shouldUseBlurPlaceholder = (
61
+ src: NextImageProps["src"],
62
+ placeholder: string,
63
+ blurDataURL: string | undefined
64
+ ): boolean => {
65
+ if (!src) return false
66
+ const isSvg = typeof src === "string" && src.includes(".svg")
67
+ return !isSvg && placeholder === "blur" && !blurDataURL
68
+ }
69
+
70
+ // Helper to generate blur data URL
71
+ const generateBlurDataURL = (
72
+ shouldUse: boolean,
73
+ aspectRatio: number | undefined,
74
+ existingBlurDataURL: string | undefined
75
+ ): string | undefined => {
76
+ if (!(shouldUse && aspectRatio)) return existingBlurDataURL
77
+
78
+ const shimmerSvg = generateShimmer(700, Math.round(700 / aspectRatio))
79
+ return `data:image/svg+xml;base64,${toBase64(shimmerSvg)}`
80
+ }
81
+
82
+ // Helper to determine final placeholder value
83
+ const getFinalPlaceholder = (
84
+ shouldUse: boolean,
85
+ aspectRatio: number | undefined,
86
+ blurDataURL: string | undefined,
87
+ originalPlaceholder: NextImageProps["placeholder"]
88
+ ): NextImageProps["placeholder"] => {
89
+ if (!shouldUse) {
90
+ return originalPlaceholder === "blur" && !blurDataURL
91
+ ? "empty"
92
+ : originalPlaceholder
93
+ }
94
+
95
+ return aspectRatio || blurDataURL ? "blur" : "empty"
96
+ }
97
+
98
+ /**
99
+ * Enhanced Image component with responsive sizing and automatic optimizations.
100
+ *
101
+ * Always use this component instead of next/image directly. Provides:
102
+ * - Automatic responsive sizes generation
103
+ * - Smart blur placeholders with aspect ratio support
104
+ * - Performance optimizations (lazy loading by default)
105
+ * - Preload for LCP images
106
+ *
107
+ * @param props - Image props extending Next.js Image
108
+ * @param props.aspectRatio - Aspect ratio for layout stability and blur placeholder
109
+ * @param props.mobileSize - Size on mobile (e.g., "100vw")
110
+ * @param props.desktopSize - Size on desktop (e.g., "50vw")
111
+ * @param props.block - Display as block element
112
+ * @param props.preload - Enable preloading for LCP images
113
+ *
114
+ * @example
115
+ * ```tsx
116
+ * // Basic usage with aspect ratio
117
+ * <Image
118
+ * src="/hero.jpg"
119
+ * alt="Hero image"
120
+ * aspectRatio={16/9}
121
+ * />
122
+ * ```
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * // LCP image with preload
127
+ * <Image
128
+ * src="/hero.jpg"
129
+ * alt="Hero image"
130
+ * aspectRatio={16/9}
131
+ * preload // Preloads image for LCP
132
+ * />
133
+ * ```
134
+ *
135
+ * @example
136
+ * ```tsx
137
+ * // Responsive grid image
138
+ * <Image
139
+ * src="/product.jpg"
140
+ * alt="Product"
141
+ * aspectRatio={1}
142
+ * mobileSize="100vw"
143
+ * desktopSize="33vw"
144
+ * />
145
+ * ```
146
+ */
147
+ export function Image({
148
+ style,
149
+ className,
150
+ loading,
151
+ objectFit = "cover",
152
+ quality = 90,
153
+ alt = "",
154
+ fill,
155
+ block = !fill,
156
+ width = block ? 1 : undefined,
157
+ height = block ? 1 : undefined,
158
+ mobileSize = "100vw",
159
+ desktopSize = "100vw",
160
+ sizes,
161
+ src,
162
+ unoptimized,
163
+ ref,
164
+ aspectRatio,
165
+ placeholder = "blur",
166
+ preload = false,
167
+ ...props
168
+ }: ImageProps) {
169
+ // Determine loading strategy
170
+ const finalLoading = loading ?? (preload ? "eager" : "lazy")
171
+
172
+ // Generate responsive sizes if not provided
173
+ const finalSizes =
174
+ sizes ||
175
+ `(max-width: ${breakpoints.desktop}px) ${mobileSize}, ${desktopSize}`
176
+
177
+ // Early return after hooks
178
+ if (!src) return null
179
+
180
+ // Determine SVG status and placeholder logic
181
+ const isSvg = typeof src === "string" && src.includes(".svg")
182
+ const shouldUsePlaceholder = shouldUseBlurPlaceholder(
183
+ src,
184
+ placeholder,
185
+ props.blurDataURL
186
+ )
187
+ const blurDataURL = generateBlurDataURL(
188
+ shouldUsePlaceholder,
189
+ aspectRatio,
190
+ props.blurDataURL
191
+ )
192
+ const finalPlaceholder = getFinalPlaceholder(
193
+ shouldUsePlaceholder,
194
+ aspectRatio,
195
+ props.blurDataURL,
196
+ placeholder
197
+ )
198
+
199
+ return (
200
+ <NextImage
201
+ ref={ref}
202
+ fill={!block}
203
+ {...(width !== undefined && { width })}
204
+ {...(height !== undefined && { height })}
205
+ loading={finalLoading}
206
+ quality={quality}
207
+ alt={alt}
208
+ style={{
209
+ objectFit,
210
+ ...style,
211
+ }}
212
+ className={cn(className, block && s.block)}
213
+ sizes={finalSizes}
214
+ src={src}
215
+ unoptimized={unoptimized || isSvg}
216
+ draggable={false}
217
+ onDragStart={(e) => e.preventDefault()}
218
+ {...(finalPlaceholder && { placeholder: finalPlaceholder })}
219
+ {...(blurDataURL && { blurDataURL })}
220
+ preload={preload}
221
+ {...props}
222
+ />
223
+ )
224
+ }
@@ -0,0 +1,146 @@
1
+ "use client"
2
+
3
+ import NextLink from "next/link"
4
+ import { usePathname } from "next/navigation"
5
+ import {
6
+ type AnchorHTMLAttributes,
7
+ type ComponentProps,
8
+ type MouseEvent,
9
+ useEffect,
10
+ useState,
11
+ } from "react"
12
+
13
+ // Helper to extract props safe for button elements
14
+ function getButtonProps(props: Record<string, unknown>) {
15
+ const {
16
+ href,
17
+ target,
18
+ rel,
19
+ "data-external": _dataExternal,
20
+ ...buttonProps
21
+ } = props
22
+ return buttonProps
23
+ }
24
+
25
+ // Helper to extract props safe for div elements
26
+ function getDivProps(props: Record<string, unknown>) {
27
+ const {
28
+ href,
29
+ target,
30
+ rel,
31
+ onClick,
32
+ "data-external": _dataExternal,
33
+ ...divProps
34
+ } = props
35
+ return divProps
36
+ }
37
+
38
+ type CustomLinkProps = Omit<
39
+ AnchorHTMLAttributes<HTMLAnchorElement>,
40
+ keyof ComponentProps<typeof NextLink> | "href"
41
+ > &
42
+ Omit<ComponentProps<typeof NextLink>, "href"> & {
43
+ href?: string
44
+ onClick?: (e: MouseEvent<HTMLElement>) => void
45
+ scroll?: boolean
46
+ }
47
+
48
+ export function Link({
49
+ href,
50
+ children,
51
+ onClick,
52
+ scroll = false, // Default to false to prevent scroll restoration warnings with fixed/sticky elements
53
+ ...props
54
+ }: CustomLinkProps) {
55
+ const [shouldPrefetch, setShouldPrefetch] = useState(false)
56
+ const [isExternal, setIsExternal] = useState(false)
57
+ const [isActive, setIsActive] = useState(false)
58
+
59
+ // Get pathname - deferred to avoid blocking static generation
60
+ // usePathname is safe to call but we defer the active check to useEffect
61
+ const pathname = usePathname()
62
+
63
+ useEffect(() => {
64
+ // Check if this link is active (current page)
65
+ if (href && pathname) {
66
+ setIsActive(pathname === href)
67
+ }
68
+ }, [href, pathname])
69
+
70
+ useEffect(() => {
71
+ // Skip if no href
72
+ if (!href) return
73
+
74
+ // Check if external link
75
+ try {
76
+ const url = new URL(href, window.location.href)
77
+ setIsExternal(url.host !== window.location.host)
78
+ } catch {
79
+ setIsExternal(false)
80
+ }
81
+
82
+ // Only prefetch on good connections
83
+ const connection = (
84
+ navigator as Navigator & {
85
+ connection?: { effectiveType: string; saveData: boolean }
86
+ }
87
+ ).connection
88
+ if (connection) {
89
+ const { effectiveType, saveData } = connection
90
+ setShouldPrefetch(effectiveType === "4g" && !saveData)
91
+ } else {
92
+ // Default to prefetching if API not available
93
+ setShouldPrefetch(true)
94
+ }
95
+ }, [href])
96
+
97
+ // If no href is provided but there's an onClick, render a button
98
+ if (!href && onClick) {
99
+ return (
100
+ <button
101
+ onClick={(e: MouseEvent<HTMLButtonElement>) => onClick(e)}
102
+ type="button"
103
+ {...getButtonProps(props)}
104
+ >
105
+ {children}
106
+ </button>
107
+ )
108
+ }
109
+
110
+ // If no href and no onClick, render a div
111
+ if (!href) {
112
+ return <div {...getDivProps(props)}>{children}</div>
113
+ }
114
+
115
+ // For SSR, check if it's external based on the href pattern
116
+ const isExternalSSR =
117
+ href.startsWith("http://") || href.startsWith("https://")
118
+
119
+ if (isExternalSSR || isExternal) {
120
+ return (
121
+ <a
122
+ href={href}
123
+ target="_blank"
124
+ rel="noopener noreferrer"
125
+ data-external
126
+ onClick={onClick}
127
+ {...props}
128
+ >
129
+ {children}
130
+ </a>
131
+ )
132
+ }
133
+
134
+ return (
135
+ <NextLink
136
+ href={href as ComponentProps<typeof NextLink>["href"]}
137
+ prefetch={shouldPrefetch}
138
+ scroll={scroll}
139
+ data-active={isActive || undefined}
140
+ {...(onClick && { onClick })}
141
+ {...props}
142
+ >
143
+ {children}
144
+ </NextLink>
145
+ )
146
+ }
@@ -0,0 +1,33 @@
1
+ # Lib
2
+
3
+ Non-UI code: hooks, integrations, styles, and utilities.
4
+
5
+ > **Rule**: Renders UI → `components/` · Everything else → `lib/`
6
+
7
+ ## Quick Imports
8
+
9
+ ```tsx
10
+ // Utilities - explicit imports for better tree-shaking
11
+ import { clamp, lerp } from '@/lib/utils/math'
12
+ import { slugify } from '@/lib/utils/strings'
13
+
14
+ // Styles
15
+ import { colors, themes, breakpoints } from '@/lib/styles/config'
16
+ ```
17
+
18
+ ## Directories
19
+
20
+ | Directory | Purpose | Optional? |
21
+ |-----------|---------|-----------|
22
+ | [hooks/](hooks/README.md) | React hooks + Zustand store | ❌ Core |
23
+ | [styles/](styles/README.md) | CSS & Tailwind config | ❌ Core |
24
+ | [utils/](utils/README.md) | Pure utility functions | ❌ Core |
25
+
26
+ ## Scripts
27
+
28
+ ```bash
29
+ bun dev # Start dev server
30
+ bun run generate # Generate pages/components
31
+ bun run setup:project # Configure integrations
32
+ bun setup:styles # Regenerate CSS
33
+ ```
@@ -0,0 +1,12 @@
1
+ const EXPERIMENTS = [
2
+ {
3
+ name: "EXPERIMENT 1",
4
+ path: "/experiment-1",
5
+ },
6
+ {
7
+ name: "EXPERIMENT 2",
8
+ path: "/experiment-2",
9
+ },
10
+ ]
11
+
12
+ export default EXPERIMENTS
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Custom React Hooks
3
+ *
4
+ * Import individual hooks:
5
+ * import { useDeviceDetection } from '@/hooks/use-device-detection'
6
+ *
7
+ * Or import from barrel:
8
+ * import { useDeviceDetection, usePrefetch } from '@/hooks/use-device-detection'
9
+ */
10
+
11
+ export { useDeviceDetection } from "./use-device-detection"
12
+ export { usePrefetch } from "./use-prefetch"
@@ -0,0 +1,81 @@
1
+ import { useEffect, useState } from "react"
2
+ import { useMedia } from "react-use"
3
+ import { breakpoints } from "@/lib/styles/config"
4
+
5
+ /**
6
+ * Hook for detecting device capabilities and characteristics.
7
+ *
8
+ * Provides comprehensive device detection including screen size, input methods,
9
+ * performance preferences, and browser capabilities. Useful for responsive design,
10
+ * performance optimization, and feature detection.
11
+ *
12
+ * @returns Object with device detection results
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * import { useDeviceDetection } from '@/hooks/use-device-detection'
17
+ *
18
+ * function ResponsiveComponent() {
19
+ * const {
20
+ * isMobile,
21
+ * isDesktop,
22
+ * isReducedMotion,
23
+ * isWebGL,
24
+ * isLowPowerMode,
25
+ * dpr,
26
+ * isSafari
27
+ * } = useDeviceDetection()
28
+ *
29
+ * // Adapt behavior based on device capabilities
30
+ * if (isReducedMotion) {
31
+ * // Disable animations
32
+ * }
33
+ *
34
+ * if (isWebGL && !isLowPowerMode) {
35
+ * // Enable WebGL features
36
+ * }
37
+ *
38
+ * return (
39
+ * <div>
40
+ * {isMobile ? <MobileLayout /> : <DesktopLayout />}
41
+ * {isSafari && <SafariSpecificStyles />}
42
+ * </div>
43
+ * )
44
+ * }
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * // Performance optimizations
50
+ * const { isLowPowerMode, dpr, isReducedMotion } = useDeviceDetection()
51
+ *
52
+ * // Reduce quality on low-power devices
53
+ * const quality = isLowPowerMode ? 'low' : 'high'
54
+ * const pixelRatio = Math.min(dpr || 1, 2) // Cap DPR
55
+ *
56
+ * // Respect user motion preferences
57
+ * const enableAnimations = !isReducedMotion
58
+ * ```
59
+ */
60
+ export function useDeviceDetection() {
61
+ const isMobile = useMedia(`(max-width: ${breakpoints.mobile - 1}px)`, true)
62
+ const isReducedMotion = useMedia("(prefers-reduced-motion: reduce)")
63
+ const [dpr, setDpr] = useState<number | undefined>(undefined)
64
+ const [isSafari, setIsSafari] = useState<boolean | undefined>(undefined)
65
+
66
+ // Check for low power mode with fallback for unsupported browsers
67
+ const isTouchDevice = useMedia("(any-pointer: coarse) and (hover: none)")
68
+
69
+ useEffect(() => {
70
+ setDpr(window.devicePixelRatio)
71
+ setIsSafari(/^((?!chrome|android).)*safari/i.test(navigator.userAgent))
72
+ }, [])
73
+
74
+ return {
75
+ isMobile,
76
+ isReducedMotion,
77
+ isTouchDevice,
78
+ dpr,
79
+ isSafari,
80
+ }
81
+ }
@@ -0,0 +1,15 @@
1
+ import { useMedia } from "react-use"
2
+ import { breakpoints } from "@/lib/styles/config"
3
+
4
+ /**
5
+ * Hook for detecting if the viewport is at a specific breakpoint.
6
+ *
7
+ * @param breakpoint - The breakpoint to detect
8
+ * @returns True if the viewport is at the breakpoint
9
+ */
10
+ export function useMediaBreakpoint(
11
+ breakpoint: keyof typeof breakpoints,
12
+ defaultState = false
13
+ ) {
14
+ return useMedia(`(min-width: ${breakpoints[breakpoint]}px)`, defaultState)
15
+ }
@@ -0,0 +1,74 @@
1
+ import type { Route } from "next"
2
+ import { useRouter } from "next/navigation"
3
+ import { useEffect, useRef } from "react"
4
+
5
+ /**
6
+ * Hook to prefetch a route when an element becomes visible in the viewport
7
+ * @param href - The route to prefetch
8
+ * @param options - Intersection Observer options
9
+ * @returns ref to attach to the element that should trigger prefetching
10
+ */
11
+ export function usePrefetch<T extends HTMLElement = HTMLElement>(
12
+ href: Route | null | undefined,
13
+ options?: IntersectionObserverInit
14
+ ) {
15
+ const ref = useRef<T>(null)
16
+ const router = useRouter()
17
+ const prefetchedRef = useRef(false)
18
+
19
+ useEffect(() => {
20
+ // Early return if no href or already prefetched
21
+ if (!href || prefetchedRef.current) return
22
+
23
+ const element = ref.current
24
+ if (!element) return
25
+
26
+ // Reset prefetched state when href changes
27
+ prefetchedRef.current = false
28
+
29
+ const handleIntersection = (entries: IntersectionObserverEntry[]) => {
30
+ const [entry] = entries
31
+ if (entry?.isIntersecting && !prefetchedRef.current) {
32
+ // Check network conditions before prefetching
33
+ const connection = (
34
+ navigator as Navigator & {
35
+ connection?: NetworkInformation
36
+ }
37
+ ).connection
38
+
39
+ const shouldPrefetch =
40
+ !connection ||
41
+ (connection.effectiveType !== "slow-2g" &&
42
+ connection.effectiveType !== "2g" &&
43
+ !connection.saveData)
44
+
45
+ if (shouldPrefetch) {
46
+ router.prefetch(href)
47
+ prefetchedRef.current = true
48
+ }
49
+ }
50
+ }
51
+
52
+ const observer = new IntersectionObserver(handleIntersection, {
53
+ rootMargin: "50px",
54
+ ...options,
55
+ })
56
+
57
+ observer.observe(element)
58
+
59
+ return () => {
60
+ observer.disconnect()
61
+ }
62
+ }, [href, options, router])
63
+
64
+ // Return null ref if href is not provided
65
+ return href ? ref : { current: null }
66
+ }
67
+
68
+ // TypeScript types for Network Information API
69
+ interface NetworkInformation {
70
+ readonly effectiveType: "slow-2g" | "2g" | "3g" | "4g"
71
+ readonly saveData: boolean
72
+ readonly rtt?: number
73
+ readonly downlink?: number
74
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Cross-platform parallel dev script
3
+ * Replaces npm-run-all for running multiple processes simultaneously
4
+ * Works on Windows, macOS, and Linux using Bun's native APIs
5
+ */
6
+
7
+ import { bunExecutable, colorEnv } from "./utils"
8
+
9
+ const isHttps = process.argv.includes("--https")
10
+ const isInspect = process.argv.includes("--inspect")
11
+
12
+ // Build next dev command args
13
+ const nextDevArgs = [bunExecutable, "next", "dev"]
14
+ if (isHttps) nextDevArgs.push("--experimental-https")
15
+ if (isInspect) nextDevArgs.push("--inspect")
16
+
17
+ // Build environment with FORCE_COLOR
18
+ const devEnv = colorEnv()
19
+
20
+ const processes = [
21
+ // Style watcher
22
+ Bun.spawn(
23
+ [bunExecutable, "--watch", "./lib/styles/scripts/setup-styles.ts"],
24
+ {
25
+ stdout: "inherit",
26
+ stderr: "inherit",
27
+ env: devEnv,
28
+ }
29
+ ),
30
+
31
+ // Next.js dev server
32
+ Bun.spawn(nextDevArgs, {
33
+ stdout: "inherit",
34
+ stderr: "inherit",
35
+ env: devEnv,
36
+ }),
37
+ ]
38
+
39
+ // Handle graceful shutdown
40
+ const cleanup = () => {
41
+ for (const proc of processes) {
42
+ proc.kill()
43
+ }
44
+ process.exit(0)
45
+ }
46
+
47
+ process.on("SIGINT", cleanup)
48
+ process.on("SIGTERM", cleanup)
49
+
50
+ // Wait for any process to exit (if one crashes, we want to know)
51
+ await Promise.race(processes.map((p) => p.exited))
52
+ cleanup()