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,28 @@
1
+ // packages/create-basement-app/src/configs/animations.js
2
+
3
+ /**
4
+ * Animation library configuration manifest.
5
+ * Single source of truth for animation library dependencies.
6
+ */
7
+ export const ANIMATION_CONFIG = {
8
+ gsap: {
9
+ dependencies: {
10
+ gsap: "^3.12.0",
11
+ "@gsap/react": "^2.0.0",
12
+ },
13
+ },
14
+ motion: {
15
+ dependencies: {
16
+ motion: "^12.0.0",
17
+ },
18
+ },
19
+ };
20
+
21
+ /**
22
+ * Get configuration for a specific animation library
23
+ * @param {string} name - The animation library name (e.g., 'gsap', 'motion')
24
+ * @returns {object|null} Animation configuration or null if not found
25
+ */
26
+ export function getAnimationConfig(name) {
27
+ return ANIMATION_CONFIG[name] || null;
28
+ }
@@ -0,0 +1,15 @@
1
+ // packages/create-basement-app/src/index.js
2
+
3
+ export { ANIMATION_CONFIG, getAnimationConfig } from "./configs/animations.js";
4
+ export {
5
+ CMS_CONFIG,
6
+ getCmsConfig,
7
+ getLayerConfig,
8
+ isCmsSupported,
9
+ LAYER_CONFIG,
10
+ } from "./mergers/config.js";
11
+ export {
12
+ formatMergeResults,
13
+ injectIntegration,
14
+ injectLayer,
15
+ } from "./mergers/index.js";
@@ -0,0 +1,105 @@
1
+ // packages/create-basement-app/src/mergers/check-integration-merger.js
2
+ import fs from "fs-extra";
3
+
4
+ /**
5
+ * Sanity configuration check function to add
6
+ */
7
+ const SANITY_FUNCTION = `
8
+ /**
9
+ * Check if Sanity CMS is configured
10
+ * Requires: NEXT_PUBLIC_SANITY_PROJECT_ID and NEXT_PUBLIC_SANITY_DATASET
11
+ */
12
+ export function isSanityConfigured(): boolean {
13
+ return Boolean(
14
+ process.env.NEXT_PUBLIC_SANITY_PROJECT_ID &&
15
+ process.env.NEXT_PUBLIC_SANITY_DATASET
16
+ )
17
+ }
18
+ `;
19
+
20
+ /**
21
+ * Update to getConfiguredIntegrations to include Sanity
22
+ */
23
+ const SANITY_CONFIGURED_CHECK = ` if (isSanityConfigured()) integrations.push("Sanity")`;
24
+
25
+ /**
26
+ * Update to getUnconfiguredIntegrations to include Sanity
27
+ */
28
+ const SANITY_UNCONFIGURED_CHECK = ` if (!isSanityConfigured()) integrations.push("Sanity")`;
29
+
30
+ /**
31
+ * Merge Sanity integration into template check-integration
32
+ * @param {string} templatePath - Path to the template's check-integration.ts
33
+ * @returns {Promise<{skipped?: boolean, reason?: string, success?: boolean}>}
34
+ */
35
+ export async function mergeCheckIntegration(templatePath) {
36
+ let content = await fs.readFile(templatePath, "utf-8");
37
+
38
+ // Skip if already has isSanityConfigured
39
+ if (content.includes("isSanityConfigured")) {
40
+ return { skipped: true, reason: "Already has isSanityConfigured" };
41
+ }
42
+
43
+ // 1. Add isSanityConfigured function after isAnalyticsConfigured
44
+ const analyticsMatch = content.match(
45
+ /(export function isAnalyticsConfigured\(\)[^}]+\})/s,
46
+ );
47
+ if (analyticsMatch) {
48
+ const insertPos = analyticsMatch.index + analyticsMatch[0].length;
49
+ content =
50
+ content.slice(0, insertPos) +
51
+ "\n" +
52
+ SANITY_FUNCTION +
53
+ content.slice(insertPos);
54
+ } else {
55
+ // If no isAnalyticsConfigured, add before getConfiguredIntegrations
56
+ const getConfiguredMatch = content.match(
57
+ /export function getConfiguredIntegrations/,
58
+ );
59
+ if (getConfiguredMatch) {
60
+ content =
61
+ content.slice(0, getConfiguredMatch.index) +
62
+ SANITY_FUNCTION +
63
+ "\n" +
64
+ content.slice(getConfiguredMatch.index);
65
+ } else {
66
+ // Fallback: append to end
67
+ content = `${content.trimEnd()}\n${SANITY_FUNCTION}`;
68
+ }
69
+ }
70
+
71
+ // 2. Update getConfiguredIntegrations to include Sanity check
72
+ const configuredFnMatch = content.match(
73
+ /(export function getConfiguredIntegrations\(\)[^{]*\{[\s\S]*?)(if \(isAnalyticsConfigured\(\)\))/m,
74
+ );
75
+ if (configuredFnMatch) {
76
+ const insertPos = content.indexOf(
77
+ configuredFnMatch[2],
78
+ configuredFnMatch.index,
79
+ );
80
+ content =
81
+ content.slice(0, insertPos) +
82
+ SANITY_CONFIGURED_CHECK +
83
+ "\n " +
84
+ content.slice(insertPos);
85
+ }
86
+
87
+ // 3. Update getUnconfiguredIntegrations to include Sanity check
88
+ const unconfiguredFnMatch = content.match(
89
+ /(export function getUnconfiguredIntegrations\(\)[^{]*\{[\s\S]*?)(if \(!isAnalyticsConfigured\(\)\))/m,
90
+ );
91
+ if (unconfiguredFnMatch) {
92
+ const insertPos = content.indexOf(
93
+ unconfiguredFnMatch[2],
94
+ unconfiguredFnMatch.index,
95
+ );
96
+ content =
97
+ content.slice(0, insertPos) +
98
+ SANITY_UNCONFIGURED_CHECK +
99
+ "\n " +
100
+ content.slice(insertPos);
101
+ }
102
+
103
+ await fs.writeFile(templatePath, content);
104
+ return { success: true };
105
+ }
@@ -1,4 +1,4 @@
1
- // src/mergers/config.js
1
+ // packages/create-basement-app/src/mergers/config.js
2
2
 
3
3
  /**
4
4
  * CMS-specific configuration for smart merge integration
@@ -6,9 +6,6 @@
6
6
  */
7
7
  export const CMS_CONFIG = {
8
8
  sanity: {
9
- // Git branch containing the Sanity integration files
10
- branch: "sanity-integration",
11
-
12
9
  // Files that need smart merging (exist in both template and integration)
13
10
  mergeFiles: [
14
11
  "app/layout.tsx",
@@ -31,9 +28,6 @@ export const CMS_CONFIG = {
31
28
  },
32
29
 
33
30
  basehub: {
34
- // Git branch containing the BaseHub integration files
35
- branch: "basehub-integration",
36
-
37
31
  // Files that need smart merging for BaseHub
38
32
  mergeFiles: [],
39
33
 
@@ -1,10 +1,8 @@
1
- // src/mergers/index.js
1
+ // packages/create-basement-app/src/mergers/index.js
2
2
 
3
- import os from "node:os";
4
3
  import path from "node:path";
5
4
  import { fileURLToPath } from "node:url";
6
5
  import fs from "fs-extra";
7
- import tiged from "tiged";
8
6
  import { getCmsConfig, getLayerConfig } from "./config.js";
9
7
 
10
8
  const __filename = fileURLToPath(import.meta.url);
@@ -17,13 +15,17 @@ const __dirname = path.dirname(__filename);
17
15
  const CMS_MERGERS = {
18
16
  sanity: {
19
17
  "app/layout.tsx": () =>
20
- import("./layout-merger.js").then((m) => m.mergeLayout),
18
+ import("../../integrations/sanity/mergers/layout-merger.js").then(
19
+ (m) => m.mergeLayout,
20
+ ),
21
21
  "app/sitemap.ts": () =>
22
- import("./sitemap-merger.js").then((m) => m.mergeSitemap),
23
- "lib/integrations/check-integration.ts": () =>
24
- import("./check-integration-merger.js").then(
25
- (m) => m.mergeCheckIntegration,
22
+ import("../../integrations/sanity/mergers/sitemap-merger.js").then(
23
+ (m) => m.mergeSitemap,
26
24
  ),
25
+ "lib/integrations/check-integration.ts": () =>
26
+ import(
27
+ "../../integrations/sanity/mergers/check-integration-merger.js"
28
+ ).then((m) => m.mergeCheckIntegration),
27
29
  },
28
30
  basehub: {
29
31
  // BaseHub mergers would go here when implemented
@@ -113,7 +115,7 @@ export async function injectIntegration(targetDir, cms, spinner) {
113
115
  return results;
114
116
  }
115
117
 
116
- const { branch, mergeFiles, additivePaths } = cmsConfig;
118
+ const { mergeFiles, additivePaths } = cmsConfig;
117
119
 
118
120
  // Detect if project uses src/ prefix (e.g., src/app/ instead of app/)
119
121
  const pathPrefix = await detectPathPrefix(targetDir);
@@ -121,111 +123,103 @@ export async function injectIntegration(targetDir, cms, spinner) {
121
123
  spinner.text = `Detected src/ directory structure...`;
122
124
  }
123
125
 
124
- // 1. Clone integration to temp directory
125
- const tempDir = path.join(os.tmpdir(), `integration-${Date.now()}`);
126
+ // Resolve local integration files directory
127
+ const integrationDir = path.resolve(
128
+ __dirname,
129
+ "../../integrations",
130
+ cms,
131
+ "files",
132
+ );
126
133
 
127
- try {
128
- spinner.text = `Downloading ${cms} integration...`;
129
-
130
- // Use CMS-specific branch
131
- const integrationRepoPath = `github:basementstudio/basement-cli/integrations/${cms}#${branch}`;
132
- const emitter = tiged(integrationRepoPath, {
133
- cache: false,
134
- force: true,
135
- mode: "git",
134
+ if (!(await fs.pathExists(integrationDir))) {
135
+ results.failed.push({
136
+ path: cms,
137
+ error: `Integration directory not found: ${integrationDir}`,
136
138
  });
139
+ return results;
140
+ }
137
141
 
138
- await emitter.clone(tempDir);
139
-
140
- // 2. Copy additive files/directories (CMS-specific paths)
141
- spinner.text = `Adding ${cms} files...`;
142
+ // 1. Copy additive files/directories (CMS-specific paths)
143
+ spinner.text = `Adding ${cms} files...`;
142
144
 
143
- for (const additivePath of additivePaths) {
144
- const src = path.join(tempDir, additivePath);
145
- // Transform destination path based on project structure
146
- const transformedPath = transformPath(additivePath, pathPrefix);
147
- const dest = path.join(targetDir, transformedPath);
145
+ for (const additivePath of additivePaths) {
146
+ const src = path.join(integrationDir, additivePath);
147
+ // Transform destination path based on project structure
148
+ const transformedPath = transformPath(additivePath, pathPrefix);
149
+ const dest = path.join(targetDir, transformedPath);
148
150
 
149
- try {
150
- if (await fs.pathExists(src)) {
151
- await fs.copy(src, dest, { overwrite: false });
152
- results.copied.push(transformedPath);
153
- }
154
- } catch (error) {
155
- results.failed.push({ path: transformedPath, error: error.message });
151
+ try {
152
+ if (await fs.pathExists(src)) {
153
+ await fs.copy(src, dest, { overwrite: false });
154
+ results.copied.push(transformedPath);
156
155
  }
156
+ } catch (error) {
157
+ results.failed.push({ path: transformedPath, error: error.message });
157
158
  }
159
+ }
158
160
 
159
- // 3. Smart merge files that exist in both (CMS-specific mergers)
160
- if (mergeFiles.length > 0) {
161
- spinner.text = `Merging ${cms} integration...`;
162
-
163
- for (const mergeFile of mergeFiles) {
164
- // Transform path for the target project
165
- const transformedPath = transformPath(mergeFile, pathPrefix);
166
- const templateFile = path.join(targetDir, transformedPath);
167
- const integrationFile = path.join(tempDir, mergeFile);
168
-
169
- try {
170
- // Check if template file exists
171
- if (!(await fs.pathExists(templateFile))) {
172
- // Template doesn't have this file - copy from integration
173
- if (await fs.pathExists(integrationFile)) {
174
- await fs.ensureDir(path.dirname(templateFile));
175
- await fs.copy(integrationFile, templateFile);
176
- results.copied.push(transformedPath);
177
- } else {
178
- results.skipped.push({
179
- path: transformedPath,
180
- reason: "Not in integration",
181
- });
182
- }
183
- continue;
184
- }
161
+ // 2. Smart merge files that exist in both (CMS-specific mergers)
162
+ if (mergeFiles.length > 0) {
163
+ spinner.text = `Merging ${cms} integration...`;
185
164
 
186
- // Check if integration file exists
187
- if (!(await fs.pathExists(integrationFile))) {
165
+ for (const mergeFile of mergeFiles) {
166
+ // Transform path for the target project
167
+ const transformedPath = transformPath(mergeFile, pathPrefix);
168
+ const templateFile = path.join(targetDir, transformedPath);
169
+ const integrationFile = path.join(integrationDir, mergeFile);
170
+
171
+ try {
172
+ // Check if template file exists
173
+ if (!(await fs.pathExists(templateFile))) {
174
+ // Template doesn't have this file - copy from integration
175
+ if (await fs.pathExists(integrationFile)) {
176
+ await fs.ensureDir(path.dirname(templateFile));
177
+ await fs.copy(integrationFile, templateFile);
178
+ results.copied.push(transformedPath);
179
+ } else {
188
180
  results.skipped.push({
189
181
  path: transformedPath,
190
182
  reason: "Not in integration",
191
183
  });
192
- continue;
193
184
  }
185
+ continue;
186
+ }
194
187
 
195
- // Get the CMS-specific merger function (use base path for lookup)
196
- const merger = await getMerger(cms, mergeFile);
188
+ // Check if integration file exists
189
+ if (!(await fs.pathExists(integrationFile))) {
190
+ results.skipped.push({
191
+ path: transformedPath,
192
+ reason: "Not in integration",
193
+ });
194
+ continue;
195
+ }
197
196
 
198
- if (merger) {
199
- const result = await merger(templateFile, {
200
- targetDir,
201
- pathPrefix,
202
- });
203
- if (result.skipped) {
204
- results.skipped.push({
205
- path: transformedPath,
206
- reason: result.reason,
207
- });
208
- } else {
209
- results.merged.push(transformedPath);
210
- }
211
- } else {
197
+ // Get the CMS-specific merger function (use base path for lookup)
198
+ const merger = await getMerger(cms, mergeFile);
199
+
200
+ if (merger) {
201
+ const result = await merger(templateFile, {
202
+ targetDir,
203
+ pathPrefix,
204
+ });
205
+ if (result.skipped) {
212
206
  results.skipped.push({
213
207
  path: transformedPath,
214
- reason: `No merger for ${cms}`,
208
+ reason: result.reason,
215
209
  });
210
+ } else {
211
+ results.merged.push(transformedPath);
216
212
  }
217
- } catch (error) {
218
- results.failed.push({ path: transformedPath, error: error.message });
213
+ } else {
214
+ results.skipped.push({
215
+ path: transformedPath,
216
+ reason: `No merger for ${cms}`,
217
+ });
219
218
  }
219
+ } catch (error) {
220
+ results.failed.push({ path: transformedPath, error: error.message });
220
221
  }
221
222
  }
222
- } finally {
223
- // 4. Cleanup temp directory
224
- try {
225
- await fs.remove(tempDir);
226
- } catch {
227
- // Ignore cleanup errors
228
- }
229
223
  }
230
224
 
231
225
  return results;
@@ -253,8 +247,8 @@ export async function injectLayer(targetDir, layer, spinner) {
253
247
  return results;
254
248
  }
255
249
 
256
- // Resolve the layer directory from the CLI repo's layers/{type}/ path
257
- const layerDir = path.resolve(__dirname, "../../layers", layer);
250
+ // Resolve the layer directory from create-basement-app's templates/{type}/ path
251
+ const layerDir = path.resolve(__dirname, "../../templates", layer);
258
252
 
259
253
  if (!(await fs.pathExists(layerDir))) {
260
254
  results.skipped.push({
@@ -0,0 +1,223 @@
1
+ // packages/create-basement-app/src/mergers/layout-merger.js
2
+
3
+ import path from "node:path";
4
+ import fs from "fs-extra";
5
+
6
+ /**
7
+ * Sanity-specific imports to inject into layout.
8
+ * Only two lightweight components — no dynamic functions (draftMode, headers, etc.)
9
+ */
10
+ const SANITY_IMPORTS = `import { SanityStudioGuard } from "@/components/sanity/studio-guard"
11
+ import { SanityVisualEditing } from "@/components/sanity/visual-editing"`;
12
+
13
+ /**
14
+ * Client component that hides site chrome on /studio routes.
15
+ * Uses useSelectedLayoutSegment() — a stable Next.js client API.
16
+ */
17
+ const STUDIO_GUARD_COMPONENT = `"use client"
18
+
19
+ import { useSelectedLayoutSegment } from "next/navigation"
20
+
21
+ export function SanityStudioGuard({ children }: { children: React.ReactNode }) {
22
+ const segment = useSelectedLayoutSegment()
23
+ if (segment === "studio") return null
24
+ return <>{children}</>
25
+ }
26
+ `;
27
+
28
+ /**
29
+ * Server component that handles Sanity visual editing.
30
+ * Keeps draftMode() inside its own <Suspense> boundary so the root layout
31
+ * never calls dynamic functions directly — preserving static rendering.
32
+ */
33
+ const VISUAL_EDITING_COMPONENT = `import { Suspense } from "react"
34
+ import { draftMode } from "next/headers"
35
+ import { VisualEditing } from "next-sanity/visual-editing"
36
+ import { isSanityConfigured } from "@/lib/integrations/check-integration"
37
+ import { SanityLive } from "@/lib/integrations/sanity/live"
38
+
39
+ async function VisualEditingInner() {
40
+ const { isEnabled: isDraftMode } = await draftMode()
41
+ const sanityConfigured = isSanityConfigured()
42
+
43
+ if (!sanityConfigured || !isDraftMode) return null
44
+
45
+ return (
46
+ <>
47
+ <VisualEditing />
48
+ <SanityLive />
49
+ </>
50
+ )
51
+ }
52
+
53
+ export function SanityVisualEditing() {
54
+ return (
55
+ <Suspense fallback={null}>
56
+ <VisualEditingInner />
57
+ </Suspense>
58
+ )
59
+ }
60
+ `;
61
+
62
+ /**
63
+ * Merge Sanity integration into template layout.
64
+ * The layout itself stays free of dynamic functions (draftMode, headers, etc.)
65
+ * All dynamic behavior is encapsulated in generated components.
66
+ *
67
+ * Strategy:
68
+ * 1. Inject two imports (SanityStudioGuard, SanityVisualEditing)
69
+ * 2. Wrap body chrome in <SanityStudioGuard>
70
+ * 3. Add <SanityVisualEditing /> before </body>
71
+ * 4. Generate the two component files
72
+ *
73
+ * @param {string} templatePath - Path to the template's layout.tsx
74
+ * @param {object} options - Options from the merge orchestrator
75
+ * @param {string} options.targetDir - The project root directory
76
+ * @param {string} options.pathPrefix - Path prefix (e.g., 'src/' or '')
77
+ * @returns {Promise<{skipped?: boolean, reason?: string, success?: boolean}>}
78
+ */
79
+ export async function mergeLayout(
80
+ templatePath,
81
+ { targetDir, pathPrefix } = {},
82
+ ) {
83
+ let content = await fs.readFile(templatePath, "utf-8");
84
+
85
+ // Skip if already has Sanity integration
86
+ if (
87
+ content.includes("SanityStudioGuard") ||
88
+ content.includes("isSanityConfigured")
89
+ ) {
90
+ return { skipped: true, reason: "Already has Sanity integration" };
91
+ }
92
+
93
+ // 1. Add Sanity imports after existing imports
94
+ const importMatches = [...content.matchAll(/^import .+$/gm)];
95
+ if (importMatches.length > 0) {
96
+ const lastImport = importMatches[importMatches.length - 1];
97
+ const insertPos = lastImport.index + lastImport[0].length;
98
+ content =
99
+ content.slice(0, insertPos) +
100
+ "\n" +
101
+ SANITY_IMPORTS +
102
+ content.slice(insertPos);
103
+ }
104
+
105
+ // 2. Ensure Suspense is imported from react
106
+ if (!content.match(/import\s+.*Suspense.*from\s+["']react["']/)) {
107
+ const reactImportMatch = content.match(
108
+ /import\s+\{([^}]*)\}\s+from\s+["']react["']/,
109
+ );
110
+ if (reactImportMatch) {
111
+ if (!reactImportMatch[1].includes("Suspense")) {
112
+ content = content.replace(
113
+ reactImportMatch[0],
114
+ reactImportMatch[0].replace(
115
+ reactImportMatch[1],
116
+ `${reactImportMatch[1].trim()}, Suspense`,
117
+ ),
118
+ );
119
+ }
120
+ } else {
121
+ const lastImportMatch = content.match(/^(import\s+.+\n)/gm);
122
+ if (lastImportMatch) {
123
+ const lastImport = lastImportMatch[lastImportMatch.length - 1];
124
+ content = content.replace(
125
+ lastImport,
126
+ `${lastImport}import { Suspense } from "react"\n`,
127
+ );
128
+ }
129
+ }
130
+ }
131
+
132
+ // 3. Wrap body chrome in <SanityStudioGuard> and add <SanityVisualEditing />
133
+ content = content.replace(
134
+ /(\s*)(<body[^>]*>)([\s\S]*?)(\{children\})([\s\S]*?)(<\/body>)/m,
135
+ (
136
+ _match,
137
+ bodyIndent,
138
+ bodyOpen,
139
+ beforeChildren,
140
+ _childrenExpr,
141
+ afterChildren,
142
+ bodyClose,
143
+ ) => {
144
+ const baseIndent = bodyIndent || " ";
145
+ const indent = `${baseIndent} `;
146
+ const innerIndent = `${indent} `;
147
+
148
+ const trimmedBefore = beforeChildren.trim();
149
+ const trimmedAfter = afterChildren.trim();
150
+ const hasChrome = trimmedBefore.length > 0 || trimmedAfter.length > 0;
151
+
152
+ // Preserve relative indentation of chrome content
153
+ const reindent = (text, targetIndent) => {
154
+ const lines = text.split("\n").filter((line) => line.trim());
155
+ if (lines.length === 0) return "";
156
+ const minIndent = Math.min(
157
+ ...lines
158
+ .map((line) => line.match(/^(\s*)/)[1].length)
159
+ .filter((n) => n > 0),
160
+ Infinity,
161
+ );
162
+ return lines
163
+ .map((line) => {
164
+ const currentIndent = line.match(/^(\s*)/)[1].length;
165
+ const relativeIndent = Math.max(
166
+ 0,
167
+ currentIndent - (minIndent === Infinity ? 0 : minIndent),
168
+ );
169
+ return targetIndent + " ".repeat(relativeIndent) + line.trim();
170
+ })
171
+ .join("\n");
172
+ };
173
+
174
+ let result = `${baseIndent}${bodyOpen}\n`;
175
+
176
+ if (hasChrome && trimmedBefore) {
177
+ result += `${indent}<Suspense fallback={null}>\n`;
178
+ result += `${innerIndent}<SanityStudioGuard>\n`;
179
+ result += reindent(trimmedBefore, `${innerIndent} `);
180
+ result += `\n${innerIndent}</SanityStudioGuard>\n`;
181
+ result += `${indent}</Suspense>\n\n`;
182
+ }
183
+
184
+ result += `${indent}{children}\n`;
185
+
186
+ if (hasChrome && trimmedAfter) {
187
+ result += `\n${indent}<Suspense fallback={null}>\n`;
188
+ result += `${innerIndent}<SanityStudioGuard>\n`;
189
+ result += reindent(trimmedAfter, `${innerIndent} `);
190
+ result += `\n${innerIndent}</SanityStudioGuard>\n`;
191
+ result += `${indent}</Suspense>\n`;
192
+ }
193
+
194
+ result += `\n${indent}<SanityVisualEditing />\n${baseIndent}${bodyClose}`;
195
+ return result;
196
+ },
197
+ );
198
+
199
+ await fs.writeFile(templatePath, content);
200
+
201
+ // 3. Generate component files
202
+ if (targetDir) {
203
+ const sanityDir = path.join(
204
+ targetDir,
205
+ pathPrefix || "",
206
+ "components",
207
+ "sanity",
208
+ );
209
+ await fs.ensureDir(sanityDir);
210
+
211
+ const guardPath = path.join(sanityDir, "studio-guard.tsx");
212
+ if (!(await fs.pathExists(guardPath))) {
213
+ await fs.writeFile(guardPath, STUDIO_GUARD_COMPONENT);
214
+ }
215
+
216
+ const visualEditingPath = path.join(sanityDir, "visual-editing.tsx");
217
+ if (!(await fs.pathExists(visualEditingPath))) {
218
+ await fs.writeFile(visualEditingPath, VISUAL_EDITING_COMPONENT);
219
+ }
220
+ }
221
+
222
+ return { success: true };
223
+ }