@master/internal-site 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (687) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -2
  3. package/dist/astro.d.mts +3 -0
  4. package/dist/astro.mjs +510 -0
  5. package/dist/config.d.mts +69 -0
  6. package/dist/config.mjs +10 -0
  7. package/package.json +384 -4
  8. package/src/astro/Page.astro +12 -0
  9. package/src/astro/content-pages.ts +75 -0
  10. package/src/astro/index.ts +124 -0
  11. package/src/astro/module-id.ts +4 -0
  12. package/src/astro/propagated-assets.ts +29 -0
  13. package/src/astro/route-paths.ts +78 -0
  14. package/src/astro/routes.template.ts +110 -0
  15. package/src/astro/server-styles.ts +26 -0
  16. package/src/astro/site-context.ts +27 -0
  17. package/src/astro/source-url.ts +22 -0
  18. package/src/astro/svelte-renderer.ts +45 -0
  19. package/src/astro/svg-markup.ts +23 -0
  20. package/src/benchmarks/BenchmarkBarRows.astro +34 -0
  21. package/src/benchmarks/BenchmarkBars.astro +14 -0
  22. package/src/benchmarks/BenchmarkChart.astro +53 -0
  23. package/src/benchmarks/BenchmarkChartGroup.astro +24 -0
  24. package/src/benchmarks/BenchmarkDataTable.astro +24 -0
  25. package/src/benchmarks/BenchmarkDelta.astro +23 -0
  26. package/src/benchmarks/BenchmarkFigure.astro +30 -0
  27. package/src/benchmarks/BenchmarkMetricTable.astro +38 -0
  28. package/src/benchmarks/BenchmarkMetrics.astro +23 -0
  29. package/src/benchmarks/BenchmarkSampleSummary.astro +30 -0
  30. package/src/benchmarks/BenchmarkScrollRegion.svelte +27 -0
  31. package/src/benchmarks/BenchmarkSource.astro +20 -0
  32. package/src/benchmarks/BenchmarkStackedBars.astro +54 -0
  33. package/src/benchmarks/BenchmarkStatus.astro +16 -0
  34. package/src/benchmarks/types.ts +98 -0
  35. package/src/benchmarks/utils.ts +42 -0
  36. package/src/blog/BlogAuthors.astro +25 -0
  37. package/src/blog/article/BlogArticleContents.svelte +24 -0
  38. package/src/blog/article/BlogArticleEnd.astro +55 -0
  39. package/src/blog/article/BlogArticleMasthead.astro +61 -0
  40. package/src/blog/article/language.ts +29 -0
  41. package/src/blog/article/neighbors.ts +27 -0
  42. package/src/blog/article/title-lines.astro +14 -0
  43. package/src/blog/article/title-parts.ts +9 -0
  44. package/src/components.d.ts +5 -0
  45. package/src/config.ts +68 -0
  46. package/src/css/ButtonPreview.astro +22 -0
  47. package/src/css/ConfiguredExample.astro +15 -0
  48. package/src/css/NamespaceUtilityTable.astro +50 -0
  49. package/src/css/StylesheetExample.astro +15 -0
  50. package/src/css/ThemeNumberVariableTable.astro +57 -0
  51. package/src/css/configured-example.ts +53 -0
  52. package/src/css/foundation-data/elevation/shadow-data.ts +52 -0
  53. package/src/css/foundation-data/sizing/scale-data.ts +37 -0
  54. package/src/css/foundation-data/specimen-content.ts +10 -0
  55. package/src/css/foundation-data/specimens.ts +96 -0
  56. package/src/css/foundation-data/tokens.ts +32 -0
  57. package/src/css/generate-preset-css.ts +12 -0
  58. package/src/css/highlight.ts +34 -0
  59. package/src/css/manifest-utilities.ts +29 -0
  60. package/src/css/markdown.ts +279 -0
  61. package/src/css/preset-css.ts +15 -0
  62. package/src/css/preset-manifest.ts +3 -0
  63. package/src/css/stylesheet-example.ts +26 -0
  64. package/src/css/theme-variables.ts +74 -0
  65. package/src/css/variable-namespace-sources.ts +20 -0
  66. package/src/demo/Demo.svelte +55 -0
  67. package/src/demo/DemoAsset.astro +38 -0
  68. package/src/demo/DemoAxes.svelte +22 -0
  69. package/src/demo/DemoBadge.svelte +18 -0
  70. package/src/demo/DemoCatalog.astro +36 -0
  71. package/src/demo/DemoComparison.svelte +36 -0
  72. package/src/demo/DemoConfiguredExample.astro +48 -0
  73. package/src/demo/DemoContainer.svelte +48 -0
  74. package/src/demo/DemoControls.svelte +16 -0
  75. package/src/demo/DemoCopyButton.svelte +50 -0
  76. package/src/demo/DemoCopyGroup.svelte +15 -0
  77. package/src/demo/DemoExample.astro +27 -0
  78. package/src/demo/DemoFeatureSupport.svelte +18 -0
  79. package/src/demo/DemoGeneratedCSS.svelte +8 -0
  80. package/src/demo/DemoIndex.astro +23 -0
  81. package/src/demo/DemoInstallation.astro +17 -0
  82. package/src/demo/DemoItem.svelte +17 -0
  83. package/src/demo/DemoLabel.svelte +15 -0
  84. package/src/demo/DemoLegend.svelte +15 -0
  85. package/src/demo/DemoMeasure.svelte +28 -0
  86. package/src/demo/DemoMedia.svelte +43 -0
  87. package/src/demo/DemoMotion.svelte +41 -0
  88. package/src/demo/DemoPageViewport.astro +17 -0
  89. package/src/demo/DemoPalette.astro +29 -0
  90. package/src/demo/DemoPaletteGroups.svelte +15 -0
  91. package/src/demo/DemoScrollArea.svelte +15 -0
  92. package/src/demo/DemoStyleComparison.astro +25 -0
  93. package/src/demo/DemoSurface.svelte +15 -0
  94. package/src/demo/DemoSwatch.svelte +19 -0
  95. package/src/demo/DemoThemeComparison.astro +30 -0
  96. package/src/demo/DemoTokenTable.astro +34 -0
  97. package/src/demo/DemoViewTransition.astro +18 -0
  98. package/src/demo/DemoViewport.svelte +324 -0
  99. package/src/demo/DemoWaterfall.astro +30 -0
  100. package/src/demo/FoundationBreakpoint.astro +12 -0
  101. package/src/demo/ProjectStyleExample.astro +13 -0
  102. package/src/demo/copy-feedback.ts +10 -0
  103. package/src/demo/demo-waterfall.ts +17 -0
  104. package/src/demo/drag-readings.ts +20 -0
  105. package/src/demo/foundations/FoundationAxes.astro +12 -0
  106. package/src/demo/foundations/FoundationColorRoles.astro +5 -0
  107. package/src/demo/foundations/FoundationContainerGrid.astro +24 -0
  108. package/src/demo/foundations/FoundationDialog.astro +14 -0
  109. package/src/demo/foundations/FoundationElevation.astro +5 -0
  110. package/src/demo/foundations/FoundationElevationState.astro +5 -0
  111. package/src/demo/foundations/FoundationHue.astro +5 -0
  112. package/src/demo/foundations/FoundationLines.astro +5 -0
  113. package/src/demo/foundations/FoundationMedia.astro +28 -0
  114. package/src/demo/foundations/FoundationMotion.astro +5 -0
  115. package/src/demo/foundations/FoundationPalette.astro +8 -0
  116. package/src/demo/foundations/FoundationRadius.astro +13 -0
  117. package/src/demo/foundations/FoundationShapes.astro +12 -0
  118. package/src/demo/foundations/FoundationShrink.astro +14 -0
  119. package/src/demo/foundations/FoundationSizing.astro +19 -0
  120. package/src/demo/foundations/FoundationSpecimen.astro +20 -0
  121. package/src/demo/foundations/FoundationSurfaces.astro +5 -0
  122. package/src/demo/foundations/FoundationTextHue.astro +5 -0
  123. package/src/demo/foundations/FoundationTextRoles.astro +5 -0
  124. package/src/demo/foundations/FoundationTokens.astro +22 -0
  125. package/src/demo/foundations/FoundationTokensView.astro +65 -0
  126. package/src/demo/foundations/FoundationTransition.astro +5 -0
  127. package/src/demo/foundations/FoundationTypeComparison.astro +12 -0
  128. package/src/demo/foundations/FoundationTypography.astro +5 -0
  129. package/src/demo/foundations/Palette.svelte +37 -0
  130. package/src/demo/foundations/ShadowScaleDemo.astro +22 -0
  131. package/src/demo/illustration-materials.ts +180 -0
  132. package/src/demo/maintenance-example.ts +62 -0
  133. package/src/demo/playback.ts +75 -0
  134. package/src/demo/project-style-examples.ts +128 -0
  135. package/src/demo/reference/alignment.ts +42 -0
  136. package/src/demo/reference/animations.ts +30 -0
  137. package/src/demo/reference/backgrounds.ts +39 -0
  138. package/src/demo/reference/border-paint.ts +31 -0
  139. package/src/demo/reference/clipping.ts +26 -0
  140. package/src/demo/reference/document.ts +55 -0
  141. package/src/demo/reference/edges.ts +40 -0
  142. package/src/demo/reference/effects.ts +27 -0
  143. package/src/demo/reference/flexbox.ts +33 -0
  144. package/src/demo/reference/frame.css +118 -0
  145. package/src/demo/reference/grid.ts +42 -0
  146. package/src/demo/reference/html.ts +40 -0
  147. package/src/demo/reference/interaction.ts +42 -0
  148. package/src/demo/reference/layout-html.ts +10 -0
  149. package/src/demo/reference/layout.ts +102 -0
  150. package/src/demo/reference/media.ts +29 -0
  151. package/src/demo/reference/positioning.ts +90 -0
  152. package/src/demo/reference/scenes.ts +197 -0
  153. package/src/demo/reference/scrolling.ts +66 -0
  154. package/src/demo/reference/shapes.ts +22 -0
  155. package/src/demo/reference/sizing.ts +43 -0
  156. package/src/demo/reference/source.ts +8 -0
  157. package/src/demo/reference/text-effects.ts +37 -0
  158. package/src/demo/reference/text-flow.ts +41 -0
  159. package/src/demo/reference/transforms.ts +26 -0
  160. package/src/demo/reference/transitions.ts +24 -0
  161. package/src/demo/reference/type-specimens.ts +56 -0
  162. package/src/demo/reference/types.ts +30 -0
  163. package/src/demo/reference/typography.ts +32 -0
  164. package/src/demo/specimens/accent-color.json +50 -0
  165. package/src/demo/specimens/align-items.json +56 -0
  166. package/src/demo/specimens/animation-delay.json +55 -0
  167. package/src/demo/specimens/animation-direction.json +49 -0
  168. package/src/demo/specimens/animation-fill-mode.json +55 -0
  169. package/src/demo/specimens/animation-iteration-count.json +55 -0
  170. package/src/demo/specimens/animation-play-state.json +83 -0
  171. package/src/demo/specimens/animation-timing-function.json +48 -0
  172. package/src/demo/specimens/appearance.json +44 -0
  173. package/src/demo/specimens/aspect-ratio.json +28 -0
  174. package/src/demo/specimens/backdrop-filter.json +44 -0
  175. package/src/demo/specimens/background-attachment.json +49 -0
  176. package/src/demo/specimens/background-image.json +25 -0
  177. package/src/demo/specimens/background-origin.json +36 -0
  178. package/src/demo/specimens/background-size.json +29 -0
  179. package/src/demo/specimens/border-collapse.json +45 -0
  180. package/src/demo/specimens/border-color.json +35 -0
  181. package/src/demo/specimens/border-image-repeat.json +50 -0
  182. package/src/demo/specimens/border-image-slice.json +45 -0
  183. package/src/demo/specimens/border-radius.json +30 -0
  184. package/src/demo/specimens/box-decoration-break.json +35 -0
  185. package/src/demo/specimens/box-shadow.json +33 -0
  186. package/src/demo/specimens/clear.json +77 -0
  187. package/src/demo/specimens/clip-path.json +38 -0
  188. package/src/demo/specimens/content.json +27 -0
  189. package/src/demo/specimens/counter-set.json +31 -0
  190. package/src/demo/specimens/fill.json +23 -0
  191. package/src/demo/specimens/filter.json +23 -0
  192. package/src/demo/specimens/flex-direction.json +27 -0
  193. package/src/demo/specimens/flex-grow.json +27 -0
  194. package/src/demo/specimens/font-style.json +23 -0
  195. package/src/demo/specimens/font-variant-numeric.json +28 -0
  196. package/src/demo/specimens/grid-auto-columns.json +29 -0
  197. package/src/demo/specimens/grid-auto-flow.json +37 -0
  198. package/src/demo/specimens/grid-template-areas.json +34 -0
  199. package/src/demo/specimens/grid-template-columns.json +36 -0
  200. package/src/demo/specimens/isolation.json +25 -0
  201. package/src/demo/specimens/justify-content.json +36 -0
  202. package/src/demo/specimens/line-height.json +28 -0
  203. package/src/demo/specimens/list-style-position.json +36 -0
  204. package/src/demo/specimens/mask-image.json +54 -0
  205. package/src/demo/specimens/min-width.json +39 -0
  206. package/src/demo/specimens/mix-blend-mode.json +43 -0
  207. package/src/demo/specimens/object-fit.json +27 -0
  208. package/src/demo/specimens/object-position.json +27 -0
  209. package/src/demo/specimens/opacity.json +37 -0
  210. package/src/demo/specimens/order.json +28 -0
  211. package/src/demo/specimens/overflow-wrap.json +26 -0
  212. package/src/demo/specimens/overflow.json +53 -0
  213. package/src/demo/specimens/overscroll-behavior.json +29 -0
  214. package/src/demo/specimens/padding.json +84 -0
  215. package/src/demo/specimens/place-content.json +31 -0
  216. package/src/demo/specimens/pointer-events.json +46 -0
  217. package/src/demo/specimens/position.json +29 -0
  218. package/src/demo/specimens/resize.json +32 -0
  219. package/src/demo/specimens/screen-readers.json +37 -0
  220. package/src/demo/specimens/scroll-padding.json +29 -0
  221. package/src/demo/specimens/scroll-snap-stop.json +33 -0
  222. package/src/demo/specimens/shape-image-threshold.json +37 -0
  223. package/src/demo/specimens/shape-margin.json +40 -0
  224. package/src/demo/specimens/shape-outside.json +37 -0
  225. package/src/demo/specimens/stroke-width.json +27 -0
  226. package/src/demo/specimens/text-fill-color.json +23 -0
  227. package/src/demo/specimens/text-stroke-width.json +32 -0
  228. package/src/demo/specimens/touch-action.json +45 -0
  229. package/src/demo/specimens/transform-box.json +37 -0
  230. package/src/demo/specimens/transform-origin.json +56 -0
  231. package/src/demo/specimens/transform-style.json +55 -0
  232. package/src/demo/specimens/transform.json +47 -0
  233. package/src/demo/specimens/transition-delay.json +57 -0
  234. package/src/demo/specimens/transition-duration.json +60 -0
  235. package/src/demo/specimens/transition-property.json +60 -0
  236. package/src/demo/specimens/transition-timing-function.json +65 -0
  237. package/src/demo/specimens/user-drag.json +28 -0
  238. package/src/demo/specimens/user-select.json +25 -0
  239. package/src/demo/specimens/vertical-align.json +28 -0
  240. package/src/demo/specimens/width.json +56 -0
  241. package/src/demo/specimens/will-change.json +50 -0
  242. package/src/demo/specimens/writing-mode.json +26 -0
  243. package/src/demo/specimens/z-index.json +35 -0
  244. package/src/demo/style.ts +15 -0
  245. package/src/demo/tone.ts +4 -0
  246. package/src/demo/useDemoViewTransition.svelte.ts +71 -0
  247. package/src/docs-shell/common/i18n.config.d.ts +2 -0
  248. package/src/docs-shell/common/i18n.config.js +13 -0
  249. package/src/docs-shell/common/svgo.config.d.ts +2 -0
  250. package/src/docs-shell/common/svgo.config.js +11 -0
  251. package/src/docs-shell/components/ArticleHeader.astro +65 -0
  252. package/src/docs-shell/components/ArticleTOC.astro +18 -0
  253. package/src/docs-shell/components/Callout.astro +26 -0
  254. package/src/docs-shell/components/Code.astro +25 -0
  255. package/src/docs-shell/components/CodeCopyButton.astro +25 -0
  256. package/src/docs-shell/components/CodeTabBar.astro +40 -0
  257. package/src/docs-shell/components/CodeTabs.astro +53 -0
  258. package/src/docs-shell/components/CodeView.astro +23 -0
  259. package/src/docs-shell/components/Do.astro +5 -0
  260. package/src/docs-shell/components/DoNot.astro +5 -0
  261. package/src/docs-shell/components/DocArticle.astro +14 -0
  262. package/src/docs-shell/components/DocHeader.svelte +93 -0
  263. package/src/docs-shell/components/DocHeading.astro +28 -0
  264. package/src/docs-shell/components/DocMain.astro +19 -0
  265. package/src/docs-shell/components/DocMenuButton.svelte +96 -0
  266. package/src/docs-shell/components/DocSidebar.svelte +62 -0
  267. package/src/docs-shell/components/DocVersionSelect.svelte +22 -0
  268. package/src/docs-shell/components/DocWrapper.astro +11 -0
  269. package/src/docs-shell/components/DocumentAPIIndex.astro +24 -0
  270. package/src/docs-shell/components/DocumentChoices.astro +24 -0
  271. package/src/docs-shell/components/DocumentCodeExample.astro +20 -0
  272. package/src/docs-shell/components/DocumentCodeExampleView.astro +35 -0
  273. package/src/docs-shell/components/DocumentCodeTable.astro +19 -0
  274. package/src/docs-shell/components/DocumentComparison.astro +7 -0
  275. package/src/docs-shell/components/DocumentCopyButton.svelte +41 -0
  276. package/src/docs-shell/components/DocumentDeclaration.astro +17 -0
  277. package/src/docs-shell/components/DocumentDeclarationView.astro +12 -0
  278. package/src/docs-shell/components/DocumentDisclosure.astro +14 -0
  279. package/src/docs-shell/components/DocumentFileTree.astro +34 -0
  280. package/src/docs-shell/components/DocumentFlow.astro +27 -0
  281. package/src/docs-shell/components/DocumentIdentifier.astro +14 -0
  282. package/src/docs-shell/components/DocumentIllustration.astro +46 -0
  283. package/src/docs-shell/components/DocumentKeyList.astro +22 -0
  284. package/src/docs-shell/components/DocumentNamespaceTable.astro +20 -0
  285. package/src/docs-shell/components/DocumentOptionEntry.astro +15 -0
  286. package/src/docs-shell/components/DocumentOptionList.astro +11 -0
  287. package/src/docs-shell/components/DocumentOptions.astro +23 -0
  288. package/src/docs-shell/components/DocumentParameters.astro +30 -0
  289. package/src/docs-shell/components/DocumentPrompt.astro +16 -0
  290. package/src/docs-shell/components/DocumentValueList.astro +25 -0
  291. package/src/docs-shell/components/DocumentationIndex.svelte +144 -0
  292. package/src/docs-shell/components/Dropped.astro +21 -0
  293. package/src/docs-shell/components/ExpandContent.svelte +21 -0
  294. package/src/docs-shell/components/ExplorerView.astro +37 -0
  295. package/src/docs-shell/components/FileIcon.astro +123 -0
  296. package/src/docs-shell/components/Footer.svelte +80 -0
  297. package/src/docs-shell/components/GeneratedCSS.astro +8 -0
  298. package/src/docs-shell/components/Header.svelte +121 -0
  299. package/src/docs-shell/components/HeaderIcon.astro +14 -0
  300. package/src/docs-shell/components/HeaderNav.svelte +20 -0
  301. package/src/docs-shell/components/Image.svelte +56 -0
  302. package/src/docs-shell/components/Info.astro +5 -0
  303. package/src/docs-shell/components/InlineCode.astro +30 -0
  304. package/src/docs-shell/components/InteractingIndicator.astro +19 -0
  305. package/src/docs-shell/components/LanguageButton.svelte +18 -0
  306. package/src/docs-shell/components/LanguageSelect.svelte +44 -0
  307. package/src/docs-shell/components/Link.svelte +127 -0
  308. package/src/docs-shell/components/ModeImg.astro +11 -0
  309. package/src/docs-shell/components/NotFound.astro +21 -0
  310. package/src/docs-shell/components/OverviewButtons.astro +36 -0
  311. package/src/docs-shell/components/PMAction.astro +25 -0
  312. package/src/docs-shell/components/PackageBadges.astro +39 -0
  313. package/src/docs-shell/components/PageContent.svelte +38 -0
  314. package/src/docs-shell/components/PageContentBootstrap.astro +13 -0
  315. package/src/docs-shell/components/PageContentDisclosure.astro +25 -0
  316. package/src/docs-shell/components/PageContentList.svelte +70 -0
  317. package/src/docs-shell/components/PageContentProvider.svelte +15 -0
  318. package/src/docs-shell/components/PageContentTitle.svelte +16 -0
  319. package/src/docs-shell/components/PageNavs.astro +40 -0
  320. package/src/docs-shell/components/PreparedCodeView.astro +12 -0
  321. package/src/docs-shell/components/RenderNode.astro +16 -0
  322. package/src/docs-shell/components/RouteLayers.astro +17 -0
  323. package/src/docs-shell/components/SearchButton.svelte +31 -0
  324. package/src/docs-shell/components/SearchDialog.svelte +174 -0
  325. package/src/docs-shell/components/Segments.svelte +62 -0
  326. package/src/docs-shell/components/Step.astro +13 -0
  327. package/src/docs-shell/components/StepL.astro +10 -0
  328. package/src/docs-shell/components/StepR.astro +10 -0
  329. package/src/docs-shell/components/StepSection.astro +12 -0
  330. package/src/docs-shell/components/Tab.astro +8 -0
  331. package/src/docs-shell/components/Tabs.astro +10 -0
  332. package/src/docs-shell/components/ThemeIcon.astro +19 -0
  333. package/src/docs-shell/components/ThemeSelect.svelte +20 -0
  334. package/src/docs-shell/components/TimeAgo.svelte +32 -0
  335. package/src/docs-shell/components/Translate.astro +14 -0
  336. package/src/docs-shell/components/Warn.astro +5 -0
  337. package/src/docs-shell/components/code-props.ts +28 -0
  338. package/src/docs-shell/components/document-types.ts +119 -0
  339. package/src/docs-shell/components/markdown/Anchor.astro +5 -0
  340. package/src/docs-shell/components/markdown/Heading2.astro +5 -0
  341. package/src/docs-shell/components/markdown/Heading3.astro +5 -0
  342. package/src/docs-shell/components/markdown/Table.astro +6 -0
  343. package/src/docs-shell/components/markdown-components.ts +36 -0
  344. package/src/docs-shell/components/page-content-bootstrap.ts +115 -0
  345. package/src/docs-shell/components/page-content.svelte.ts +125 -0
  346. package/src/docs-shell/contexts/search.ts +18 -0
  347. package/src/docs-shell/contexts/theme-mode.svelte.ts +61 -0
  348. package/src/docs-shell/data/authors.ts +17 -0
  349. package/src/docs-shell/data/base-colors.ts +29 -0
  350. package/src/docs-shell/data/brands.ts +79 -0
  351. package/src/docs-shell/data/color-names.ts +1 -0
  352. package/src/docs-shell/data/color-palette.ts +50 -0
  353. package/src/docs-shell/data/colors.ts +1 -0
  354. package/src/docs-shell/factories/Page.astro +35 -0
  355. package/src/docs-shell/factories/create-page.ts +31 -0
  356. package/src/docs-shell/layouts/BlogArticle.astro +53 -0
  357. package/src/docs-shell/layouts/Doc.astro +41 -0
  358. package/src/docs-shell/remark/markdown-components.d.ts +2 -0
  359. package/src/docs-shell/remark/markdown-components.js +101 -0
  360. package/src/docs-shell/remark/slug-and-toc.d.ts +2 -0
  361. package/src/docs-shell/remark/slug-and-toc.js +53 -0
  362. package/src/docs-shell/scripts/code-tabs-bootstrap.ts +34 -0
  363. package/src/docs-shell/scripts/code.ts +124 -0
  364. package/src/docs-shell/scripts/document-anchor.ts +57 -0
  365. package/src/docs-shell/scripts/document.ts +47 -0
  366. package/src/docs-shell/site.ts +67 -0
  367. package/src/docs-shell/types/IllustrationImages.ts +2 -0
  368. package/src/docs-shell/types/Metadata.ts +17 -0
  369. package/src/docs-shell/types/Props.ts +9 -0
  370. package/src/docs-shell/types/StaticImage.ts +6 -0
  371. package/src/docs-shell/uses/use-selected-preview-syntax.svelte.ts +16 -0
  372. package/src/docs-shell/utils/anchor.ts +24 -0
  373. package/src/docs-shell/utils/beautify-css.ts +14 -0
  374. package/src/docs-shell/utils/beautify-html.ts +12 -0
  375. package/src/docs-shell/utils/beautify-js.ts +9 -0
  376. package/src/docs-shell/utils/create-highlighter.ts +50 -0
  377. package/src/docs-shell/utils/css-modern-grammar.ts +339 -0
  378. package/src/docs-shell/utils/documentation-search.ts +68 -0
  379. package/src/docs-shell/utils/generate-metadata.ts +60 -0
  380. package/src/docs-shell/utils/group-page-content.ts +10 -0
  381. package/src/docs-shell/utils/head.ts +72 -0
  382. package/src/docs-shell/utils/highlight-code-core.ts +146 -0
  383. package/src/docs-shell/utils/highlight-code.ts +1 -0
  384. package/src/docs-shell/utils/highlighted-code-text.ts +27 -0
  385. package/src/docs-shell/utils/i18n-pathname.ts +98 -0
  386. package/src/docs-shell/utils/i18n.ts +12 -0
  387. package/src/docs-shell/utils/is-date-within-seven-days.ts +16 -0
  388. package/src/docs-shell/utils/isBrowser.ts +1 -0
  389. package/src/docs-shell/utils/isInteractOutside.ts +16 -0
  390. package/src/docs-shell/utils/markdown-tree.ts +22 -0
  391. package/src/docs-shell/utils/metadata.ts +25 -0
  392. package/src/docs-shell/utils/prepared-code.ts +21 -0
  393. package/src/docs-shell/utils/resolve-heading.d.ts +1 -0
  394. package/src/docs-shell/utils/resolve-heading.js +19 -0
  395. package/src/docs-shell/utils/search-pages.ts +271 -0
  396. package/src/docs-shell/utils/slot-text.ts +15 -0
  397. package/src/docs-shell/utils/snackbar.ts +39 -0
  398. package/src/docs-shell/utils/syntax-theme.ts +53 -0
  399. package/src/docs-shell/utils/transformer-notation-word-mark.ts +146 -0
  400. package/src/docs-shell/utils/unique-id.ts +11 -0
  401. package/src/examples/article-transitions/page.astro +7 -0
  402. package/src/examples/article-transitions/transitions.css +10 -0
  403. package/src/examples/components/ArticleTransitionScene.svelte +83 -0
  404. package/src/examples/components/ViewTransitionScene.svelte +31 -0
  405. package/src/examples/images/article-aurora.jpg +0 -0
  406. package/src/examples/images/article-coast.jpg +0 -0
  407. package/src/examples/images/article-grid.jpg +0 -0
  408. package/src/examples/images/article-studio.jpg +0 -0
  409. package/src/examples/layout-system/page.astro +59 -0
  410. package/src/examples/scene.css +3 -0
  411. package/src/examples/view-transitions/page.astro +7 -0
  412. package/src/examples/view-transitions/transitions.css +9 -0
  413. package/src/home/HeroCanvas.svelte +617 -0
  414. package/src/home/HomeAction.astro +17 -0
  415. package/src/home/HomeBentoFrame.astro +9 -0
  416. package/src/home/HomeBentoGrid.astro +9 -0
  417. package/src/home/HomeCompactIcon.astro +15 -0
  418. package/src/home/HomeFooter.svelte +63 -0
  419. package/src/home/HomeIllustration.astro +17 -0
  420. package/src/home/HomeIllustrationArt.svelte +15 -0
  421. package/src/home/HomeLamp.svelte +18 -0
  422. package/src/home/design.css +532 -0
  423. package/src/home/footer.css +225 -0
  424. package/src/home/hero-shaders.ts +460 -0
  425. package/src/home/hero-title-mask.ts +175 -0
  426. package/src/home/hero.css +547 -0
  427. package/src/home/home-illustration.ts +5 -0
  428. package/src/home/home-lamp.ts +225 -0
  429. package/src/home/home.css +1081 -0
  430. package/src/home/icons/agent-check-preview-apply.svg +24 -0
  431. package/src/home/icons/agent-clients.svg +26 -0
  432. package/src/home/icons/agent-project-tools.svg +23 -0
  433. package/src/home/icons/artwork/agent-check-preview-apply-dark.webp +0 -0
  434. package/src/home/icons/artwork/agent-check-preview-apply-light.webp +0 -0
  435. package/src/home/icons/artwork/agent-clients-dark.webp +0 -0
  436. package/src/home/icons/artwork/agent-clients-light.webp +0 -0
  437. package/src/home/icons/artwork/agent-edit-file-dark.webp +0 -0
  438. package/src/home/icons/artwork/agent-edit-file-light.webp +0 -0
  439. package/src/home/icons/artwork/agent-project-tools-dark.webp +0 -0
  440. package/src/home/icons/artwork/agent-project-tools-light.webp +0 -0
  441. package/src/home/icons/artwork/design-cascade-layers-dark.webp +0 -0
  442. package/src/home/icons/artwork/design-cascade-layers-light.webp +0 -0
  443. package/src/home/icons/artwork/design-layout-motion-dark.webp +0 -0
  444. package/src/home/icons/artwork/design-layout-motion-light.webp +0 -0
  445. package/src/home/icons/artwork/design-p3-gamut-dark.webp +0 -0
  446. package/src/home/icons/artwork/design-p3-gamut-light.webp +0 -0
  447. package/src/home/icons/artwork/design-theme-modes-dark.webp +0 -0
  448. package/src/home/icons/artwork/design-theme-modes-light.webp +0 -0
  449. package/src/home/icons/artwork/design-theme-tokens-dark.webp +0 -0
  450. package/src/home/icons/artwork/design-theme-tokens-light.webp +0 -0
  451. package/src/home/icons/artwork/editor-color-tools-dark.webp +0 -0
  452. package/src/home/icons/artwork/editor-color-tools-light.webp +0 -0
  453. package/src/home/icons/artwork/editor-focused-highlighting-dark.webp +0 -0
  454. package/src/home/icons/artwork/editor-focused-highlighting-light.webp +0 -0
  455. package/src/home/icons/artwork/editor-hover-inspection-dark.webp +0 -0
  456. package/src/home/icons/artwork/editor-hover-inspection-light.webp +0 -0
  457. package/src/home/icons/artwork/editor-manifest-completions-dark.webp +0 -0
  458. package/src/home/icons/artwork/editor-manifest-completions-light.webp +0 -0
  459. package/src/home/icons/artwork/lint-class-order-dark.webp +0 -0
  460. package/src/home/icons/artwork/lint-class-order-light.webp +0 -0
  461. package/src/home/icons/artwork/lint-conflicting-classes-dark.webp +0 -0
  462. package/src/home/icons/artwork/lint-conflicting-classes-light.webp +0 -0
  463. package/src/home/icons/artwork/lint-fix-previews-dark.webp +0 -0
  464. package/src/home/icons/artwork/lint-fix-previews-light.webp +0 -0
  465. package/src/home/icons/artwork/lint-invalid-classes-dark.webp +0 -0
  466. package/src/home/icons/artwork/lint-invalid-classes-light.webp +0 -0
  467. package/src/home/icons/artwork/lint-strict-vocabulary-dark.webp +0 -0
  468. package/src/home/icons/artwork/lint-strict-vocabulary-light.webp +0 -0
  469. package/src/home/icons/artwork/lint-theme-tokens-dark.webp +0 -0
  470. package/src/home/icons/artwork/lint-theme-tokens-light.webp +0 -0
  471. package/src/home/icons/artwork/mcp-apply-preview-dark.webp +0 -0
  472. package/src/home/icons/artwork/mcp-apply-preview-light.webp +0 -0
  473. package/src/home/icons/artwork/mcp-css-compare-dark.webp +0 -0
  474. package/src/home/icons/artwork/mcp-css-compare-light.webp +0 -0
  475. package/src/home/icons/artwork/mcp-inspect-class-dark.webp +0 -0
  476. package/src/home/icons/artwork/mcp-inspect-class-light.webp +0 -0
  477. package/src/home/icons/artwork/mcp-lint-project-dark.webp +0 -0
  478. package/src/home/icons/artwork/mcp-lint-project-light.webp +0 -0
  479. package/src/home/icons/artwork/mcp-manifest-query-dark.webp +0 -0
  480. package/src/home/icons/artwork/mcp-manifest-query-light.webp +0 -0
  481. package/src/home/icons/artwork/mcp-preview-fixes-dark.webp +0 -0
  482. package/src/home/icons/artwork/mcp-preview-fixes-light.webp +0 -0
  483. package/src/home/icons/artwork/mcp-render-css-dark.webp +0 -0
  484. package/src/home/icons/artwork/mcp-render-css-light.webp +0 -0
  485. package/src/home/icons/artwork/mcp-scan-project-dark.webp +0 -0
  486. package/src/home/icons/artwork/mcp-scan-project-light.webp +0 -0
  487. package/src/home/icons/artwork/mcp-trace-class-dark.webp +0 -0
  488. package/src/home/icons/artwork/mcp-trace-class-light.webp +0 -0
  489. package/src/home/icons/artwork/render-progressive-dark.webp +0 -0
  490. package/src/home/icons/artwork/render-progressive-light.webp +0 -0
  491. package/src/home/icons/artwork/render-runtime-dark.webp +0 -0
  492. package/src/home/icons/artwork/render-runtime-light.webp +0 -0
  493. package/src/home/icons/artwork/render-static-dark.webp +0 -0
  494. package/src/home/icons/artwork/render-static-light.webp +0 -0
  495. package/src/home/icons/artwork/section-ai-agents-dark.webp +0 -0
  496. package/src/home/icons/artwork/section-ai-agents-light.webp +0 -0
  497. package/src/home/icons/artwork/section-css-size-dark.webp +0 -0
  498. package/src/home/icons/artwork/section-css-size-light.webp +0 -0
  499. package/src/home/icons/artwork/section-design-system-dark.webp +0 -0
  500. package/src/home/icons/artwork/section-design-system-light.webp +0 -0
  501. package/src/home/icons/artwork/section-editor-dark.webp +0 -0
  502. package/src/home/icons/artwork/section-editor-light.webp +0 -0
  503. package/src/home/icons/artwork/section-lint-dark.webp +0 -0
  504. package/src/home/icons/artwork/section-lint-light.webp +0 -0
  505. package/src/home/icons/artwork/section-rendering-dark.webp +0 -0
  506. package/src/home/icons/artwork/section-rendering-light.webp +0 -0
  507. package/src/home/icons/artwork/section-workflow-dark.webp +0 -0
  508. package/src/home/icons/artwork/section-workflow-light.webp +0 -0
  509. package/src/home/icons/artwork/source.json +303 -0
  510. package/src/home/icons/artwork/workflow-integrations-dark.webp +0 -0
  511. package/src/home/icons/artwork/workflow-integrations-light.webp +0 -0
  512. package/src/home/icons/artwork/workflow-monorepo-dark.webp +0 -0
  513. package/src/home/icons/artwork/workflow-monorepo-light.webp +0 -0
  514. package/src/home/icons/artwork/workflow-route-styles-dark.webp +0 -0
  515. package/src/home/icons/artwork/workflow-route-styles-light.webp +0 -0
  516. package/src/home/icons/artwork/workflow-trace-change-dark.webp +0 -0
  517. package/src/home/icons/artwork/workflow-trace-change-light.webp +0 -0
  518. package/src/home/icons/artwork.css +4 -0
  519. package/src/home/icons/artwork.ts +131 -0
  520. package/src/home/icons/catalog.ts +381 -0
  521. package/src/home/icons/design-cascade-layers.svg +32 -0
  522. package/src/home/icons/design-layout-motion.svg +16 -0
  523. package/src/home/icons/design-p3-gamut.svg +12 -0
  524. package/src/home/icons/design-theme-modes.svg +12 -0
  525. package/src/home/icons/design-theme-tokens.svg +20 -0
  526. package/src/home/icons/editor-color-tools.svg +18 -0
  527. package/src/home/icons/editor-focused-highlighting.svg +15 -0
  528. package/src/home/icons/editor-hover-inspection.svg +19 -0
  529. package/src/home/icons/editor-manifest-completions.svg +24 -0
  530. package/src/home/icons/lint-class-order-compact.svg +15 -0
  531. package/src/home/icons/lint-class-order.svg +28 -0
  532. package/src/home/icons/lint-conflicting-classes-compact.svg +11 -0
  533. package/src/home/icons/lint-conflicting-classes.svg +24 -0
  534. package/src/home/icons/lint-fix-previews-compact.svg +9 -0
  535. package/src/home/icons/lint-fix-previews.svg +19 -0
  536. package/src/home/icons/lint-invalid-classes-compact.svg +7 -0
  537. package/src/home/icons/lint-invalid-classes.svg +17 -0
  538. package/src/home/icons/lint-strict-vocabulary-compact.svg +8 -0
  539. package/src/home/icons/lint-strict-vocabulary.svg +16 -0
  540. package/src/home/icons/lint-theme-tokens-compact.svg +7 -0
  541. package/src/home/icons/lint-theme-tokens.svg +14 -0
  542. package/src/home/icons/mcp-apply-preview-compact.svg +9 -0
  543. package/src/home/icons/mcp-apply-preview.svg +18 -0
  544. package/src/home/icons/mcp-css-compare-compact.svg +9 -0
  545. package/src/home/icons/mcp-css-compare.svg +20 -0
  546. package/src/home/icons/mcp-inspect-class-compact.svg +9 -0
  547. package/src/home/icons/mcp-inspect-class.svg +18 -0
  548. package/src/home/icons/mcp-lint-project-compact.svg +14 -0
  549. package/src/home/icons/mcp-lint-project.svg +30 -0
  550. package/src/home/icons/mcp-manifest-query-compact.svg +14 -0
  551. package/src/home/icons/mcp-manifest-query.svg +27 -0
  552. package/src/home/icons/mcp-preview-fixes-compact.svg +9 -0
  553. package/src/home/icons/mcp-preview-fixes.svg +15 -0
  554. package/src/home/icons/mcp-render-css-compact.svg +13 -0
  555. package/src/home/icons/mcp-render-css.svg +30 -0
  556. package/src/home/icons/mcp-scan-project-compact.svg +7 -0
  557. package/src/home/icons/mcp-scan-project.svg +13 -0
  558. package/src/home/icons/mcp-trace-class-compact.svg +11 -0
  559. package/src/home/icons/mcp-trace-class.svg +24 -0
  560. package/src/home/icons/render-progressive.svg +17 -0
  561. package/src/home/icons/render-runtime.svg +23 -0
  562. package/src/home/icons/render-static.svg +29 -0
  563. package/src/home/icons/section-ai-agents.svg +24 -0
  564. package/src/home/icons/section-css-size.svg +13 -0
  565. package/src/home/icons/section-design-system.svg +24 -0
  566. package/src/home/icons/section-editor.svg +14 -0
  567. package/src/home/icons/section-lint.svg +14 -0
  568. package/src/home/icons/section-rendering.svg +30 -0
  569. package/src/home/icons/section-workflow.svg +22 -0
  570. package/src/home/icons/workflow-integrations.svg +15 -0
  571. package/src/home/icons/workflow-monorepo.svg +27 -0
  572. package/src/home/icons/workflow-route-styles.svg +24 -0
  573. package/src/home/icons/workflow-trace-change.svg +21 -0
  574. package/src/layouts/Document.astro +71 -0
  575. package/src/public/brand/v2/logo/mark/master-mark-small-on-dark.svg +1 -0
  576. package/src/public/brand/v2/logo/master-css/master-css-horizontal-on-dark.svg +1 -0
  577. package/src/public/brand/v2/logo/master-css/master-css-horizontal-on-light.svg +1 -0
  578. package/src/public/demo/border-grid.svg +7 -0
  579. package/src/public/demo/landscape.svg +1 -0
  580. package/src/public/demo/marker.svg +1 -0
  581. package/src/public/demo/mask.svg +1 -0
  582. package/src/public/fonts/Geist-Medium.ttf +0 -0
  583. package/src/public/fonts/Geist-Regular.ttf +0 -0
  584. package/src/public/fonts/GeistVariable.woff2 +0 -0
  585. package/src/public/fonts/IBMPlexMono-Bold.woff2 +0 -0
  586. package/src/public/fonts/IBMPlexMono-Medium.woff2 +0 -0
  587. package/src/public/fonts/IBMPlexMono-Regular.woff2 +0 -0
  588. package/src/public/fonts/IBMPlexMono-SemiBold.woff2 +0 -0
  589. package/src/public/fonts/index.css +40 -0
  590. package/src/public/icons/csharp.svg +1 -0
  591. package/src/public/icons/css.svg +1 -0
  592. package/src/public/icons/eslint.svg +1 -0
  593. package/src/public/icons/folder.svg +12 -0
  594. package/src/public/icons/html.svg +1 -0
  595. package/src/public/icons/php.svg +1 -0
  596. package/src/public/icons/sass.svg +1 -0
  597. package/src/public/icons/storybook.svg +1 -0
  598. package/src/public/icons/visualstudiocode.svg +41 -0
  599. package/src/public/images/authors/aron.jpg +0 -0
  600. package/src/public/images/authors/benseage.jpg +0 -0
  601. package/src/public/images/authors/joy.jpg +0 -0
  602. package/src/public/images/authors/lola.jpg +0 -0
  603. package/src/public/images/authors/miles.jpg +0 -0
  604. package/src/public/images/bootstrap.svg +23 -0
  605. package/src/public/images/build-tools/rsbuild.svg +1 -0
  606. package/src/public/images/build-tools/rspack.svg +1 -0
  607. package/src/public/images/build-tools/vite.svg +15 -0
  608. package/src/public/images/build-tools/webpack.svg +10 -0
  609. package/src/public/images/cdns/esm-sh.svg +1 -0
  610. package/src/public/images/chevron-left.svg +4 -0
  611. package/src/public/images/cover-bg.jpg +0 -0
  612. package/src/public/images/emotion.svg +1 -0
  613. package/src/public/images/frameworks/angular.svg +29 -0
  614. package/src/public/images/frameworks/astro.svg +4 -0
  615. package/src/public/images/frameworks/blazor.svg +22 -0
  616. package/src/public/images/frameworks/express.svg +1 -0
  617. package/src/public/images/frameworks/laravel.svg +8 -0
  618. package/src/public/images/frameworks/line-liff.svg +1 -0
  619. package/src/public/images/frameworks/lit.svg +1 -0
  620. package/src/public/images/frameworks/nextjs.svg +16 -0
  621. package/src/public/images/frameworks/nuxtjs.svg +3 -0
  622. package/src/public/images/frameworks/rails.svg +1 -0
  623. package/src/public/images/frameworks/react.svg +8 -0
  624. package/src/public/images/frameworks/remix.svg +5 -0
  625. package/src/public/images/frameworks/shopify.svg +1 -0
  626. package/src/public/images/frameworks/svelte.svg +6 -0
  627. package/src/public/images/frameworks/tanstack.svg +1 -0
  628. package/src/public/images/frameworks/vuejs.svg +11 -0
  629. package/src/public/images/frameworks/wordpress.svg +1 -0
  630. package/src/public/images/mui.svg +1 -0
  631. package/src/public/images/styled-components.svg +4 -0
  632. package/src/public/images/tailwindcss.svg +1 -0
  633. package/src/scripts/bundler-imports.ts +25 -0
  634. package/src/scripts/static-social.ts +333 -0
  635. package/src/scripts/write-if-changed.ts +26 -0
  636. package/src/sections/blog.astro +11 -0
  637. package/src/sections/design-system.astro +14 -0
  638. package/src/sections/document.astro +8 -0
  639. package/src/sections/examples.astro +6 -0
  640. package/src/sections/guide.astro +26 -0
  641. package/src/sections/home.astro +7 -0
  642. package/src/sections/page.astro +12 -0
  643. package/src/styles/base.css +57 -0
  644. package/src/styles/benchmarks.css +20 -0
  645. package/src/styles/blog-article.css +670 -0
  646. package/src/styles/blog-materials.css +399 -0
  647. package/src/styles/blog.css +568 -0
  648. package/src/styles/demo.css +30 -0
  649. package/src/styles/design-system.css +15 -0
  650. package/src/styles/docs-shell/code.css +61 -0
  651. package/src/styles/docs-shell/docs.css +79 -0
  652. package/src/styles/docs-shell/documentation-search.css +42 -0
  653. package/src/styles/docs-shell/footer.css +38 -0
  654. package/src/styles/docs-shell/header.css +73 -0
  655. package/src/styles/docs-shell/materials.css +25 -0
  656. package/src/styles/docs-shell/menu.css +19 -0
  657. package/src/styles/docs-shell/not-found.css +10 -0
  658. package/src/styles/docs-shell/page-content.css +37 -0
  659. package/src/styles/docs-shell/prose.css +89 -0
  660. package/src/styles/docs-shell/segments.css +13 -0
  661. package/src/styles/docs-shell/steps.css +39 -0
  662. package/src/styles/docs-shell/syntax-theme.css +18 -0
  663. package/src/styles/docs-shell/theme.css +68 -0
  664. package/src/styles/docs-shell/wrapper.css +10 -0
  665. package/src/styles/document-comparison.css +7 -0
  666. package/src/styles/documentation-illustration.css +34 -0
  667. package/src/styles/documentation-index.css +100 -0
  668. package/src/styles/documents.css +4 -0
  669. package/src/styles/documents.ts +2 -0
  670. package/src/styles/foundation.css +4 -0
  671. package/src/styles/globals.css +2 -0
  672. package/src/styles/interface.css +3 -0
  673. package/src/styles/interface.ts +2 -0
  674. package/src/styles/site.ts +2 -0
  675. package/src/styles/system/DESIGN.md +108 -0
  676. package/src/styles/system/buttons.css +51 -0
  677. package/src/styles/system/code.css +85 -0
  678. package/src/styles/system/controls.css +110 -0
  679. package/src/styles/system/data.css +134 -0
  680. package/src/styles/system/mixins.css +7 -0
  681. package/src/styles/system/prose.css +75 -0
  682. package/src/styles/system/shell.css +102 -0
  683. package/src/styles/system/specimens.css +98 -0
  684. package/src/styles/system/surfaces.css +104 -0
  685. package/src/styles/system/tokens.css +136 -0
  686. package/src/utils/cloudflare-image-loader.js +85 -0
  687. package/src/virtual.d.ts +36 -0
@@ -0,0 +1,617 @@
1
+ <script lang="ts">
2
+ import { heroClothSource, heroCompositeSource, heroCopySource, heroPlaneScale, heroVertexSource } from './hero-shaders'
3
+ import { rasterizeHeroTitle, type HeroTitleMask } from './hero-title-mask'
4
+
5
+ const renderScale = 0.6
6
+ const introDuration = 2200
7
+ const materialDuration = 800
8
+ const glintDelay = 260
9
+ const glintDuration = 1700
10
+ const touchDuration = 2600
11
+ const rippleDuration = 2.5
12
+ // The silk renders into its own low-density target, so the output pass is cheap enough to reach the
13
+ // display's density on most screens; a slow GPU steps it down at runtime.
14
+ const compositePixelBudget = 9_000_000
15
+ const minimumCompositeBudget = 2_000_000
16
+ const backgroundPixelBudget = 1_500_000
17
+ // Named directly: an island wrapper with `display: contents` sits between the action row and the command.
18
+ const litSelector = '.home-hero-pill, .home-hero-actions .home-action-primary, .home-hero-actions .home-command'
19
+ const litProperties = ['--lit-x', '--lit-y', '--lit-angle', '--cast-x', '--cast-y', '--lit-near']
20
+
21
+ type Bounds = [number, number, number, number]
22
+
23
+ interface LitControl {
24
+ element: HTMLElement
25
+ focus: number
26
+ left: number
27
+ top: number
28
+ width: number
29
+ height: number
30
+ values: string[]
31
+ }
32
+
33
+ /** Matte gold and a cut-stone title share one lamp; controls read the same lamp through CSS properties. */
34
+ let { class: className }: { class?: string } = $props()
35
+ let canvasRef = $state<HTMLCanvasElement>()
36
+ // A restored WebGL context mounts the field again from scratch.
37
+ let generation = $state(0)
38
+
39
+ $effect(() => {
40
+ void generation
41
+ const canvas = canvasRef
42
+ const host = canvas?.closest<HTMLElement>('[data-glyph-host]')
43
+ const title = host?.querySelector<HTMLElement>('[data-glass-title]')
44
+ const readingArea = host?.querySelector<HTMLElement>('.home-hero-actions')
45
+ if (!canvas || !host || !title) return
46
+ const header = document.querySelector<HTMLElement>('.home-header')
47
+ const body = host.querySelector<HTMLElement>('.home-hero-body')
48
+ let gl: WebGLRenderingContext | null = null
49
+ try {
50
+ gl = canvas.getContext('webgl', { antialias: false, depth: false, stencil: false })
51
+ } catch {
52
+ // A readable DOM composition is already present when WebGL is unavailable.
53
+ }
54
+ if (!gl) { canvas.hidden = true; return }
55
+ const context = gl
56
+ const probe = document.createElement('canvas').getContext('2d', { willReadFrequently: true })
57
+ if (!probe) { canvas.hidden = true; return }
58
+ const motion = matchMedia('(prefers-reduced-motion: reduce)')
59
+ const contrast = matchMedia('(forced-colors: active)')
60
+ const print = matchMedia('print')
61
+ const scheme = matchMedia('(prefers-color-scheme: dark)')
62
+ const opaque = matchMedia('(prefers-reduced-transparency: reduce), (prefers-contrast: more)')
63
+ const programs: WebGLProgram[] = []
64
+ const shaders: WebGLShader[] = []
65
+ const textures: WebGLTexture[] = []
66
+ const buffers: WebGLBuffer[] = []
67
+ const framebuffers: WebGLFramebuffer[] = []
68
+ let contextLost = false
69
+ let released = false
70
+ const clearReady = () => {
71
+ host.removeAttribute('data-glass-ready')
72
+ host.removeAttribute('data-lens-ready')
73
+ }
74
+ const release = () => {
75
+ // Restoration invalidates old handles; the driver has already reclaimed these resources.
76
+ if (contextLost || released) return
77
+ released = true
78
+ programs.forEach((item) => context.deleteProgram(item))
79
+ shaders.forEach((item) => context.deleteShader(item))
80
+ textures.forEach((item) => context.deleteTexture(item))
81
+ buffers.forEach((item) => context.deleteBuffer(item))
82
+ framebuffers.forEach((item) => context.deleteFramebuffer(item))
83
+ }
84
+ const program = (source: string, names: string[]) => {
85
+ const result = context.createProgram()
86
+ if (!result) throw new Error('Cannot allocate a hero program')
87
+ programs.push(result)
88
+ for (const [type, sourceText] of [[context.VERTEX_SHADER, heroVertexSource], [context.FRAGMENT_SHADER, source]] as const) {
89
+ const shader = context.createShader(type)
90
+ if (!shader) throw new Error('Cannot allocate a hero shader')
91
+ shaders.push(shader)
92
+ context.shaderSource(shader, sourceText)
93
+ context.compileShader(shader)
94
+ if (!context.getShaderParameter(shader, context.COMPILE_STATUS)) throw new Error('Cannot compile a hero shader')
95
+ context.attachShader(result, shader)
96
+ }
97
+ context.bindAttribLocation(result, 0, 'position')
98
+ context.linkProgram(result)
99
+ if (!context.getProgramParameter(result, context.LINK_STATUS)) throw new Error('Cannot link a hero program')
100
+ return { program: result, uniforms: Object.fromEntries(names.map((name) => [name, context.getUniformLocation(result, name)])) }
101
+ }
102
+ const texture = (unit: number) => {
103
+ const result = context.createTexture()
104
+ if (!result) throw new Error('Cannot allocate a hero texture')
105
+ textures.push(result)
106
+ context.activeTexture(context.TEXTURE0 + unit)
107
+ context.bindTexture(context.TEXTURE_2D, result)
108
+ context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.LINEAR)
109
+ context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MAG_FILTER, context.LINEAR)
110
+ context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_S, context.CLAMP_TO_EDGE)
111
+ context.texParameteri(context.TEXTURE_2D, context.TEXTURE_WRAP_T, context.CLAMP_TO_EDGE)
112
+ context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, 1, 1, 0, context.RGBA, context.UNSIGNED_BYTE, new Uint8Array(4))
113
+ return result
114
+ }
115
+ let cloth: ReturnType<typeof program>
116
+ let composite: ReturnType<typeof program>
117
+ let copy: ReturnType<typeof program>
118
+ let scene: WebGLTexture
119
+ let glyphs: WebGLTexture
120
+ let target: WebGLFramebuffer
121
+ try {
122
+ cloth = program(heroClothSource, ['resolution', 'time', 'pointer', 'lamp', 'drift', 'ripple', 'shadow', 'body', 'sheen', 'ground', 'title', 'readingArea', 'fontSize'])
123
+ composite = program(heroCompositeSource, ['resolution', 'title', 'fontSize', 'distanceRange', 'material', 'glint', 'time', 'lamp', 'ink', 'ground', 'scene', 'glyphs'])
124
+ copy = program(heroCopySource, ['scene', 'glyphs', 'resolution', 'time', 'ground', 'title', 'fontSize', 'distanceRange', 'lamp', 'shade', 'intro', 'lenses', 'lensRadii', 'lensFocus'])
125
+ const buffer = context.createBuffer()
126
+ if (!buffer) throw new Error('Cannot allocate a hero triangle')
127
+ buffers.push(buffer)
128
+ context.bindBuffer(context.ARRAY_BUFFER, buffer)
129
+ context.bufferData(context.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), context.STATIC_DRAW)
130
+ context.enableVertexAttribArray(0)
131
+ context.vertexAttribPointer(0, 2, context.FLOAT, false, 0, 0)
132
+ scene = texture(0)
133
+ glyphs = texture(1)
134
+ const framebuffer = context.createFramebuffer()
135
+ if (!framebuffer) throw new Error('Cannot allocate a hero background')
136
+ target = framebuffer
137
+ framebuffers.push(target)
138
+ context.bindFramebuffer(context.FRAMEBUFFER, target)
139
+ context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, scene, 0)
140
+ context.bindFramebuffer(context.FRAMEBUFFER, null)
141
+ } catch {
142
+ canvas.hidden = true
143
+ release()
144
+ return
145
+ }
146
+
147
+ let disposed = false
148
+ let failed = false
149
+ let visible = true
150
+ let fontsReady = false
151
+ let dirty = true
152
+ let frame = 0
153
+ let width = 1
154
+ let height = 1
155
+ let sceneWidth = 0
156
+ let sceneHeight = 0
157
+ let startedAt = -1
158
+ let materialAt = -1
159
+ let darkScheme: boolean | undefined
160
+ let previousFrame = -1
161
+ let sceneTime = 8
162
+ let budget = compositePixelBudget
163
+ let slowFrames = 0
164
+ let scissor: Bounds = [0, 0, 0, 0]
165
+ let mask: HeroTitleMask | null = null
166
+ let maskKey = ''
167
+ let fontFace: FontFace | undefined
168
+ const pointer = { x: 0, y: 0, targetX: 0, targetY: 0, strength: 0, targetStrength: 0 }
169
+ // The lamp rests over the title's first line, left of center, and drifts, staying with the viewer as the page scrolls.
170
+ // A mouse picks it up and carries it lower; keyboard focus hangs it over the focused control; a tap
171
+ // sets it down where the finger touched for a moment.
172
+ const lamp = { x: 0, y: 0, z: 0, clientX: 0, clientY: 0, focusX: 0, focusY: 0, until: 0, source: 'rest' as 'rest' | 'pointer' | 'focus' | 'touch', placed: false }
173
+ const rest = { x: 0, y: 0, z: 1, sway: 0, fontSize: 1, left: 0, top: 0, right: 0, bottom: 0 }
174
+ const origin = { left: 0, top: 0, scroll: 0 }
175
+ // On a phone, tilting the device swings the resting lamp, as turning a stone in the hand would.
176
+ const tilt = { x: 0, y: 0, targetX: 0, targetY: 0 }
177
+ const ripple = { x: 0, y: 0, at: -1 }
178
+ let lit: LitControl[] = []
179
+ let lenses: LitControl[] = []
180
+ let litAt = -Infinity
181
+ const maximumTexture = context.getParameter(context.MAX_TEXTURE_SIZE) as number
182
+ const maximumViewport = context.getParameter(context.MAX_VIEWPORT_DIMS) as Int32Array
183
+ const maximumSurface = Math.min(maximumTexture, maximumViewport[0], maximumViewport[1])
184
+ const fallback = () => {
185
+ failed = true
186
+ unlight()
187
+ cancelAnimationFrame(frame)
188
+ frame = 0
189
+ clearReady()
190
+ canvas.hidden = true
191
+ release()
192
+ }
193
+ const channels = (color: string) => {
194
+ probe.clearRect(0, 0, 1, 1)
195
+ probe.fillStyle = '#000'
196
+ probe.fillStyle = color
197
+ probe.fillRect(0, 0, 1, 1)
198
+ const [red, green, blue] = probe.getImageData(0, 0, 1, 1).data
199
+ return [red / 255, green / 255, blue / 255] as const
200
+ }
201
+ const clip = (bounds: Bounds, padding = 0): Bounds => {
202
+ const left = Math.max(0, Math.floor((bounds[0] - padding) * canvas.width / width))
203
+ const bottom = Math.max(0, Math.floor((height - bounds[1] - bounds[3] - padding) * canvas.height / height))
204
+ const right = Math.min(canvas.width, Math.ceil((bounds[0] + bounds[2] + padding) * canvas.width / width))
205
+ const top = Math.min(canvas.height, Math.ceil((height - bounds[1] + padding) * canvas.height / height))
206
+ return [left, bottom, Math.max(0, right - left), Math.max(0, top - bottom)]
207
+ }
208
+ const layout = () => {
209
+ const rect = canvas.getBoundingClientRect()
210
+ if (!rect.width || !rect.height) return false
211
+ width = rect.width
212
+ height = rect.height
213
+ // Phones at 3× fit their full density within the output budget, so the stone stays as crisp as native type.
214
+ const maskRatio = Math.min(devicePixelRatio || 1, 3, maximumTexture / (Math.max(width, height) + 16))
215
+ const ratio = Math.min(maskRatio, Math.sqrt(budget / (width * height)), maximumSurface / Math.max(width, height))
216
+ const pixelWidth = Math.max(1, Math.floor(width * ratio))
217
+ const pixelHeight = Math.max(1, Math.floor(height * ratio))
218
+ if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
219
+ canvas.width = pixelWidth
220
+ canvas.height = pixelHeight
221
+ }
222
+ const backgroundRatio = Math.min(maskRatio * renderScale, Math.sqrt(backgroundPixelBudget / (width * height)))
223
+ const backgroundWidth = Math.max(1, Math.floor(width * backgroundRatio))
224
+ const backgroundHeight = Math.max(1, Math.floor(height * backgroundRatio))
225
+ if (sceneWidth !== backgroundWidth || sceneHeight !== backgroundHeight) {
226
+ sceneWidth = backgroundWidth
227
+ sceneHeight = backgroundHeight
228
+ context.activeTexture(context.TEXTURE0)
229
+ context.bindTexture(context.TEXTURE_2D, scene)
230
+ context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, sceneWidth, sceneHeight, 0, context.RGBA, context.UNSIGNED_BYTE, null)
231
+ context.bindFramebuffer(context.FRAMEBUFFER, target)
232
+ if (context.checkFramebufferStatus(context.FRAMEBUFFER) !== context.FRAMEBUFFER_COMPLETE) throw new Error('Incomplete hero background')
233
+ context.bindFramebuffer(context.FRAMEBUFFER, null)
234
+ }
235
+ const titleStyle = getComputedStyle(title)
236
+ const titleRect = title.getBoundingClientRect()
237
+ const key = [title.textContent, titleStyle.font, titleStyle.letterSpacing, titleStyle.fontFeatureSettings, titleStyle.lineHeight, titleRect.x - rect.x, titleRect.y - rect.y, titleRect.width, titleRect.height, maskRatio, document.documentElement.lang].join('|')
238
+ if (fontsReady && key !== maskKey) {
239
+ mask = rasterizeHeroTitle(title, canvas, maskRatio, titleStyle.fontFamily.replace(/\bGeist\b/, 'Home Hero Geist'))
240
+ maskKey = key
241
+ context.activeTexture(context.TEXTURE1)
242
+ context.bindTexture(context.TEXTURE_2D, glyphs)
243
+ if (mask) {
244
+ context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, mask.width, mask.height, 0, context.RGBA, context.UNSIGNED_BYTE, mask.pixels)
245
+ } else {
246
+ host.removeAttribute('data-glass-ready')
247
+ }
248
+ }
249
+ const bounds: Bounds = mask ? [mask.left, mask.top, mask.cssWidth, mask.cssHeight] : [titleRect.left - rect.left, titleRect.top - rect.top, titleRect.width, titleRect.height]
250
+ scissor = clip(bounds)
251
+ const style = getComputedStyle(canvas)
252
+ const ground = channels(getComputedStyle(host).backgroundColor)
253
+ for (const renderer of [cloth, composite, copy]) {
254
+ context.useProgram(renderer.program)
255
+ context.uniform2f(renderer.uniforms.resolution, width, height)
256
+ if ('ground' in renderer.uniforms) context.uniform3f(renderer.uniforms.ground, ...ground)
257
+ if ('scene' in renderer.uniforms) context.uniform1i(renderer.uniforms.scene, 0)
258
+ }
259
+ const fontSize = mask?.fontSize ?? parseFloat(titleStyle.fontSize)
260
+ for (const renderer of [cloth, composite, copy]) {
261
+ context.useProgram(renderer.program)
262
+ context.uniform4f(renderer.uniforms.title, ...bounds)
263
+ context.uniform1f(renderer.uniforms.fontSize, fontSize)
264
+ }
265
+ context.useProgram(copy.program)
266
+ context.uniform1i(copy.uniforms.glyphs, 1)
267
+ context.uniform1f(copy.uniforms.distanceRange, mask?.range ?? 1)
268
+ const groundLight = ground[0] * 0.2126 + ground[1] * 0.7152 + ground[2] * 0.0722
269
+ // Switching themes re-cuts the title: the native ink returns, then the other stone forms and glints.
270
+ if (darkScheme !== undefined && darkScheme !== groundLight <= 0.4) materialAt = -1
271
+ darkScheme = groundLight <= 0.4
272
+ // Obsidian casts a clear shadow on champagne silk; on dark silk it only separates the moonstone.
273
+ context.uniform1f(copy.uniforms.shade, mask ? (groundLight > 0.4 ? 1 : 0.45) : 0)
274
+ origin.left = rect.left
275
+ origin.top = rect.top
276
+ origin.scroll = scrollY
277
+ rest.x = titleRect.left - rect.left + titleRect.width * 0.3
278
+ // Over the first line, so as the lamp sways its reflection now and then slides across the letters.
279
+ rest.y = titleRect.top - rect.top + fontSize * 0.3
280
+ rest.z = fontSize * 5
281
+ rest.sway = titleRect.width * 0.2
282
+ rest.left = titleRect.left - rect.left
283
+ rest.top = titleRect.top - rect.top
284
+ rest.right = rest.left + titleRect.width
285
+ rest.bottom = rest.top + titleRect.height
286
+ rest.fontSize = fontSize
287
+ lit = Array.from(host.querySelectorAll<HTMLElement>(litSelector), (element) => {
288
+ const box = element.getBoundingClientRect()
289
+ const previous = lit.find((item) => item.element === element)
290
+ return { element, focus: previous?.focus ?? 0, left: box.left - rect.left, top: box.top - rect.top, width: box.width, height: box.height, values: [] }
291
+ })
292
+ // Liquid-glass controls refract the silk drawn beneath them.
293
+ lenses = opaque.matches ? [] : lit.filter((control) => control.element.classList.contains('home-glass')).slice(0, 2)
294
+ context.useProgram(copy.program)
295
+ context.uniform4fv(copy.uniforms.lenses, [0, 1].flatMap((index) => {
296
+ const lens = lenses[index]
297
+ return lens ? [lens.left, lens.top, lens.width, lens.height] : [0, 0, 0, 0]
298
+ }))
299
+ context.uniform2f(copy.uniforms.lensRadii, ...[0, 1].map((index) => {
300
+ const lens = lenses[index]
301
+ return lens ? Math.min(parseFloat(getComputedStyle(lens.element).borderTopLeftRadius) || 0, lens.width / 2, lens.height / 2) : 0
302
+ }) as [number, number])
303
+ context.useProgram(cloth.program)
304
+ const readingRect = readingArea?.getBoundingClientRect()
305
+ context.uniform4f(cloth.uniforms.readingArea, (readingRect?.left ?? rect.left) - rect.left, (readingRect?.top ?? rect.top) - rect.top, readingRect?.width ?? 0, readingRect?.height ?? 0)
306
+ context.uniform3f(cloth.uniforms.shadow, ...channels(style.color))
307
+ context.uniform3f(cloth.uniforms.body, ...channels(style.caretColor))
308
+ context.uniform3f(cloth.uniforms.sheen, ...channels(style.outlineColor))
309
+ context.useProgram(composite.program)
310
+ context.uniform1f(composite.uniforms.distanceRange, mask?.range ?? 1)
311
+ context.uniform3f(composite.uniforms.ink, ...channels(titleStyle.color))
312
+ context.uniform1i(composite.uniforms.glyphs, 1)
313
+ return true
314
+ }
315
+ const canDraw = () => !disposed && !failed && visible && !document.hidden && !contrast.matches && !print.matches
316
+ const schedule = () => {
317
+ if (!frame && canDraw()) frame = requestAnimationFrame(tick)
318
+ }
319
+ const invalidate = () => { dirty = true; schedule() }
320
+ const tick = (time: number) => {
321
+ frame = 0
322
+ if (!canDraw()) return
323
+ try {
324
+ if (dirty) {
325
+ if (!layout()) return
326
+ dirty = false
327
+ }
328
+ if (startedAt < 0) startedAt = time
329
+ if (mask && materialAt < 0) materialAt = time
330
+ const reduced = motion.matches
331
+ const delta = previousFrame < 0 ? 0 : Math.min(64, time - previousFrame)
332
+ previousFrame = time
333
+ // After the arrival settles, sustained frames under ~40fps trade output density for smoothness.
334
+ if (time - startedAt > introDuration + 1000 && budget > minimumCompositeBudget) {
335
+ slowFrames = delta > 25 ? slowFrames + 1 : Math.max(0, slowFrames - 2)
336
+ if (slowFrames > 45) {
337
+ slowFrames = 0
338
+ budget = Math.max(minimumCompositeBudget, Math.min(budget, canvas.width * canvas.height) * 0.6)
339
+ dirty = true
340
+ }
341
+ }
342
+ if (!reduced) sceneTime += delta / 1000
343
+ const follow = 1 - Math.exp(-delta / 180)
344
+ pointer.x += (pointer.targetX - pointer.x) * follow
345
+ pointer.y += (pointer.targetY - pointer.y) * follow
346
+ pointer.strength += ((reduced ? 0 : pointer.targetStrength) - pointer.strength) * (1 - Math.exp(-delta / 260))
347
+ const sceneClock = sceneTime
348
+ const opened = reduced ? 1 : Math.min(1, (time - startedAt) / introDuration)
349
+ const formed = reduced ? 1 : Math.max(0, Math.min(1, (time - materialAt) / materialDuration))
350
+ const material = 1 - Math.pow(1 - formed, 3)
351
+ const glint = reduced || materialAt < 0 ? 1 : Math.max(0, Math.min(1, (time - materialAt - glintDelay) / glintDuration))
352
+ // Client coordinates convert through the scroll since the last layout; the resting lamp and the silk's drift
353
+ // follow the page's own scroll, so a layout taken mid-page (re-entering view, a resize) cannot shift them.
354
+ const scrolled = scrollY - origin.scroll
355
+ const travelled = Math.max(0, scrollY)
356
+ tilt.x += (tilt.targetX - tilt.x) * follow
357
+ tilt.y += (tilt.targetY - tilt.y) * follow
358
+ let targetX = rest.x + Math.sin(sceneClock * 0.19) * rest.sway + tilt.x * rest.sway * 2
359
+ let targetY = rest.y + Math.cos(sceneClock * 0.15) * rest.fontSize * 0.3 + tilt.y * rest.fontSize * 1.5 + (reduced ? 0 : travelled)
360
+ if (lamp.source === 'touch' && time > lamp.until) {
361
+ lamp.source = 'rest'
362
+ pointer.targetStrength = 0
363
+ }
364
+ if (lamp.source === 'pointer' || lamp.source === 'touch') {
365
+ targetX = lamp.clientX - origin.left
366
+ targetY = lamp.clientY - origin.top + scrolled
367
+ pointer.targetX = (targetX / width - 0.5) * width / height * heroPlaneScale
368
+ pointer.targetY = (0.5 - targetY / height) * heroPlaneScale
369
+ } else if (lamp.source === 'focus') {
370
+ targetX = lamp.focusX
371
+ targetY = lamp.focusY
372
+ }
373
+ // The lamp lowers into place with the silk, so shadows grow from short and faint to their resting length.
374
+ const lowered = 1 - Math.pow(1 - opened, 3)
375
+ // Held over the title, the lamp comes closer, as if to examine the stone: longer shadows, a tighter glint.
376
+ const examining = lamp.source === 'pointer' && targetX > rest.left && targetX < rest.right && targetY > rest.top && targetY < rest.bottom
377
+ const targetZ = lamp.source === 'rest' ? rest.z * (1 + (1 - lowered) * 2.5) : rest.fontSize * (examining ? 2.2 : 3.2)
378
+ // A held lamp follows the hand closely; let go, it drifts back to its resting place.
379
+ const carry = lamp.placed ? 1 - Math.exp(-delta / (lamp.source === 'rest' ? 700 : 120)) : 1
380
+ lamp.x += (targetX - lamp.x) * carry
381
+ lamp.y += (targetY - lamp.y) * carry
382
+ lamp.z += (targetZ - lamp.z) * carry
383
+ lamp.placed = true
384
+ // A drifting lamp moves the controls' light by a fraction of a percent per frame; restyling them ten
385
+ // times a second is indistinguishable and spares most style recalculation. A held lamp updates every frame.
386
+ if (lamp.source !== 'rest' || time - litAt > 100) {
387
+ litAt = time
388
+ illuminate()
389
+ }
390
+ context.bindFramebuffer(context.FRAMEBUFFER, target)
391
+ context.viewport(0, 0, sceneWidth, sceneHeight)
392
+ context.useProgram(cloth.program)
393
+ context.uniform1f(cloth.uniforms.time, sceneClock)
394
+ context.uniform3f(cloth.uniforms.pointer, pointer.x, pointer.y, reduced ? 0 : pointer.strength)
395
+ context.uniform3f(cloth.uniforms.lamp, lamp.x, lamp.y, lamp.z)
396
+ context.uniform1f(cloth.uniforms.drift, reduced ? 0 : travelled / height * heroPlaneScale * 0.3)
397
+ const rippleAge = ripple.at < 0 || reduced ? -1 : (time - ripple.at) / 1000
398
+ context.uniform3f(cloth.uniforms.ripple, ripple.x, ripple.y, rippleAge > rippleDuration ? -1 : rippleAge)
399
+ context.drawArrays(context.TRIANGLES, 0, 3)
400
+ context.bindFramebuffer(context.FRAMEBUFFER, null)
401
+ context.viewport(0, 0, canvas.width, canvas.height)
402
+ context.useProgram(copy.program)
403
+ context.uniform1f(copy.uniforms.time, sceneClock)
404
+ context.uniform3f(copy.uniforms.lamp, lamp.x, lamp.y, lamp.z)
405
+ context.uniform1f(copy.uniforms.intro, 1 - Math.pow(1 - opened, 3))
406
+ // Hovered or focused glass is drawn a little closer: it magnifies and bends more.
407
+ for (const lens of lenses) {
408
+ const engaged = !reduced && lens.element.matches(':hover, :focus-within')
409
+ lens.focus += ((engaged ? 1 : 0) - lens.focus) * (1 - Math.exp(-delta / 160))
410
+ }
411
+ context.uniform2f(copy.uniforms.lensFocus, lenses[0]?.focus ?? 0, lenses[1]?.focus ?? 0)
412
+ context.drawArrays(context.TRIANGLES, 0, 3)
413
+ context.enable(context.SCISSOR_TEST)
414
+ context.enable(context.BLEND)
415
+ context.blendFuncSeparate(context.SRC_ALPHA, context.ONE_MINUS_SRC_ALPHA, context.ONE, context.ONE_MINUS_SRC_ALPHA)
416
+ if (mask) {
417
+ context.useProgram(composite.program)
418
+ context.uniform1f(composite.uniforms.time, sceneClock)
419
+ context.uniform3f(composite.uniforms.lamp, lamp.x, lamp.y, lamp.z)
420
+ context.uniform1f(composite.uniforms.material, material)
421
+ context.uniform1f(composite.uniforms.glint, glint)
422
+ context.scissor(...scissor)
423
+ context.drawArrays(context.TRIANGLES, 0, 3)
424
+ }
425
+ context.disable(context.SCISSOR_TEST)
426
+ context.disable(context.BLEND)
427
+ if (!host.hasAttribute('data-lens-ready')) host.setAttribute('data-lens-ready', '')
428
+ if (mask && !host.hasAttribute('data-glass-ready')) {
429
+ if (context.getError() !== context.NO_ERROR) throw new Error('Cannot draw hero glass')
430
+ if (mask) host.setAttribute('data-glass-ready', '')
431
+ }
432
+ if (!reduced) schedule()
433
+ } catch {
434
+ if (!disposed) fallback()
435
+ }
436
+ }
437
+ // Native controls read the lamp as a highlight position, a rim angle and a cast-shadow offset.
438
+ const illuminate = () => {
439
+ for (const control of lit) {
440
+ const centerX = control.left + control.width / 2
441
+ const centerY = control.top + control.height / 2
442
+ const elevation = 6
443
+ const scale = elevation / Math.max(lamp.z - elevation, 1)
444
+ const castX = Math.max(-10, Math.min(10, (centerX - lamp.x) * scale))
445
+ const castY = Math.max(-10, Math.min(10, (centerY - lamp.y) * scale))
446
+ const near = Math.exp(-(((lamp.x - centerX) / (control.width * 0.9)) ** 2 + ((lamp.y - centerY) / (control.height * 2.4)) ** 2))
447
+ // Rounded to what the eye can tell apart, so a drifting lamp restyles the controls only now and then.
448
+ const values = [
449
+ `${Math.round(Math.max(-60, Math.min(160, (lamp.x - control.left) / control.width * 100)))}%`,
450
+ `${Math.round(Math.max(-160, Math.min(260, (lamp.y - control.top) / control.height * 100)))}%`,
451
+ `${Math.round(Math.atan2(lamp.x - centerX, centerY - lamp.y) * 180 / Math.PI)}deg`,
452
+ `${castX.toFixed(1)}px`,
453
+ `${castY.toFixed(1)}px`,
454
+ (lamp.source === 'rest' ? near * 0.4 : near).toFixed(2)
455
+ ]
456
+ litProperties.forEach((name, index) => {
457
+ if (values[index] !== control.values[index]) control.element.style.setProperty(name, values[index])
458
+ })
459
+ control.values = values
460
+ }
461
+ }
462
+ const unlight = () => {
463
+ for (const control of lit) litProperties.forEach((name) => control.element.style.removeProperty(name))
464
+ }
465
+ const activity = () => {
466
+ cancelAnimationFrame(frame)
467
+ frame = 0
468
+ previousFrame = -1
469
+ canvas.hidden = failed || contrast.matches || print.matches
470
+ if (contrast.matches || print.matches) clearReady()
471
+ dirty = true
472
+ schedule()
473
+ }
474
+ const move = (event: PointerEvent) => {
475
+ if (motion.matches || event.pointerType !== 'mouse') return
476
+ pointer.targetStrength = 1
477
+ lamp.clientX = event.clientX
478
+ lamp.clientY = event.clientY
479
+ lamp.source = 'pointer'
480
+ }
481
+ // Touch never holds the lamp, so it cannot interfere with scrolling; it only sets it down briefly.
482
+ const tap = (event: PointerEvent) => {
483
+ if (motion.matches || event.pointerType === 'mouse' || !event.isPrimary) return
484
+ pointer.targetStrength = 1
485
+ lamp.clientX = event.clientX
486
+ lamp.clientY = event.clientY
487
+ lamp.until = performance.now() + touchDuration
488
+ lamp.source = 'touch'
489
+ }
490
+ // A mouse may press anywhere on the silk; touch and keys ripple only from a control, so scrolling stays quiet.
491
+ const press = (event: PointerEvent | KeyboardEvent) => {
492
+ if (motion.matches) return
493
+ const control = lit.find((item) => item.element.contains(event.target as Node))
494
+ if (event instanceof KeyboardEvent) {
495
+ // Only keys that activate: Enter on a link or button, Space on a button (on a link it scrolls).
496
+ const activates = event.key === 'Enter' || (event.key === ' ' && (event.target as Element).closest('button'))
497
+ if (!control || !activates) return
498
+ } else if (!control && (event.pointerType !== 'mouse' || event.button !== 0)) return
499
+ const rect = canvas.getBoundingClientRect()
500
+ const x = event instanceof PointerEvent ? event.clientX - rect.left : control!.left + control!.width / 2
501
+ const y = event instanceof PointerEvent ? event.clientY - rect.top : control!.top + control!.height / 2
502
+ ripple.x = (x / width - 0.5) * width / height * heroPlaneScale
503
+ ripple.y = (0.5 - y / height) * heroPlaneScale
504
+ ripple.at = performance.now()
505
+ }
506
+ const leave = () => {
507
+ pointer.targetStrength = 0
508
+ if (lamp.source === 'pointer') lamp.source = 'rest'
509
+ }
510
+ const focus = (event: FocusEvent) => {
511
+ const control = lit.find((item) => item.element.contains(event.target as Node))
512
+ if (motion.matches || !control || !(event.target as Element).matches(':focus-visible')) return
513
+ lamp.focusX = control.left + control.width * 0.35
514
+ lamp.focusY = control.top - control.height * 0.6
515
+ lamp.source = 'focus'
516
+ }
517
+ const blur = (event: FocusEvent) => {
518
+ if (lamp.source === 'focus' && !host.contains(event.relatedTarget as Node)) lamp.source = 'rest'
519
+ }
520
+ const orient = (event: DeviceOrientationEvent) => {
521
+ if (motion.matches || event.beta === null || event.gamma === null) return
522
+ // Relative to a phone held at a comfortable reading angle.
523
+ tilt.targetX = Math.max(-1, Math.min(1, event.gamma / 25))
524
+ tilt.targetY = Math.max(-1, Math.min(1, (event.beta - 40) / 25))
525
+ }
526
+ const lost = (event: Event) => { event.preventDefault(); contextLost = true; fallback() }
527
+ const restored = () => { generation += 1 }
528
+ const resize = new ResizeObserver(invalidate)
529
+ resize.observe(canvas)
530
+ resize.observe(title)
531
+ if (readingArea) resize.observe(readingArea)
532
+ if (body) resize.observe(body)
533
+ const theme = new MutationObserver(invalidate)
534
+ theme.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'data-theme', 'style', 'lang'] })
535
+ const text = new MutationObserver(invalidate)
536
+ text.observe(title, { childList: true, characterData: true, subtree: true })
537
+ // Notifications batch while layout settles; the last entry is the current state.
538
+ const intersection = new IntersectionObserver((entries) => { const entry = entries[entries.length - 1]; visible = entry.isIntersecting; activity() })
539
+ intersection.observe(host)
540
+ document.addEventListener('visibilitychange', activity)
541
+ document.fonts.addEventListener('loadingdone', invalidate)
542
+ window.addEventListener('resize', invalidate)
543
+ motion.addEventListener('change', activity)
544
+ contrast.addEventListener('change', activity)
545
+ print.addEventListener('change', activity)
546
+ scheme.addEventListener('change', invalidate)
547
+ opaque.addEventListener('change', invalidate)
548
+ host.addEventListener('pointermove', move)
549
+ host.addEventListener('pointerleave', leave)
550
+ host.addEventListener('pointerdown', tap)
551
+ host.addEventListener('pointerdown', press)
552
+ host.addEventListener('keydown', press)
553
+ host.addEventListener('focusin', focus)
554
+ host.addEventListener('focusout', blur)
555
+ // Only browsers that grant orientation without a permission prompt take part.
556
+ const coarse = matchMedia('(pointer: coarse)').matches
557
+ if (coarse) addEventListener('deviceorientation', orient)
558
+ header?.addEventListener('pointermove', move)
559
+ header?.addEventListener('pointerleave', leave)
560
+ canvas.addEventListener('webglcontextlost', lost)
561
+ canvas.addEventListener('webglcontextrestored', restored)
562
+ activity()
563
+ const prepareFont = async () => {
564
+ try {
565
+ // Canvas lacks font-feature-settings; retain the site's Geist stylistic sets in a private face.
566
+ fontFace = new FontFace('Home Hero Geist', 'url("/fonts/GeistVariable.woff2")', { weight: '100 900', featureSettings: getComputedStyle(title).fontFeatureSettings })
567
+ await fontFace.load()
568
+ if (disposed) return
569
+ document.fonts.add(fontFace)
570
+ const style = getComputedStyle(title)
571
+ await document.fonts.load(`${style.fontWeight} ${style.fontSize} ${style.fontFamily.replace(/\bGeist\b/, 'Home Hero Geist')}`, title.textContent ?? '')
572
+ await document.fonts.ready
573
+ if (disposed) return
574
+ fontsReady = true
575
+ invalidate()
576
+ } catch {
577
+ if (!disposed) fallback()
578
+ }
579
+ }
580
+ void prepareFont()
581
+
582
+ return () => {
583
+ disposed = true
584
+ cancelAnimationFrame(frame)
585
+ clearReady()
586
+ unlight()
587
+ resize.disconnect()
588
+ theme.disconnect()
589
+ text.disconnect()
590
+ intersection.disconnect()
591
+ document.removeEventListener('visibilitychange', activity)
592
+ document.fonts.removeEventListener('loadingdone', invalidate)
593
+ window.removeEventListener('resize', invalidate)
594
+ motion.removeEventListener('change', activity)
595
+ contrast.removeEventListener('change', activity)
596
+ print.removeEventListener('change', activity)
597
+ scheme.removeEventListener('change', invalidate)
598
+ opaque.removeEventListener('change', invalidate)
599
+ host.removeEventListener('pointermove', move)
600
+ host.removeEventListener('pointerleave', leave)
601
+ host.removeEventListener('pointerdown', tap)
602
+ host.removeEventListener('pointerdown', press)
603
+ host.removeEventListener('keydown', press)
604
+ host.removeEventListener('focusin', focus)
605
+ host.removeEventListener('focusout', blur)
606
+ if (coarse) removeEventListener('deviceorientation', orient)
607
+ header?.removeEventListener('pointermove', move)
608
+ header?.removeEventListener('pointerleave', leave)
609
+ canvas.removeEventListener('webglcontextlost', lost)
610
+ canvas.removeEventListener('webglcontextrestored', restored)
611
+ if (fontFace) document.fonts.delete(fontFace)
612
+ release()
613
+ }
614
+ })
615
+ </script>
616
+
617
+ <canvas aria-hidden="true" class={['home-hero-canvas', className]} bind:this={canvasRef}></canvas>
@@ -0,0 +1,17 @@
1
+ ---
2
+ import Link from '@master/internal-site/components/Link.svelte'
3
+
4
+ const actionClassNames = {
5
+ primary: 'home-action home-action-primary',
6
+ secondary: 'home-action home-action-secondary'
7
+ }
8
+
9
+ interface Props {
10
+ href: string
11
+ variant: keyof typeof actionClassNames
12
+ }
13
+
14
+ const { href, variant } = Astro.props
15
+ ---
16
+
17
+ <Link class={actionClassNames[variant]} {href}><slot /></Link>
@@ -0,0 +1,9 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ type Props = HTMLAttributes<'div'>
5
+
6
+ const { class: className, ...props } = Astro.props
7
+ ---
8
+
9
+ <div class:list={['home-bento-frame', className]} {...props}><slot /></div>
@@ -0,0 +1,9 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types'
3
+
4
+ type Props = HTMLAttributes<'div'>
5
+
6
+ const { class: className, ...props } = Astro.props
7
+ ---
8
+
9
+ <div class:list={['home-bento-grid', className]} {...props}><slot /></div>
@@ -0,0 +1,15 @@
1
+ ---
2
+ import HomeIllustration from '@master/internal-site/home/HomeIllustration.astro'
3
+ import type { HomeCompactIconId } from '@master/internal-site/home/home-illustration.ts'
4
+
5
+ export type { HomeCompactIconId } from '@master/internal-site/home/home-illustration.ts'
6
+
7
+ interface Props {
8
+ icon: HomeCompactIconId
9
+ }
10
+
11
+ /** The same themed glass artwork in list-sized slots; rendered on the server. */
12
+ const { icon } = Astro.props
13
+ ---
14
+
15
+ <HomeIllustration class="home-compact-icon" {icon} size={48} />