hexo-theme-stellar 1.44.0 → 2.0.0-rc.2

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 (377) hide show
  1. package/CHANGELOG.md +63 -5
  2. package/CONTRIBUTING.md +29 -120
  3. package/README.md +66 -73
  4. package/README_EN.md +66 -73
  5. package/_config.yml +890 -743
  6. package/_data/icons.yml +43 -171
  7. package/_data/widgets.yml +1 -1
  8. package/assets/icon-v2-x512.webp +0 -0
  9. package/languages/en.yml +59 -2
  10. package/languages/zh-CN.yml +59 -2
  11. package/languages/zh-TW.yml +59 -2
  12. package/layout/404.ejs +7 -4
  13. package/layout/_partial/comments/artalk/layout.ejs +3 -2
  14. package/layout/_partial/comments/beaudar/layout.ejs +2 -2
  15. package/layout/_partial/comments/giscus/layout.ejs +2 -5
  16. package/layout/_partial/comments/layout.ejs +11 -40
  17. package/layout/_partial/comments/twikoo/layout.ejs +3 -2
  18. package/layout/_partial/comments/utterances/layout.ejs +2 -2
  19. package/layout/_partial/comments/waline/layout.ejs +3 -2
  20. package/layout/_partial/components/collection-item.ejs +30 -13
  21. package/layout/_partial/components/collection.ejs +2 -2
  22. package/layout/_partial/cover/index.ejs +5 -2
  23. package/layout/_partial/cover/wiki_cover.ejs +39 -28
  24. package/layout/_partial/dropdown.ejs +26 -14
  25. package/layout/_partial/head.ejs +96 -69
  26. package/layout/_partial/main/article/contributors.ejs +12 -9
  27. package/layout/_partial/main/article/post_footer.ejs +47 -0
  28. package/layout/_partial/main/article/post_read_next.ejs +22 -0
  29. package/layout/_partial/main/article/post_related.ejs +14 -0
  30. package/layout/_partial/main/article/post_tags.ejs +12 -0
  31. package/layout/_partial/main/article/share.ejs +55 -0
  32. package/layout/_partial/main/footer.ejs +11 -10
  33. package/layout/_partial/main/{navbar/nav_tabs_blog.ejs → listing_nav/blog.ejs} +21 -18
  34. package/layout/_partial/main/listing_nav/wiki.ejs +56 -0
  35. package/layout/_partial/main/navbar/article_banner.ejs +39 -35
  36. package/layout/_partial/main/navbar/breadcrumb/blog.ejs +15 -28
  37. package/layout/_partial/main/navbar/breadcrumb/note.ejs +12 -5
  38. package/layout/_partial/main/navbar/breadcrumb/wiki.ejs +15 -11
  39. package/layout/_partial/main/navbar/dateinfo.ejs +28 -12
  40. package/layout/_partial/main/navbar/ghinfo.ejs +5 -3
  41. package/layout/_partial/main/notebook/note_card.ejs +12 -17
  42. package/layout/_partial/main/notebook/note_tags.ejs +3 -4
  43. package/layout/_partial/main/notebook/notebook_card.ejs +11 -4
  44. package/layout/_partial/main/pin_slider.ejs +48 -43
  45. package/layout/_partial/main/post_list/archive_item.ejs +8 -4
  46. package/layout/_partial/main/post_list/latest_post_card.ejs +10 -4
  47. package/layout/_partial/main/post_list/post_card.ejs +39 -90
  48. package/layout/_partial/main/post_list/topic_card.ejs +7 -5
  49. package/layout/_partial/main/post_list/wiki_card.ejs +16 -13
  50. package/layout/_partial/menubtn.ejs +3 -3
  51. package/layout/_partial/primitives/item.ejs +8 -0
  52. package/layout/_partial/primitives/navigation.ejs +17 -0
  53. package/layout/_partial/primitives/region.ejs +16 -0
  54. package/layout/_partial/primitives/section.ejs +8 -0
  55. package/layout/_partial/primitives/shell.ejs +35 -0
  56. package/layout/_partial/regions/widgets.ejs +84 -0
  57. package/layout/_partial/scripts/defines.ejs +46 -76
  58. package/layout/_partial/scripts/runtime.ejs +55 -0
  59. package/layout/_partial/scripts.ejs +18 -42
  60. package/layout/_partial/search/dialog.ejs +33 -0
  61. package/layout/_partial/search/shortcut.ejs +1 -0
  62. package/layout/_partial/sidebar/brand.ejs +127 -0
  63. package/layout/_partial/sidebar/menu.ejs +59 -14
  64. package/layout/_partial/sidebar/search.ejs +58 -41
  65. package/layout/_partial/widgets/actions.ejs +25 -0
  66. package/layout/_partial/widgets/author.ejs +9 -5
  67. package/layout/_partial/widgets/components/linklist.ejs +1 -2
  68. package/layout/_partial/widgets/ghissues.ejs +7 -10
  69. package/layout/_partial/widgets/ghrepo.ejs +23 -16
  70. package/layout/_partial/widgets/ghuser.ejs +3 -3
  71. package/layout/_partial/widgets/recent.ejs +25 -21
  72. package/layout/_partial/widgets/related.ejs +25 -34
  73. package/layout/_partial/widgets/settings.ejs +17 -0
  74. package/layout/_partial/widgets/tagtree.ejs +18 -10
  75. package/layout/_partial/widgets/toc.ejs +17 -9
  76. package/layout/_partial/widgets/tree.ejs +12 -13
  77. package/layout/archive.ejs +20 -13
  78. package/layout/categories.ejs +4 -3
  79. package/layout/collection-preview.ejs +8 -9
  80. package/layout/index.ejs +32 -43
  81. package/layout/index_topic.ejs +6 -13
  82. package/layout/index_wiki.ejs +17 -34
  83. package/layout/layout.ejs +195 -65
  84. package/layout/notebooks.ejs +3 -3
  85. package/layout/notes.ejs +4 -4
  86. package/layout/page.ejs +95 -50
  87. package/layout/settings.ejs +109 -0
  88. package/layout/tags.ejs +4 -3
  89. package/{THIRD-PARTY-NOTICES.md → legal/THIRD-PARTY-NOTICES.md} +8 -4
  90. package/package.json +28 -6
  91. package/scripts/commands/stellar.js +55 -0
  92. package/scripts/events/index.js +15 -9
  93. package/scripts/events/lib/authors.js +9 -7
  94. package/scripts/events/lib/config-hot-reload.js +65 -0
  95. package/scripts/events/lib/config-schema.js +20 -0
  96. package/scripts/events/lib/config.js +22 -63
  97. package/scripts/events/lib/content-config.js +5 -0
  98. package/scripts/events/lib/doc_tree.js +99 -9
  99. package/scripts/events/lib/links.js +6 -3
  100. package/scripts/events/lib/notebooks.js +200 -8
  101. package/scripts/events/lib/utils.js +4 -4
  102. package/scripts/events/lib/version-check.js +57 -3
  103. package/scripts/filters/index.js +2 -27
  104. package/scripts/filters/lib/img_lazyload.js +4 -126
  105. package/scripts/filters/lib/img_onerror.js +14 -17
  106. package/scripts/filters/lib/page-view-model.js +152 -0
  107. package/scripts/generators/404.js +13 -8
  108. package/scripts/generators/author.js +16 -11
  109. package/scripts/generators/notebooks.js +68 -39
  110. package/scripts/generators/search.js +62 -67
  111. package/scripts/generators/settings.js +43 -0
  112. package/scripts/generators/stellar-icons.js +13 -5
  113. package/scripts/generators/topic.js +24 -13
  114. package/scripts/generators/wiki.js +49 -21
  115. package/scripts/helpers/ai_label.js +6 -12
  116. package/scripts/helpers/brand.js +17 -0
  117. package/scripts/helpers/browser_runtime_manifest.js +12 -0
  118. package/scripts/helpers/caption.js +8 -0
  119. package/scripts/helpers/category_color.js +13 -13
  120. package/scripts/helpers/collection.js +18 -0
  121. package/scripts/helpers/comments_model.js +14 -0
  122. package/scripts/helpers/extension_assets.js +8 -0
  123. package/scripts/helpers/json_ld.js +16 -7
  124. package/scripts/helpers/mdrender.js +3 -9
  125. package/scripts/helpers/menu.js +9 -0
  126. package/scripts/helpers/post_view_model.js +23 -0
  127. package/scripts/helpers/regions.js +37 -0
  128. package/scripts/helpers/scrollreveal.js +7 -7
  129. package/scripts/helpers/search_domain.js +34 -0
  130. package/scripts/helpers/service_provider.js +9 -0
  131. package/scripts/helpers/settings.js +16 -0
  132. package/scripts/helpers/share_action.js +8 -0
  133. package/scripts/helpers/stellar_config.js +12 -0
  134. package/scripts/helpers/stellar_data.js +8 -0
  135. package/scripts/helpers/stellar_info.js +21 -16
  136. package/scripts/helpers/stellar_inject.js +9 -0
  137. package/scripts/helpers/ui_classes.js +12 -0
  138. package/scripts/lib/ai_label.js +14 -11
  139. package/scripts/lib/brand.js +41 -0
  140. package/scripts/lib/browser-runtime.js +115 -0
  141. package/scripts/lib/caption.js +21 -0
  142. package/scripts/lib/collection-pipeline/adapters/notebook.js +62 -0
  143. package/scripts/lib/collection-pipeline/adapters/post.js +20 -0
  144. package/scripts/lib/collection-pipeline/adapters/topic.js +82 -0
  145. package/scripts/lib/collection-pipeline/adapters/wiki.js +20 -0
  146. package/scripts/lib/collection-pipeline/index.js +169 -0
  147. package/scripts/lib/collection-pipeline/registry.js +27 -0
  148. package/scripts/lib/collection-pipeline/shared.js +164 -0
  149. package/scripts/lib/comments.js +60 -0
  150. package/scripts/lib/config-inject.js +20 -0
  151. package/scripts/lib/config-schema.js +1095 -0
  152. package/scripts/lib/content-config.js +157 -0
  153. package/scripts/lib/content-defaults.js +56 -0
  154. package/scripts/lib/content-membership.js +233 -0
  155. package/scripts/lib/contribution-contract.js +165 -0
  156. package/scripts/lib/contribution-registry.js +429 -0
  157. package/scripts/lib/doc_tree.js +46 -44
  158. package/scripts/lib/doctor.js +296 -0
  159. package/scripts/lib/front-matter.js +29 -0
  160. package/scripts/lib/hero-effect-registry.js +262 -0
  161. package/scripts/lib/html-images.js +128 -0
  162. package/scripts/lib/internal-constants.js +152 -0
  163. package/scripts/lib/layout-config.js +62 -0
  164. package/scripts/lib/mdrender_html.js +36 -23
  165. package/scripts/lib/menu.js +36 -0
  166. package/scripts/lib/model-schema.js +90 -0
  167. package/scripts/lib/models/index.js +1542 -0
  168. package/scripts/lib/new-note.js +172 -0
  169. package/scripts/lib/page-view-model-registry.js +103 -0
  170. package/scripts/lib/regions.js +132 -0
  171. package/scripts/lib/runtime-data.js +23 -0
  172. package/scripts/lib/safe-path.js +44 -0
  173. package/scripts/lib/search-domain.js +59 -0
  174. package/scripts/lib/seo.js +10 -10
  175. package/scripts/lib/service-provider.js +12 -0
  176. package/scripts/lib/settings.js +16 -0
  177. package/scripts/lib/share-services.js +96 -0
  178. package/scripts/lib/source-config.js +27 -0
  179. package/scripts/lib/theme-metadata.js +22 -0
  180. package/scripts/lib/ui-capabilities.js +32 -0
  181. package/scripts/lib/widget-registry.js +150 -0
  182. package/scripts/lib/wiki_readme.js +15 -11
  183. package/scripts/schema/config-rules.js +290 -0
  184. package/scripts/schema/config-schema.js +163 -0
  185. package/scripts/schema/content-config-rules.js +264 -0
  186. package/scripts/schema/content-config-schema.js +321 -0
  187. package/scripts/schema/model-schema.js +971 -0
  188. package/scripts/schema/schema-utils.js +48 -0
  189. package/scripts/tags/index.js +2 -3
  190. package/scripts/tags/lib/albums.js +6 -6
  191. package/scripts/tags/lib/banner.js +10 -4
  192. package/scripts/tags/lib/box.js +1 -1
  193. package/scripts/tags/lib/button.js +1 -1
  194. package/scripts/tags/lib/chat.js +9 -31
  195. package/scripts/tags/lib/checkbox.js +6 -1
  196. package/scripts/tags/lib/copy.js +4 -1
  197. package/scripts/tags/lib/dropdown.js +6 -4
  198. package/scripts/tags/lib/emoji.js +5 -10
  199. package/scripts/tags/lib/friends.js +4 -4
  200. package/scripts/tags/lib/gallery.js +7 -7
  201. package/scripts/tags/lib/ghcard.js +5 -3
  202. package/scripts/tags/lib/gist.js +16 -0
  203. package/scripts/tags/lib/grid.js +4 -2
  204. package/scripts/tags/lib/hashtag.js +1 -1
  205. package/scripts/tags/lib/icon.js +1 -1
  206. package/scripts/tags/lib/image.js +1 -1
  207. package/scripts/tags/lib/link.js +6 -3
  208. package/scripts/tags/lib/mark.js +8 -3
  209. package/scripts/tags/lib/md.js +1 -1
  210. package/scripts/tags/lib/note.js +1 -1
  211. package/scripts/tags/lib/okr.js +18 -1
  212. package/scripts/tags/lib/posters.js +6 -6
  213. package/scripts/tags/lib/quot.js +15 -5
  214. package/scripts/tags/lib/rating.js +7 -4
  215. package/scripts/tags/lib/sites.js +8 -6
  216. package/scripts/tags/lib/tip.js +6 -6
  217. package/scripts/tags/lib/toc.js +2 -2
  218. package/scripts/tags/lib/vote.js +8 -5
  219. package/source/css/_appearances/_mixins.styl +258 -0
  220. package/source/css/_appearances/card.styl +30 -0
  221. package/source/css/_appearances/flat.styl +44 -0
  222. package/source/css/_appearances/glass.styl +138 -0
  223. package/source/css/_appearances/minimal.styl +325 -0
  224. package/source/css/_common/base.styl +5 -9
  225. package/source/css/_common/blockquote.styl +0 -1
  226. package/source/css/_common/button.styl +1 -1
  227. package/source/css/_common/device.styl +24 -42
  228. package/source/css/_common/dropdown.styl +20 -14
  229. package/source/css/_common/highlight.styl +5 -12
  230. package/source/css/_common/icon.styl +38 -0
  231. package/source/css/_common/input.styl +33 -0
  232. package/source/css/_common/loading.styl +2 -2
  233. package/source/css/_common/svg.styl +0 -8
  234. package/source/css/_components/collection.styl +21 -64
  235. package/source/css/_components/layout.styl +524 -84
  236. package/source/css/_components/list.styl +36 -22
  237. package/source/css/_components/main.styl +16 -19
  238. package/source/css/_components/md.styl +8 -13
  239. package/source/css/_components/pages/article-indent.styl +1 -1
  240. package/source/css/_components/pages/article-story.styl +7 -6
  241. package/source/css/_components/pages/article-tech.styl +5 -5
  242. package/source/css/_components/pages/collection-preview.styl +1 -5
  243. package/source/css/_components/pages/settings.styl +184 -0
  244. package/source/css/_components/partial/article-banner.styl +2 -2
  245. package/source/css/_components/partial/article-footer.styl +0 -32
  246. package/source/css/_components/partial/article-share.styl +48 -0
  247. package/source/css/_components/partial/article-tags.styl +1 -1
  248. package/source/css/_components/partial/cover.styl +13 -13
  249. package/source/css/_components/partial/listing-nav.styl +68 -0
  250. package/source/css/_components/partial/paginator.styl +1 -1
  251. package/source/css/_components/pin-slider.styl +3 -3
  252. package/source/css/_components/sidebar/brand.styl +135 -0
  253. package/source/css/_components/sidebar/footer.styl +14 -31
  254. package/source/css/_components/sidebar/nav-area.styl +4 -0
  255. package/source/css/_components/sidebar/search.styl +176 -26
  256. package/source/css/_components/sidebar/sidebar.styl +76 -110
  257. package/source/css/_components/tag-plugins/banner.styl +16 -28
  258. package/source/css/_components/tag-plugins/checkbox.styl +7 -22
  259. package/source/css/_components/tag-plugins/copy.styl +3 -5
  260. package/source/css/_components/tag-plugins/gallery.styl +2 -2
  261. package/source/css/_components/tag-plugins/grid.styl +3 -0
  262. package/source/css/_components/tag-plugins/image.styl +2 -1
  263. package/source/css/_components/tag-plugins/link.styl +0 -1
  264. package/source/css/_components/tag-plugins/mark.styl +19 -4
  265. package/source/css/_components/tag-plugins/mdrender.styl +2 -2
  266. package/source/css/_components/tag-plugins/navbar.styl +23 -17
  267. package/source/css/_components/tag-plugins/note.styl +2 -2
  268. package/source/css/_components/tag-plugins/okr.styl +1 -2
  269. package/source/css/_components/tag-plugins/quot.styl +5 -0
  270. package/source/css/_components/tag-plugins/rating.styl +3 -2
  271. package/source/css/_components/tag-plugins/timeline.styl +1 -1
  272. package/source/css/_components/tag-plugins/tip.styl +1 -1
  273. package/source/css/_components/tag-plugins/vote.styl +3 -2
  274. package/source/css/_components/widgets/ghrepo.styl +2 -1
  275. package/source/css/_components/widgets/ghuser.styl +4 -6
  276. package/source/css/_components/widgets/settings.styl +49 -0
  277. package/source/css/_components/widgets/timeline.styl +2 -2
  278. package/source/css/_components/widgets/toc.styl +12 -33
  279. package/source/css/_components/widgets/widgets.styl +14 -19
  280. package/source/css/_components/wiki-card.styl +2 -2
  281. package/source/css/_custom.styl +26 -32
  282. package/source/css/_defines/func.styl +47 -37
  283. package/source/css/_defines/theme_base.styl +8 -10
  284. package/source/css/_plugins/card-hover.styl +1 -1
  285. package/source/css/_plugins/copycode.styl +16 -19
  286. package/source/css/_plugins/index.styl +3 -8
  287. package/source/css/_plugins/lazyload.styl +1 -1
  288. package/source/css/main.styl +12 -0
  289. package/source/js/main.js +302 -59
  290. package/source/js/plugins/adaptive-text.js +33 -16
  291. package/source/js/plugins/card-hover.js +2 -24
  292. package/source/js/plugins/copycode.js +10 -16
  293. package/source/js/plugins/voice.js +51 -48
  294. package/source/js/profile.js +316 -0
  295. package/source/js/runtime/asset-loader.js +61 -0
  296. package/source/js/runtime/extension-registry.js +149 -0
  297. package/source/js/runtime/extensions/card-hover.js +5 -0
  298. package/source/js/runtime/extensions/color-scheme-switch.js +101 -0
  299. package/source/js/runtime/extensions/comments.js +200 -0
  300. package/source/js/runtime/extensions/deferred-icons.js +53 -0
  301. package/source/js/{plugins → runtime/extensions}/dropdown.js +69 -30
  302. package/source/js/runtime/extensions/feature.js +200 -0
  303. package/source/js/runtime/extensions/hero-effect.js +179 -0
  304. package/source/js/runtime/extensions/reveal.js +80 -0
  305. package/source/js/runtime/extensions/search.js +23 -0
  306. package/source/js/{services.js → runtime/extensions/services.js} +67 -54
  307. package/source/js/runtime/extensions/settings.js +235 -0
  308. package/source/js/runtime/hero-effects/ferrofluid.js +385 -0
  309. package/source/js/{plugins → runtime/hero-effects}/galaxy.js +53 -177
  310. package/source/js/runtime/hero-effects/light-rays.js +293 -0
  311. package/source/js/runtime/index.js +75 -0
  312. package/source/js/runtime/legacy-request-adapter.js +47 -0
  313. package/source/js/runtime/request-cache.js +219 -0
  314. package/source/js/search/algolia-search.js +76 -51
  315. package/source/js/search/highlight.js +1 -1
  316. package/source/js/search/local-search.js +96 -57
  317. package/source/js/search/shortcut.js +31 -20
  318. package/source/js/services/friends_and_posts.js +6 -1
  319. package/source/js/services/rating.js +14 -6
  320. package/source/js/services/siteinfo.js +3 -7
  321. package/source/js/services/timeline.js +1 -1
  322. package/source/js/services/vote.js +7 -5
  323. package/source/js/services/weibo.js +1 -1
  324. package/source/js/utils.js +19 -444
  325. package/.claude/skills/stellar-theme-dev/SKILL.md +0 -51
  326. package/_data/chat_users.yml +0 -0
  327. package/layout/_partial/comments/artalk/script.ejs +0 -76
  328. package/layout/_partial/comments/beaudar/script.ejs +0 -33
  329. package/layout/_partial/comments/giscus/script.ejs +0 -31
  330. package/layout/_partial/comments/script.ejs +0 -3
  331. package/layout/_partial/comments/twikoo/script.ejs +0 -25
  332. package/layout/_partial/comments/utterances/script.ejs +0 -33
  333. package/layout/_partial/comments/waline/script.ejs +0 -43
  334. package/layout/_partial/main/article/article_footer.ejs +0 -164
  335. package/layout/_partial/main/article/article_tags.ejs +0 -16
  336. package/layout/_partial/main/article/read_next.ejs +0 -63
  337. package/layout/_partial/main/article/related_posts.ejs +0 -16
  338. package/layout/_partial/main/navbar/nav_tabs_wiki.ejs +0 -52
  339. package/layout/_partial/scripts/bootstrap.ejs +0 -37
  340. package/layout/_partial/scripts/lazyload.ejs +0 -89
  341. package/layout/_partial/sidebar/grad-def.ejs +0 -26
  342. package/layout/_partial/sidebar/index_leftbar.ejs +0 -191
  343. package/layout/_partial/sidebar/index_rightbar.ejs +0 -94
  344. package/layout/_partial/sidebar/logo.ejs +0 -99
  345. package/layout/_plugins/adaptive_text.ejs +0 -11
  346. package/layout/_plugins/card_hover.ejs +0 -32
  347. package/layout/_plugins/copycode.ejs +0 -17
  348. package/layout/_plugins/fancybox.ejs +0 -53
  349. package/layout/_plugins/heti.ejs +0 -21
  350. package/layout/_plugins/index.ejs +0 -50
  351. package/layout/_plugins/mathjax.ejs +0 -49
  352. package/layout/_plugins/mermaid.ejs +0 -33
  353. package/layout/_plugins/preload.ejs +0 -9
  354. package/layout/_plugins/scrollreveal.ejs +0 -102
  355. package/layout/_plugins/search/algolia_search.ejs +0 -12
  356. package/layout/_plugins/search/local_search.ejs +0 -9
  357. package/layout/_plugins/swiper.ejs +0 -27
  358. package/layout/_plugins/tianli_gpt.ejs +0 -14
  359. package/scripts/commands/new-note.js +0 -49
  360. package/scripts/events/lib/merge_posts.js +0 -48
  361. package/scripts/events/lib/topic_tree.js +0 -48
  362. package/scripts/helpers/related_posts.js +0 -51
  363. package/scripts/helpers/subtitle.js +0 -8
  364. package/scripts/lib/notebooks.js +0 -181
  365. package/scripts/lib/subtitle.js +0 -28
  366. package/scripts/tags/lib/about.js +0 -48
  367. package/source/css/_components/page-transition.styl +0 -22
  368. package/source/css/_components/partial/navbar.styl +0 -51
  369. package/source/css/_components/sidebar/logo.styl +0 -111
  370. package/source/css/_components/tag-plugins/about.styl +0 -56
  371. package/source/css/_components/widgets/tree.styl +0 -0
  372. package/source/css/_plugins/scrollreveal.styl +0 -6
  373. package/source/css/_plugins/tianli_gpt.styl +0 -213
  374. package/source/css/plugins/mermaid.styl +0 -137
  375. package/source/js/icons.js +0 -60
  376. package/source/js/services/fcircle.js +0 -35
  377. package/source/js/theme.js +0 -61
@@ -1,13 +1,12 @@
1
1
  /*
2
- * Wiki Galaxy WebGL background.
2
+ * Wiki Galaxy WebGL renderer.
3
3
  * Shader adapted from React Bits Galaxy: https://github.com/DavidHDev/react-bits
4
4
  * React Bits is MIT licensed; see THIRD-PARTY-NOTICES.md.
5
5
  */
6
6
 
7
- (function () {
8
- 'use strict';
7
+ 'use strict';
9
8
 
10
- const vertexShader = `
9
+ const vertexShader = `
11
10
  attribute vec2 position;
12
11
 
13
12
  varying vec2 vUv;
@@ -168,23 +167,6 @@ void main() {
168
167
  }
169
168
  `;
170
169
 
171
- const defaultParams = {
172
- focal: [0.5, 0.5],
173
- rotation: [1.0, 0.0],
174
- starSpeed: 2.0,
175
- density: 2.0,
176
- hueShift: 140.0,
177
- speed: 0.5,
178
- glowIntensity: 0.2,
179
- saturation: 0.1,
180
- mouseRepulsion: true,
181
- twinkleIntensity: 0.1,
182
- rotationSpeed: 0.1,
183
- repulsionStrength: 0.1,
184
- autoCenterRepulsion: 0.0,
185
- transparent: true
186
- };
187
-
188
170
  function isFiniteNumber(value) {
189
171
  return typeof value === 'number' && Number.isFinite(value);
190
172
  }
@@ -218,36 +200,28 @@ void main() {
218
200
  return ((value % 360) + 360) % 360;
219
201
  }
220
202
 
221
- function normalizeParams(value) {
203
+ function normalizeParams(value, defaults) {
222
204
  const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
223
205
  return {
224
- focal: pairOrDefault(source.focal, defaultParams.focal, true),
225
- rotation: pairOrDefault(source.rotation, defaultParams.rotation, false),
226
- starSpeed: nonNegativeOrDefault(source.starSpeed, defaultParams.starSpeed),
227
- density: nonNegativeOrDefault(source.density, defaultParams.density),
228
- hueShift: normalizeHue(source.hueShift, defaultParams.hueShift),
229
- speed: nonNegativeOrDefault(source.speed, defaultParams.speed),
230
- glowIntensity: nonNegativeOrDefault(source.glowIntensity, defaultParams.glowIntensity),
231
- saturation: nonNegativeOrDefault(source.saturation, defaultParams.saturation),
232
- mouseRepulsion: booleanOrDefault(source.mouseRepulsion, defaultParams.mouseRepulsion),
233
- twinkleIntensity: nonNegativeOrDefault(source.twinkleIntensity, defaultParams.twinkleIntensity),
234
- rotationSpeed: finiteOrDefault(source.rotationSpeed, defaultParams.rotationSpeed),
235
- repulsionStrength: nonNegativeOrDefault(source.repulsionStrength, defaultParams.repulsionStrength),
236
- autoCenterRepulsion: nonNegativeOrDefault(source.autoCenterRepulsion, defaultParams.autoCenterRepulsion),
237
- transparent: booleanOrDefault(source.transparent, defaultParams.transparent)
206
+ focal: pairOrDefault(source.focal, defaults.focal, true),
207
+ rotation: pairOrDefault(source.rotation, defaults.rotation, false),
208
+ starSpeed: nonNegativeOrDefault(source.starSpeed, defaults.starSpeed),
209
+ density: nonNegativeOrDefault(source.density, defaults.density),
210
+ hueShift: normalizeHue(source.hueShift, defaults.hueShift),
211
+ disableAnimation: booleanOrDefault(source.disableAnimation, defaults.disableAnimation),
212
+ speed: nonNegativeOrDefault(source.speed, defaults.speed),
213
+ mouseInteraction: booleanOrDefault(source.mouseInteraction, defaults.mouseInteraction),
214
+ glowIntensity: nonNegativeOrDefault(source.glowIntensity, defaults.glowIntensity),
215
+ saturation: nonNegativeOrDefault(source.saturation, defaults.saturation),
216
+ mouseRepulsion: booleanOrDefault(source.mouseRepulsion, defaults.mouseRepulsion),
217
+ twinkleIntensity: nonNegativeOrDefault(source.twinkleIntensity, defaults.twinkleIntensity),
218
+ rotationSpeed: finiteOrDefault(source.rotationSpeed, defaults.rotationSpeed),
219
+ repulsionStrength: nonNegativeOrDefault(source.repulsionStrength, defaults.repulsionStrength),
220
+ autoCenterRepulsion: nonNegativeOrDefault(source.autoCenterRepulsion, defaults.autoCenterRepulsion),
221
+ transparent: booleanOrDefault(source.transparent, defaults.transparent)
238
222
  };
239
223
  }
240
224
 
241
- function readParams(canvas) {
242
- const raw = canvas.getAttribute('data-galaxy-params');
243
- if (!raw) return normalizeParams({});
244
- try {
245
- return normalizeParams(JSON.parse(raw));
246
- } catch (e) {
247
- return normalizeParams({});
248
- }
249
- }
250
-
251
225
  function createShader(gl, type, source) {
252
226
  const shader = gl.createShader(type);
253
227
  gl.shaderSource(shader, source);
@@ -292,13 +266,9 @@ void main() {
292
266
  return result;
293
267
  }
294
268
 
295
- function mount(canvas) {
296
- if (!canvas || canvas.dataset.galaxyMounted === 'true') return;
297
-
298
- const background = canvas.parentElement;
299
- const interactionTarget = canvas.closest('.wiki-hero') || background;
300
- if (!background || !interactionTarget) return;
301
- const params = readParams(canvas);
269
+ export function createRenderer(canvas, options, defaults) {
270
+ if (!canvas) return null;
271
+ const params = normalizeParams(options, defaults);
302
272
 
303
273
  let gl;
304
274
  try {
@@ -322,7 +292,6 @@ void main() {
322
292
  return;
323
293
  }
324
294
 
325
- canvas.dataset.galaxyMounted = 'true';
326
295
  const locations = uniformLocations(gl, program);
327
296
  const position = gl.getAttribLocation(program, 'position');
328
297
  const buffer = gl.createBuffer();
@@ -354,134 +323,41 @@ void main() {
354
323
  gl.uniform1f(locations.uAutoCenterRepulsion, params.autoCenterRepulsion);
355
324
  gl.uniform1i(locations.uTransparent, params.transparent ? 1 : 0);
356
325
 
357
- const targetMouse = { x: 0.5, y: 0.5 };
358
326
  const smoothMouse = { x: 0.5, y: 0.5 };
359
- let targetMouseActive = 0.0;
360
327
  let smoothMouseActive = 0.0;
361
- let animationFrame = null;
362
- let isInViewport = true;
363
- let isDestroyed = false;
364
-
365
- function resize() {
366
- const rect = background.getBoundingClientRect();
367
- const width = Math.max(1, Math.round(rect.width));
368
- const height = Math.max(1, Math.round(rect.height));
369
- if (canvas.width !== width || canvas.height !== height) {
328
+ return Object.freeze({
329
+ pointer: params.mouseInteraction,
330
+ resize(rect) {
331
+ const width = Math.max(1, Math.round(rect.width));
332
+ const height = Math.max(1, Math.round(rect.height));
333
+ if (canvas.width === width && canvas.height === height) return;
370
334
  canvas.width = width;
371
335
  canvas.height = height;
372
336
  gl.viewport(0, 0, width, height);
373
337
  gl.uniform3f(locations.uResolution, width, height, width / height);
338
+ },
339
+ render(time, pointer) {
340
+ const targetX = pointer?.x ?? 0.5;
341
+ const targetY = 1 - (pointer?.y ?? 0.5);
342
+ const targetActive = pointer?.active === true ? 1 : 0;
343
+ const seconds = params.disableAnimation ? 0 : time * 0.001;
344
+ const lerpFactor = 0.05;
345
+ smoothMouse.x += (targetX - smoothMouse.x) * lerpFactor;
346
+ smoothMouse.y += (targetY - smoothMouse.y) * lerpFactor;
347
+ smoothMouseActive += (targetActive - smoothMouseActive) * lerpFactor;
348
+
349
+ gl.uniform1f(locations.uTime, seconds);
350
+ gl.uniform1f(locations.uStarSpeed, seconds * params.starSpeed / 10.0);
351
+ gl.uniform2f(locations.uMouse, smoothMouse.x, smoothMouse.y);
352
+ gl.uniform1f(locations.uMouseActiveFactor, smoothMouseActive);
353
+ gl.clear(gl.COLOR_BUFFER_BIT);
354
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
355
+ },
356
+ destroy() {
357
+ gl.deleteBuffer(buffer);
358
+ gl.deleteProgram(program);
359
+ const loseContext = gl.getExtension('WEBGL_lose_context');
360
+ if (loseContext) loseContext.loseContext();
374
361
  }
375
- }
376
-
377
- function shouldRender() {
378
- return !isDestroyed && isInViewport && !document.hidden;
379
- }
380
-
381
- function render(time) {
382
- animationFrame = null;
383
- if (!shouldRender()) return;
384
-
385
- const seconds = time * 0.001;
386
- const lerpFactor = 0.05;
387
- smoothMouse.x += (targetMouse.x - smoothMouse.x) * lerpFactor;
388
- smoothMouse.y += (targetMouse.y - smoothMouse.y) * lerpFactor;
389
- smoothMouseActive += (targetMouseActive - smoothMouseActive) * lerpFactor;
390
-
391
- gl.uniform1f(locations.uTime, seconds);
392
- gl.uniform1f(locations.uStarSpeed, seconds * params.starSpeed / 10.0);
393
- gl.uniform2f(locations.uMouse, smoothMouse.x, smoothMouse.y);
394
- gl.uniform1f(locations.uMouseActiveFactor, smoothMouseActive);
395
- gl.clear(gl.COLOR_BUFFER_BIT);
396
- gl.drawArrays(gl.TRIANGLES, 0, 3);
397
- animationFrame = window.requestAnimationFrame(render);
398
- }
399
-
400
- function start() {
401
- if (shouldRender() && animationFrame === null) {
402
- animationFrame = window.requestAnimationFrame(render);
403
- }
404
- }
405
-
406
- function stop() {
407
- if (animationFrame !== null) {
408
- window.cancelAnimationFrame(animationFrame);
409
- animationFrame = null;
410
- }
411
- }
412
-
413
- function handleMouseMove(event) {
414
- const rect = background.getBoundingClientRect();
415
- if (rect.width <= 0 || rect.height <= 0) return;
416
- targetMouse.x = (event.clientX - rect.left) / rect.width;
417
- targetMouse.y = 1.0 - (event.clientY - rect.top) / rect.height;
418
- targetMouseActive = 1.0;
419
- }
420
-
421
- function handleMouseLeave() {
422
- targetMouseActive = 0.0;
423
- }
424
-
425
- function handleVisibilityChange() {
426
- if (document.hidden) {
427
- stop();
428
- } else {
429
- start();
430
- }
431
- }
432
-
433
- interactionTarget.addEventListener('mousemove', handleMouseMove);
434
- interactionTarget.addEventListener('mouseleave', handleMouseLeave);
435
- document.addEventListener('visibilitychange', handleVisibilityChange);
436
-
437
- let resizeObserver = null;
438
- if (window.ResizeObserver) {
439
- resizeObserver = new window.ResizeObserver(resize);
440
- resizeObserver.observe(background);
441
- } else {
442
- window.addEventListener('resize', resize);
443
- }
444
-
445
- let viewportObserver = null;
446
- if (window.IntersectionObserver) {
447
- viewportObserver = new window.IntersectionObserver(function (entries) {
448
- isInViewport = entries[0].isIntersecting;
449
- if (isInViewport) {
450
- start();
451
- } else {
452
- stop();
453
- }
454
- });
455
- viewportObserver.observe(background);
456
- }
457
-
458
- function destroy() {
459
- if (isDestroyed) return;
460
- isDestroyed = true;
461
- stop();
462
- interactionTarget.removeEventListener('mousemove', handleMouseMove);
463
- interactionTarget.removeEventListener('mouseleave', handleMouseLeave);
464
- document.removeEventListener('visibilitychange', handleVisibilityChange);
465
- window.removeEventListener('resize', resize);
466
- window.removeEventListener('pagehide', destroy);
467
- if (resizeObserver) resizeObserver.disconnect();
468
- if (viewportObserver) viewportObserver.disconnect();
469
- gl.deleteBuffer(buffer);
470
- gl.deleteProgram(program);
471
- const loseContext = gl.getExtension('WEBGL_lose_context');
472
- if (loseContext) loseContext.loseContext();
473
- delete canvas.dataset.galaxyMounted;
474
- }
475
-
476
- window.addEventListener('pagehide', destroy);
477
- resize();
478
- start();
362
+ });
479
363
  }
480
-
481
- window.stellar = window.stellar || {};
482
- window.stellar.galaxy = {
483
- mountAll: function (canvases) {
484
- Array.prototype.forEach.call(canvases || [], mount);
485
- }
486
- };
487
- })();
@@ -0,0 +1,293 @@
1
+ /*
2
+ * Wiki Hero Light Rays WebGL renderer.
3
+ * Independently implemented with the native WebGL API for Stellar.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const vertexShader = `
9
+ attribute vec2 position;
10
+
11
+ void main() {
12
+ gl_Position = vec4(position, 0.0, 1.0);
13
+ }
14
+ `;
15
+
16
+ const fragmentShader = `
17
+ precision highp float;
18
+
19
+ uniform float uTime;
20
+ uniform vec2 uResolution;
21
+ uniform vec2 uRayPosition;
22
+ uniform vec2 uRayDirection;
23
+ uniform vec3 uRayColor;
24
+ uniform float uRaySpeed;
25
+ uniform float uLightSpread;
26
+ uniform float uRayLength;
27
+ uniform float uPulsating;
28
+ uniform float uFadeDistance;
29
+ uniform float uSaturation;
30
+ uniform vec2 uMouse;
31
+ uniform float uMouseInfluence;
32
+ uniform float uNoiseAmount;
33
+ uniform float uDistortion;
34
+ uniform float uLightMode;
35
+
36
+ float hash21(vec2 point) {
37
+ vec3 p = fract(vec3(point.xyx) * 0.1031);
38
+ p += dot(p, p.yzx + 33.33);
39
+ return fract((p.x + p.y) * p.z);
40
+ }
41
+
42
+ float valueNoise(vec2 point) {
43
+ vec2 cell = floor(point);
44
+ vec2 local = fract(point);
45
+ local = local * local * (3.0 - 2.0 * local);
46
+ float a = hash21(cell);
47
+ float b = hash21(cell + vec2(1.0, 0.0));
48
+ float c = hash21(cell + vec2(0.0, 1.0));
49
+ float d = hash21(cell + vec2(1.0, 1.0));
50
+ return mix(mix(a, b, local.x), mix(c, d, local.x), local.y);
51
+ }
52
+
53
+ vec2 safeDirection(vec2 value, vec2 fallbackValue) {
54
+ float magnitude = length(value);
55
+ return magnitude > 0.0001 ? value / magnitude : fallbackValue;
56
+ }
57
+
58
+ void main() {
59
+ vec2 point = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
60
+ vec2 baseDirection = safeDirection(uRayDirection, vec2(0.0, 1.0));
61
+ vec2 mouseDirection = safeDirection(uMouse * uResolution - uRayPosition, baseDirection);
62
+ vec2 direction = safeDirection(mix(baseDirection, mouseDirection, uMouseInfluence), baseDirection);
63
+ vec2 perpendicular = vec2(-direction.y, direction.x);
64
+ vec2 offset = point - uRayPosition;
65
+ float distanceFromSource = length(offset);
66
+ float forward = dot(offset, direction);
67
+ float side = dot(offset, perpendicular);
68
+
69
+ float spread = max(abs(uLightSpread), 0.001);
70
+ float lengthScale = max(abs(uRayLength), 0.001);
71
+ float fadeScale = max(abs(uFadeDistance), 0.001);
72
+ float directionalExtent = max(abs(direction.x) * uResolution.x + abs(direction.y) * uResolution.y, 1.0);
73
+ float lengthProgress = distanceFromSource / max(directionalExtent * lengthScale / 3.0, 1.0);
74
+ float fadeProgress = distanceFromSource / max(directionalExtent * fadeScale, 1.0);
75
+ float angularAlignment = forward / max(distanceFromSource, 0.001);
76
+ float fan = pow(max(angularAlignment, 0.0), 1.25 / spread);
77
+ float reach = 1.0 - smoothstep(0.08, 1.0, lengthProgress);
78
+ float fade = 1.0 - smoothstep(0.12, 1.2, fadeProgress);
79
+
80
+ float animatedTime = uTime * uRaySpeed;
81
+ float wave = sin(distanceFromSource * 0.015 + animatedTime * 1.7);
82
+ side += wave * uDistortion * max(uResolution.y * 0.12, 1.0);
83
+
84
+ float beamWidth = max(distanceFromSource * (0.035 + spread * 0.12), 1.0);
85
+ float beamCoordinate = side / beamWidth;
86
+ float broadBeam = 0.3 + 0.7 * exp(-beamCoordinate * beamCoordinate * 0.32);
87
+ float rayBands = 0.55
88
+ + 0.14 * sin(beamCoordinate * 2.7 - animatedTime * 0.72)
89
+ + 0.09 * sin(beamCoordinate * 6.1 + animatedTime * 0.41);
90
+ rayBands = smoothstep(0.2, 0.9, rayBands);
91
+
92
+ vec2 noisePoint = point / max(uResolution.y, 1.0) * 7.0;
93
+ float grain = valueNoise(noisePoint + vec2(animatedTime * 0.08, -animatedTime * 0.05));
94
+ float noiseFactor = mix(1.0, grain, uNoiseAmount);
95
+ float pulse = mix(1.0, 0.82 + 0.18 * sin(animatedTime * 2.4), step(0.5, uPulsating));
96
+ float intensity = clamp(fan * reach * fade * broadBeam * (0.68 + 0.32 * rayBands) * noiseFactor * pulse * 0.62, 0.0, 0.65);
97
+
98
+ float gray = dot(uRayColor, vec3(0.299, 0.587, 0.114));
99
+ vec3 saturatedColor = mix(vec3(gray), uRayColor, uSaturation);
100
+ vec3 darkInk = mix(vec3(0.025), saturatedColor * 0.42, 0.7);
101
+ vec3 outputColor = mix(saturatedColor, darkInk, step(0.5, uLightMode));
102
+ gl_FragColor = vec4(outputColor, intensity);
103
+ }
104
+ `;
105
+
106
+ function finiteOrDefault(value, fallback) {
107
+ return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
108
+ }
109
+
110
+ function booleanOrDefault(value, fallback) {
111
+ return typeof value === 'boolean' ? value : fallback;
112
+ }
113
+
114
+ function colorOrDefault(value, fallback) {
115
+ return typeof value === 'string' && /^#?[a-f\d]{6}$/i.test(value) ? value : fallback;
116
+ }
117
+
118
+ function normalizeParams(value, defaults) {
119
+ const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
120
+ return {
121
+ raysOrigin: typeof source.raysOrigin === 'string' ? source.raysOrigin : defaults.raysOrigin,
122
+ raysColor: colorOrDefault(source.raysColor, defaults.raysColor),
123
+ raysSpeed: finiteOrDefault(source.raysSpeed, defaults.raysSpeed),
124
+ lightSpread: finiteOrDefault(source.lightSpread, defaults.lightSpread),
125
+ rayLength: finiteOrDefault(source.rayLength, defaults.rayLength),
126
+ pulsating: booleanOrDefault(source.pulsating, defaults.pulsating),
127
+ fadeDistance: finiteOrDefault(source.fadeDistance, defaults.fadeDistance),
128
+ saturation: finiteOrDefault(source.saturation, defaults.saturation),
129
+ followMouse: booleanOrDefault(source.followMouse, defaults.followMouse),
130
+ mouseInfluence: finiteOrDefault(source.mouseInfluence, defaults.mouseInfluence),
131
+ noiseAmount: finiteOrDefault(source.noiseAmount, defaults.noiseAmount),
132
+ distortion: finiteOrDefault(source.distortion, defaults.distortion),
133
+ lightMode: booleanOrDefault(source.lightMode, defaults.lightMode)
134
+ };
135
+ }
136
+
137
+ function hexToRgb(value) {
138
+ const normalized = value.replace(/^#/, '');
139
+ return [
140
+ parseInt(normalized.slice(0, 2), 16) / 255,
141
+ parseInt(normalized.slice(2, 4), 16) / 255,
142
+ parseInt(normalized.slice(4, 6), 16) / 255
143
+ ];
144
+ }
145
+
146
+ function placement(origin, width, height) {
147
+ const outside = 0.2;
148
+ if (origin === 'top-left') return { position: [0, -outside * height], direction: [0, 1] };
149
+ if (origin === 'top-right') return { position: [width, -outside * height], direction: [0, 1] };
150
+ if (origin === 'left') return { position: [-outside * width, 0.5 * height], direction: [1, 0] };
151
+ if (origin === 'right') return { position: [(1 + outside) * width, 0.5 * height], direction: [-1, 0] };
152
+ if (origin === 'bottom-left') return { position: [0, (1 + outside) * height], direction: [0, -1] };
153
+ if (origin === 'bottom-center') return { position: [0.5 * width, (1 + outside) * height], direction: [0, -1] };
154
+ if (origin === 'bottom-right') return { position: [width, (1 + outside) * height], direction: [0, -1] };
155
+ return { position: [0.5 * width, -outside * height], direction: [0, 1] };
156
+ }
157
+
158
+ function createShader(gl, type, source) {
159
+ const shader = gl.createShader(type);
160
+ gl.shaderSource(shader, source);
161
+ gl.compileShader(shader);
162
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
163
+ const message = gl.getShaderInfoLog(shader) || 'Unknown shader compilation error';
164
+ gl.deleteShader(shader);
165
+ throw new Error(message);
166
+ }
167
+ return shader;
168
+ }
169
+
170
+ function createProgram(gl) {
171
+ const vertex = createShader(gl, gl.VERTEX_SHADER, vertexShader);
172
+ let fragment;
173
+ try {
174
+ fragment = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader);
175
+ } catch (error) {
176
+ gl.deleteShader(vertex);
177
+ throw error;
178
+ }
179
+ const program = gl.createProgram();
180
+ gl.attachShader(program, vertex);
181
+ gl.attachShader(program, fragment);
182
+ gl.linkProgram(program);
183
+ gl.deleteShader(vertex);
184
+ gl.deleteShader(fragment);
185
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
186
+ const message = gl.getProgramInfoLog(program) || 'Unknown program link error';
187
+ gl.deleteProgram(program);
188
+ throw new Error(message);
189
+ }
190
+ return program;
191
+ }
192
+
193
+ function uniformLocations(gl, program) {
194
+ const names = [
195
+ 'uTime', 'uResolution', 'uRayPosition', 'uRayDirection', 'uRayColor',
196
+ 'uRaySpeed', 'uLightSpread', 'uRayLength', 'uPulsating', 'uFadeDistance',
197
+ 'uSaturation', 'uMouse', 'uMouseInfluence', 'uNoiseAmount', 'uDistortion',
198
+ 'uLightMode'
199
+ ];
200
+ const locations = {};
201
+ names.forEach(function (name) {
202
+ locations[name] = gl.getUniformLocation(program, name);
203
+ });
204
+ return locations;
205
+ }
206
+
207
+ export function createRenderer(canvas, options, defaults) {
208
+ if (!canvas) return null;
209
+ const params = normalizeParams(options, defaults);
210
+
211
+ let gl;
212
+ try {
213
+ gl = canvas.getContext('webgl', {
214
+ alpha: true,
215
+ antialias: false,
216
+ premultipliedAlpha: false,
217
+ powerPreference: 'high-performance'
218
+ });
219
+ } catch (e) {
220
+ return;
221
+ }
222
+ if (!gl) return;
223
+
224
+ let program;
225
+ try {
226
+ program = createProgram(gl);
227
+ } catch (e) {
228
+ const loseContext = gl.getExtension('WEBGL_lose_context');
229
+ if (loseContext) loseContext.loseContext();
230
+ return;
231
+ }
232
+
233
+ gl.useProgram(program);
234
+ const locations = uniformLocations(gl, program);
235
+ const buffer = gl.createBuffer();
236
+ const position = gl.getAttribLocation(program, 'position');
237
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
238
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
239
+ -1.0, -1.0,
240
+ 3.0, -1.0,
241
+ -1.0, 3.0
242
+ ]), gl.STATIC_DRAW);
243
+ gl.enableVertexAttribArray(position);
244
+ gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
245
+ gl.clearColor(0, 0, 0, 0);
246
+
247
+ const color = hexToRgb(params.raysColor);
248
+ gl.uniform3f(locations.uRayColor, color[0], color[1], color[2]);
249
+ gl.uniform1f(locations.uRaySpeed, params.raysSpeed);
250
+ gl.uniform1f(locations.uLightSpread, params.lightSpread);
251
+ gl.uniform1f(locations.uRayLength, params.rayLength);
252
+ gl.uniform1f(locations.uPulsating, params.pulsating ? 1 : 0);
253
+ gl.uniform1f(locations.uFadeDistance, params.fadeDistance);
254
+ gl.uniform1f(locations.uSaturation, params.saturation);
255
+ gl.uniform1f(locations.uMouseInfluence, params.followMouse ? params.mouseInfluence : 0);
256
+ gl.uniform1f(locations.uNoiseAmount, params.noiseAmount);
257
+ gl.uniform1f(locations.uDistortion, params.distortion);
258
+ gl.uniform1f(locations.uLightMode, params.lightMode ? 1 : 0);
259
+
260
+ const smoothMouse = { x: 0.5, y: 0.5 };
261
+ return Object.freeze({
262
+ pointer: params.followMouse,
263
+ resize(rect, devicePixelRatio) {
264
+ const dpr = Math.min(devicePixelRatio, 2);
265
+ const width = Math.max(1, Math.round(rect.width * dpr));
266
+ const height = Math.max(1, Math.round(rect.height * dpr));
267
+ if (canvas.width === width && canvas.height === height) return;
268
+ canvas.width = width;
269
+ canvas.height = height;
270
+ gl.viewport(0, 0, width, height);
271
+ gl.uniform2f(locations.uResolution, width, height);
272
+ const ray = placement(params.raysOrigin, width, height);
273
+ gl.uniform2f(locations.uRayPosition, ray.position[0], ray.position[1]);
274
+ gl.uniform2f(locations.uRayDirection, ray.direction[0], ray.direction[1]);
275
+ },
276
+ render(time, pointer) {
277
+ const targetX = pointer?.active === true ? pointer.x : 0.5;
278
+ const targetY = pointer?.active === true ? pointer.y : 0.5;
279
+ smoothMouse.x += (targetX - smoothMouse.x) * 0.08;
280
+ smoothMouse.y += (targetY - smoothMouse.y) * 0.08;
281
+ gl.uniform1f(locations.uTime, time * 0.001);
282
+ gl.uniform2f(locations.uMouse, smoothMouse.x, smoothMouse.y);
283
+ gl.clear(gl.COLOR_BUFFER_BIT);
284
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
285
+ },
286
+ destroy() {
287
+ gl.deleteBuffer(buffer);
288
+ gl.deleteProgram(program);
289
+ const loseContext = gl.getExtension('WEBGL_lose_context');
290
+ if (loseContext) loseContext.loseContext();
291
+ }
292
+ });
293
+ }
@@ -0,0 +1,75 @@
1
+ const RUNTIME_CONFIG_ID = 'stellar-runtime-config';
2
+ const RUNTIME_QUERY = new URL(import.meta.url).search;
3
+
4
+ function deepFreeze(value) {
5
+ if (value == null || typeof value !== 'object' || Object.isFrozen(value)) return value;
6
+ Object.values(value).forEach(deepFreeze);
7
+ return Object.freeze(value);
8
+ }
9
+
10
+ function readManifest(documentRef) {
11
+ const element = documentRef.getElementById(RUNTIME_CONFIG_ID);
12
+ if (!element) throw new Error(`[stellar runtime] missing #${RUNTIME_CONFIG_ID}`);
13
+ const manifest = JSON.parse(element.textContent || 'null');
14
+ if (!manifest || manifest.version !== 1 || !Array.isArray(manifest.extensions)) {
15
+ throw new TypeError('[stellar runtime] invalid manifest');
16
+ }
17
+ return deepFreeze(manifest);
18
+ }
19
+
20
+ function dispatch(name, detail) {
21
+ document.dispatchEvent(new CustomEvent(name, { detail }));
22
+ }
23
+
24
+ async function start() {
25
+ const [assetModule, registryModule, adapterModule, requestModule] = await Promise.all([
26
+ import(`./asset-loader.js${RUNTIME_QUERY}`),
27
+ import(`./extension-registry.js${RUNTIME_QUERY}`),
28
+ import(`./legacy-request-adapter.js${RUNTIME_QUERY}`),
29
+ import(`./request-cache.js${RUNTIME_QUERY}`)
30
+ ]);
31
+ const { createAssetLoader } = assetModule;
32
+ const { createExtensionRegistry } = registryModule;
33
+ const { installLegacyRequestAdapter } = adapterModule;
34
+ const { createRequestClient } = requestModule;
35
+ const manifest = readManifest(document);
36
+ const assets = createAssetLoader({ document, root: manifest.root, version: RUNTIME_QUERY });
37
+ const request = createRequestClient({
38
+ cache: manifest.policy.cache,
39
+ policy: manifest.policy.request,
40
+ dispatch
41
+ });
42
+ installLegacyRequestAdapter(globalThis.utils, request, manifest.policy.request);
43
+
44
+ const registry = createExtensionRegistry({
45
+ onError(detail) {
46
+ console.error(`[stellar extension:${detail.id}] ${detail.phase} failed`, detail.error);
47
+ dispatch('stellar:extension-error', detail);
48
+ }
49
+ });
50
+ manifest.extensions.forEach(declaration => {
51
+ registry.register(Object.assign({}, declaration, {
52
+ module: `${assets.resolve(declaration.module)}${RUNTIME_QUERY}`
53
+ }));
54
+ });
55
+
56
+ const context = Object.freeze({
57
+ manifest,
58
+ assets,
59
+ request,
60
+ legacy: Object.freeze({
61
+ ctx: globalThis.ctx,
62
+ stellar: globalThis.stellar
63
+ })
64
+ });
65
+ await registry.mount(document, context);
66
+ window.addEventListener('pagehide', () => registry.unmount(document));
67
+ window.addEventListener('pageshow', event => {
68
+ if (event.persisted) registry.mount(document, context);
69
+ });
70
+ }
71
+
72
+ start().catch(error => {
73
+ console.error('[stellar runtime] bootstrap failed', error);
74
+ dispatch('stellar:runtime-error', { error });
75
+ });