@fusion.dev/helix 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/custom-elements.json +256 -256
  2. package/dist/accordion/item/accordion-item.css.js +0 -1
  3. package/dist/accordion/item/accordion-item.js +0 -29
  4. package/dist/accordion/root/accordion-root.css.js +0 -1
  5. package/dist/accordion/root/accordion-root.js +0 -20
  6. package/dist/announcement/root/announcement-root.css.js +0 -1
  7. package/dist/announcement/root/announcement-root.js +0 -16
  8. package/dist/app-header/root/app-header-root.css.js +0 -1
  9. package/dist/app-header/root/app-header-root.js +0 -45
  10. package/dist/aura/root/aura-axis.js +0 -58
  11. package/dist/aura/root/aura-root.css.js +0 -1
  12. package/dist/aura/root/aura-root.js +0 -520
  13. package/dist/aura/root/aura-shader.js +0 -35
  14. package/dist/avatar/group/avatar-group.css.js +0 -1
  15. package/dist/avatar/group/avatar-group.js +0 -24
  16. package/dist/avatar/root/avatar-root.css.js +0 -1
  17. package/dist/avatar/root/avatar-root.js +0 -23
  18. package/dist/badge/root/badge-root.css.js +0 -1
  19. package/dist/badge/root/badge-root.d.ts +2 -6
  20. package/dist/badge/root/badge-root.js +0 -18
  21. package/dist/bar-chart/root/bar-chart-root.css.js +0 -1
  22. package/dist/bar-chart/root/bar-chart-root.js +0 -50
  23. package/dist/blockquote/root/blockquote-root.css.js +0 -1
  24. package/dist/blockquote/root/blockquote-root.js +0 -17
  25. package/dist/breadcrumbs/breadcrumb/breadcrumb.css.js +0 -1
  26. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +0 -28
  27. package/dist/breadcrumbs/root/breadcrumbs-root.css.js +0 -1
  28. package/dist/breadcrumbs/root/breadcrumbs-root.js +0 -19
  29. package/dist/button/root/button-root.css.js +0 -1
  30. package/dist/button/root/button-root.js +0 -38
  31. package/dist/button-group/root/button-group-root.css.js +0 -1
  32. package/dist/button-group/root/button-group-root.js +0 -24
  33. package/dist/callout/root/callout-root.css.js +0 -1
  34. package/dist/callout/root/callout-root.js +0 -26
  35. package/dist/card/root/card-root.css.js +0 -1
  36. package/dist/card/root/card-root.js +0 -45
  37. package/dist/carousel/root/carousel-root.css.js +0 -1
  38. package/dist/carousel/root/carousel-root.js +0 -24
  39. package/dist/chat/composer/chat-composer.css.js +0 -1
  40. package/dist/chat/composer/chat-composer.js +0 -26
  41. package/dist/chat/message/chat-message.css.js +0 -1
  42. package/dist/chat/message/chat-message.js +0 -29
  43. package/dist/chat/root/chat-root.css.js +0 -1
  44. package/dist/chat/root/chat-root.js +0 -38
  45. package/dist/checkbox/root/checkbox-root.css.js +0 -1
  46. package/dist/checkbox/root/checkbox-root.js +0 -26
  47. package/dist/checkbox-group/root/checkbox-group-root.css.js +0 -1
  48. package/dist/checkbox-group/root/checkbox-group-root.js +0 -15
  49. package/dist/code/root/code-root.css.js +0 -1
  50. package/dist/code/root/code-root.js +0 -21
  51. package/dist/code-block/root/code-block-root.css.js +0 -1
  52. package/dist/code-block/root/code-block-root.js +0 -19
  53. package/dist/color-input/root/color-input-root.css.js +0 -1
  54. package/dist/color-input/root/color-input-root.js +0 -42
  55. package/dist/color-picker/root/color-picker-root.css.js +0 -1
  56. package/dist/color-picker/root/color-picker-root.js +0 -42
  57. package/dist/combobox/root/combobox-root.css.js +0 -1
  58. package/dist/combobox/root/combobox-root.js +0 -28
  59. package/dist/command/root/command-root.css.js +0 -1
  60. package/dist/command/root/command-root.js +0 -21
  61. package/dist/copy-button/root/copy-button-root.css.js +0 -1
  62. package/dist/copy-button/root/copy-button-root.js +0 -14
  63. package/dist/data-table/root/data-table-root.css.js +0 -1
  64. package/dist/data-table/root/data-table-root.js +0 -39
  65. package/dist/date-input/root/date-input-root.css.js +0 -1
  66. package/dist/date-input/root/date-input-root.js +0 -38
  67. package/dist/date-picker/root/date-picker-root.css.js +0 -1
  68. package/dist/date-picker/root/date-picker-root.js +0 -28
  69. package/dist/dialog/root/dialog-root.css.js +0 -1
  70. package/dist/dialog/root/dialog-root.js +0 -31
  71. package/dist/divider/root/divider-root.css.js +0 -1
  72. package/dist/divider/root/divider-root.js +0 -24
  73. package/dist/donut-chart/root/donut-chart-root.css.js +0 -1
  74. package/dist/donut-chart/root/donut-chart-root.js +0 -49
  75. package/dist/drawer/root/drawer-root.css.js +0 -1
  76. package/dist/drawer/root/drawer-root.js +0 -38
  77. package/dist/drilldown/item/drilldown-item.css.js +0 -1
  78. package/dist/drilldown/item/drilldown-item.js +0 -15
  79. package/dist/drilldown/root/drilldown-root.css.js +0 -1
  80. package/dist/drilldown/root/drilldown-root.js +0 -23
  81. package/dist/element-events.generated.js +0 -5
  82. package/dist/empty/root/empty-root.css.js +0 -1
  83. package/dist/empty/root/empty-root.js +0 -16
  84. package/dist/file-input/root/file-input-root.css.js +0 -1
  85. package/dist/file-input/root/file-input-root.js +0 -30
  86. package/dist/flex/root/flex-root.css.js +0 -1
  87. package/dist/flex/root/flex-root.js +0 -32
  88. package/dist/format-date/root/format-date-root.css.js +0 -1
  89. package/dist/format-date/root/format-date-root.js +0 -17
  90. package/dist/grid/root/grid-root.css.js +0 -1
  91. package/dist/grid/root/grid-root.js +0 -69
  92. package/dist/heatmap/root/heatmap-root.css.js +0 -1
  93. package/dist/heatmap/root/heatmap-root.d.ts +9 -11
  94. package/dist/heatmap/root/heatmap-root.js +0 -73
  95. package/dist/icon/glyph.css.js +0 -1
  96. package/dist/icon/root/icon-root.css.js +0 -1
  97. package/dist/icon/root/icon-root.js +0 -19
  98. package/dist/icon-button/root/icon-button-root.css.js +0 -1
  99. package/dist/icon-button/root/icon-button-root.js +0 -35
  100. package/dist/image/root/image-root.css.js +0 -1
  101. package/dist/image/root/image-root.js +0 -28
  102. package/dist/index.js +0 -5
  103. package/dist/input/root/input-root.css.js +0 -1
  104. package/dist/input/root/input-root.js +0 -28
  105. package/dist/kbd/root/kbd-root.css.js +0 -1
  106. package/dist/kbd/root/kbd-root.js +0 -20
  107. package/dist/legend/root/legend-root.css.js +0 -1
  108. package/dist/legend/root/legend-root.js +0 -35
  109. package/dist/line-chart/root/line-chart-root.css.js +0 -1
  110. package/dist/line-chart/root/line-chart-root.js +0 -47
  111. package/dist/list/item/list-item.css.js +0 -1
  112. package/dist/list/item/list-item.js +0 -38
  113. package/dist/list/root/list-root.css.js +0 -1
  114. package/dist/list/root/list-root.js +0 -23
  115. package/dist/listbox/root/listbox-root.css.js +0 -1
  116. package/dist/listbox/root/listbox-root.js +0 -22
  117. package/dist/loader/root/loader-root.css.js +0 -1
  118. package/dist/loader/root/loader-root.js +0 -19
  119. package/dist/megamenu/root/megamenu-root.css.js +0 -1
  120. package/dist/megamenu/root/megamenu-root.js +0 -24
  121. package/dist/menu/item/menu-item.css.js +0 -1
  122. package/dist/menu/item/menu-item.js +0 -16
  123. package/dist/menu/root/menu-root.css.js +0 -1
  124. package/dist/menu/root/menu-root.js +0 -26
  125. package/dist/meter/root/meter-root.css.js +0 -1
  126. package/dist/meter/root/meter-root.js +0 -50
  127. package/dist/mixins/mixin-control-surface/mixin-control-surface.js +0 -3
  128. package/dist/navigation/root/navigation-root.css.js +0 -1
  129. package/dist/navigation/root/navigation-root.js +0 -18
  130. package/dist/notifications/notification/notification.css.js +0 -1
  131. package/dist/notifications/notification/notification.js +0 -53
  132. package/dist/notifications/root/notifications-root.css.js +0 -1
  133. package/dist/notifications/root/notifications-root.js +0 -31
  134. package/dist/number-input/root/number-input-root.css.js +0 -1
  135. package/dist/number-input/root/number-input-root.js +0 -31
  136. package/dist/option/group/option-group.css.js +0 -1
  137. package/dist/option/group/option-group.js +0 -13
  138. package/dist/option/root/option-root.css.js +0 -1
  139. package/dist/option/root/option-root.js +0 -20
  140. package/dist/outline/root/outline-root.css.js +0 -1
  141. package/dist/outline/root/outline-root.js +0 -21
  142. package/dist/pagination/root/pagination-root.css.js +0 -1
  143. package/dist/pagination/root/pagination-root.js +0 -49
  144. package/dist/pagination/size/pagination-size.css.js +0 -1
  145. package/dist/pagination/size/pagination-size.js +0 -25
  146. package/dist/pagination/summary/pagination-summary.css.js +0 -1
  147. package/dist/pagination/summary/pagination-summary.js +0 -13
  148. package/dist/pin-input/root/pin-input-root.css.js +0 -1
  149. package/dist/pin-input/root/pin-input-root.js +0 -27
  150. package/dist/popover/root/popover-root.css.js +0 -1
  151. package/dist/popover/root/popover-root.js +0 -30
  152. package/dist/progress/root/progress-root.css.js +0 -1
  153. package/dist/progress/root/progress-root.js +0 -25
  154. package/dist/qr-code/root/qr-code-root.css.js +0 -1
  155. package/dist/qr-code/root/qr-code-root.js +0 -27
  156. package/dist/quote/root/quote-root.css.js +0 -1
  157. package/dist/quote/root/quote-root.js +0 -15
  158. package/dist/radio/group/radio-group.css.js +0 -1
  159. package/dist/radio/group/radio-group.js +0 -16
  160. package/dist/radio/root/radio-root.css.js +0 -1
  161. package/dist/radio/root/radio-root.js +0 -46
  162. package/dist/rating/root/rating-root.css.js +0 -1
  163. package/dist/rating/root/rating-root.js +0 -22
  164. package/dist/sandbox/index.js +0 -14
  165. package/dist/sandbox/preview/sandbox-preview.css.js +0 -1
  166. package/dist/sandbox/preview/sandbox-preview.js +0 -182
  167. package/dist/sandbox/root/sandbox-root.css.js +0 -1
  168. package/dist/sandbox/root/sandbox-root.js +1 -295
  169. package/dist/sandbox/source/sandbox-source.css.js +0 -1
  170. package/dist/sandbox/source/sandbox-source.js +0 -77
  171. package/dist/sandbox/status-bar/sandbox-status-bar.css.js +0 -1
  172. package/dist/sandbox/status-bar/sandbox-status-bar.js +0 -38
  173. package/dist/sandbox/terminal/sandbox-terminal.css.js +0 -1
  174. package/dist/sandbox/terminal/sandbox-terminal.js +0 -54
  175. package/dist/sandbox/toolbar/sandbox-toolbar.css.js +0 -1
  176. package/dist/sandbox/toolbar/sandbox-toolbar.js +0 -29
  177. package/dist/scroll-area/root/scroll-area-root.css.js +0 -1
  178. package/dist/scroll-area/root/scroll-area-root.js +0 -24
  179. package/dist/select/root/select-root.css.js +0 -1
  180. package/dist/select/root/select-root.js +0 -33
  181. package/dist/shared/chart/series.css.js +0 -1
  182. package/dist/shared/chart/terminus.css.js +0 -1
  183. package/dist/shared/field/field-inline.css.js +0 -1
  184. package/dist/shared/field/field-stacked.css.js +0 -1
  185. package/dist/shared/field/field.css.js +0 -1
  186. package/dist/skeleton/root/skeleton-root.css.js +0 -1
  187. package/dist/skeleton/root/skeleton-root.js +0 -18
  188. package/dist/slider/root/slider-root.css.js +0 -1
  189. package/dist/slider/root/slider-root.js +0 -32
  190. package/dist/sparkline/root/sparkline-root.css.js +0 -1
  191. package/dist/sparkline/root/sparkline-root.js +0 -40
  192. package/dist/speed-dial/item/speed-dial-item.css.js +0 -1
  193. package/dist/speed-dial/item/speed-dial-item.js +0 -16
  194. package/dist/speed-dial/root/speed-dial-root.css.js +0 -1
  195. package/dist/speed-dial/root/speed-dial-root.js +0 -16
  196. package/dist/splitter/root/splitter-root.css.js +0 -1
  197. package/dist/splitter/root/splitter-root.js +0 -50
  198. package/dist/stat/group/stat-group.css.js +0 -1
  199. package/dist/stat/group/stat-group.js +0 -19
  200. package/dist/stat/root/stat-root.css.js +0 -1
  201. package/dist/stat/root/stat-root.js +0 -17
  202. package/dist/steps/root/steps-root.css.js +0 -1
  203. package/dist/steps/root/steps-root.js +0 -26
  204. package/dist/steps/step/step.css.js +0 -1
  205. package/dist/steps/step/step.js +0 -12
  206. package/dist/switch/root/switch-root.css.js +0 -1
  207. package/dist/switch/root/switch-root.js +0 -32
  208. package/dist/table/cell/table-cell.css.js +0 -1
  209. package/dist/table/cell/table-cell.js +0 -14
  210. package/dist/table/column/table-column.css.js +0 -1
  211. package/dist/table/column/table-column.js +0 -13
  212. package/dist/table/root/table-root.css.js +0 -1
  213. package/dist/table/root/table-root.js +0 -19
  214. package/dist/table/row/table-row.css.js +0 -1
  215. package/dist/table/row/table-row.js +0 -14
  216. package/dist/tabs/panel/tab-panel.css.js +0 -1
  217. package/dist/tabs/panel/tab-panel.js +0 -16
  218. package/dist/tabs/root/tabs-root.css.js +0 -1
  219. package/dist/tabs/root/tabs-root.js +0 -19
  220. package/dist/tabs/tab/tab.css.js +0 -1
  221. package/dist/tabs/tab/tab.js +0 -16
  222. package/dist/tag/root/tag-root.css.js +0 -1
  223. package/dist/tag/root/tag-root.js +0 -25
  224. package/dist/text/root/text-root.css.js +0 -1
  225. package/dist/text/root/text-root.js +0 -48
  226. package/dist/textarea/root/textarea-root.css.js +0 -1
  227. package/dist/textarea/root/textarea-root.js +0 -17
  228. package/dist/time-input/root/time-input-root.css.js +0 -1
  229. package/dist/time-input/root/time-input-root.js +0 -31
  230. package/dist/time-picker/root/time-picker-root.css.js +0 -1
  231. package/dist/time-picker/root/time-picker-root.js +0 -29
  232. package/dist/timeline/item/timeline-item.css.js +0 -1
  233. package/dist/timeline/item/timeline-item.js +0 -17
  234. package/dist/timeline/root/timeline-root.css.js +0 -1
  235. package/dist/timeline/root/timeline-root.js +0 -15
  236. package/dist/toast/item/toast-item.css.js +0 -1
  237. package/dist/toast/item/toast-item.js +0 -21
  238. package/dist/toast/root/toast-root.css.js +0 -1
  239. package/dist/toast/root/toast-root.js +0 -27
  240. package/dist/toggle/group/toggle-group.css.js +0 -1
  241. package/dist/toggle/group/toggle-group.js +0 -25
  242. package/dist/toggle/root/toggle-root.css.js +0 -1
  243. package/dist/toggle/root/toggle-root.js +0 -18
  244. package/dist/toolbar/root/toolbar-root.css.js +0 -1
  245. package/dist/toolbar/root/toolbar-root.js +0 -19
  246. package/dist/tooltip/root/tooltip-root.css.js +0 -1
  247. package/dist/tooltip/root/tooltip-root.js +0 -22
  248. package/dist/tour/root/tour-root.css.js +0 -1
  249. package/dist/tour/root/tour-root.js +0 -14
  250. package/dist/tour/stop/tour-stop.css.js +0 -1
  251. package/dist/tour/stop/tour-stop.js +0 -22
  252. package/dist/tree/item/tree-item.css.js +0 -1
  253. package/dist/tree/item/tree-item.js +0 -34
  254. package/dist/tree/root/tree-root.css.js +0 -1
  255. package/dist/tree/root/tree-root.js +0 -27
  256. package/dist/trend/root/trend-root.css.js +0 -1
  257. package/dist/trend/root/trend-root.js +0 -34
  258. package/dist/video/root/video-root.css.js +0 -1
  259. package/dist/video/root/video-root.js +0 -37
  260. package/dist/video-playlist/item/video-playlist-item.css.js +0 -1
  261. package/dist/video-playlist/item/video-playlist-item.js +0 -15
  262. package/dist/video-playlist/menu/video-playlist-menu.css.js +0 -1
  263. package/dist/video-playlist/menu/video-playlist-menu.js +0 -36
  264. package/dist/video-playlist/root/video-playlist-root.css.js +0 -1
  265. package/dist/video-playlist/root/video-playlist-root.js +0 -16
  266. package/dist/virtual-list/root/virtual-list-root.css.js +0 -1
  267. package/dist/virtual-list/root/virtual-list-root.js +0 -21
  268. package/jsx.d.ts +1538 -2818
  269. package/package.json +7 -7
  270. package/vue.d.ts +3 -7
@@ -11,169 +11,25 @@ import { property } from 'lit/decorators.js';
11
11
  import { tiltFor } from './aura-axis.js';
12
12
  import { styles } from './aura-root.css.js';
13
13
  import { FRAGMENT, INTERACTIONS, SHAPES, VERTEX } from './aura-shader.js';
14
- /**
15
- * The widest either edge of the drawing buffer may get, in device pixels.
16
- *
17
- * Past `MAX_RENDERBUFFER_SIZE` a canvas does not draw at all, and WebGL2
18
- * guarantees only 2048. Desktop parts report 16384 and older integrated ones
19
- * report 8192, which a page-length field can pass.
20
- */
21
14
  const MAX_CANVAS_EDGE = 4096;
22
- /**
23
- * The most device pixels the drawing buffer may hold, at 2048 squared.
24
- *
25
- * Every one of them runs five octaves of noise through two warps on every
26
- * frame, so this is the fill rate rather than the fidelity: roughly what the
27
- * component already cost over the two screens it was designed against.
28
- */
29
15
  const MAX_CANVAS_PIXELS = 4_194_304;
30
- /**
31
- * How long the opening frame will wait for the box to stop changing, in ms.
32
- *
33
- * The field is scaled by its box, so painting a box that is still settling draws
34
- * the same shape at several sizes and reads as the background zooming out. The
35
- * wait ends one animation frame after the last change; this is only the cap, for
36
- * a page that never stops resizing it. Longer than any load takes to settle and
37
- * shorter than a reader takes to conclude the background is just a gradient.
38
- */
39
16
  const OPENING_PATIENCE = 500;
40
- /**
41
- * @summary A lit, drifting background, drawn from the token layer.
42
- *
43
- * @description
44
- * One fragment shader over a full-screen triangle, with the palette read from
45
- * the tokens rather than given as colors. That is the whole reason this belongs
46
- * in a design system instead of in a page: a background written with hex values
47
- * is an asset that has to be re-cut when the brand moves, and one written
48
- * against `--helix-color-primary` is a consequence of it.
49
- *
50
- * **Every shape ramps through four token stops**, and the token layer inverts
51
- * each of them: the page's own background, `primary-subtle`, `primary`, and
52
- * then a peak. The peak is the foreground on a dark page and `primary-active`
53
- * on a light one, because mixing a saturated hue toward near-black takes the
54
- * chroma out of exactly the pixels carrying the most of it. Which way the page
55
- * runs is not asked of the mode, which is a private token: it is read off the
56
- * ground's own luminance, which the shader already has.
57
- *
58
- * **No dependency, and no scene graph.** The geometry is three vertices derived
59
- * from `gl_VertexID`, so there is no attribute, no buffer and no upload. The
60
- * common implementations of this reach for a 3D library to draw one quad, which
61
- * is a camera and a material system for four vertices that never move.
62
- *
63
- * **It stops when nobody is looking**, off screen and in a background tab, and
64
- * `prefers-reduced-motion` gets one still frame rather than an empty box: the
65
- * composition is the point and the drift is a garnish.
66
- *
67
- * **A layer over an interactive aura has to let the pointer through.** The
68
- * element is hit-testable only when `interactive` is set, because a background
69
- * that swallows clicks is worse than one that does nothing, but a scrim or an
70
- * overlay a consumer paints on top will absorb the move before it arrives. Any
71
- * decorative layer above this wants `pointer-events: none`. It has already
72
- * caught this repository's own bench once.
73
- *
74
- * **The fallback needs no detection.** Where WebGL is refused the canvas never
75
- * paints and is transparent, and the host carries a gradient of the same tokens
76
- * underneath. Nothing has to ask whether it worked.
77
- *
78
- * Presentation only, so there is no headless tier: the split exists to keep
79
- * behavior separate from styling, and there is no structure or semantics here
80
- * to separate. Decorative, so the host is hidden from assistive technology and
81
- * takes no pointer events.
82
- *
83
- * @since 0.1.0
84
- * @status experimental
85
- * @category media
86
- * @aliases Backdrop, Background, Atmosphere, Gradient
87
- * @documentation https://helix.fusion.dev/components/aura
88
- *
89
- * @csspart canvas - The surface the shader draws into.
90
- */
91
17
  let HelixAura = class HelixAura extends HelixElement {
92
18
  constructor() {
93
19
  super(...arguments);
94
- /**
95
- * How soft the falloff is, `0` tight and `1` diffuse.
96
- */
97
20
  this.bloom = 0.5;
98
- /**
99
- * How far the settings wander on their own, `0` still and `1` restless.
100
- *
101
- * **One property rather than a range on each of the five.** A range per axis
102
- * is five more things to author and four more chances to write a pair that
103
- * fights another; the reason to want any of it is the same reason in every
104
- * case, which is that a fixed field is legibly a loop. So this is an amount,
105
- * and each axis is given its own span and its own period.
106
- *
107
- * The periods are irrational multiples of each other, so no two axes come
108
- * back into phase and the field has no cycle a reader can count. That is the
109
- * difference between a background that breathes and one that is obviously on
110
- * a timer.
111
- */
112
21
  this.drift = 0;
113
- /**
114
- * Overall brightness, as a multiplier on the field.
115
- */
116
22
  this.gain = 1;
117
- /**
118
- * Whether the pointer shifts and lifts the field.
119
- *
120
- * Reflected because the stylesheet selects on it: a background is not
121
- * hit-testable at rest, or it would swallow clicks meant for what is over it,
122
- * and an element that is not hit-testable never receives the `pointermove`
123
- * this listens for. Asking for the pointer is asking for the hit test.
124
- */
125
23
  this.interactive = false;
126
- /**
127
- * How far the pointer reaches into the field, `0` upward.
128
- *
129
- * Multiplied into the presence the pointer already fades in and out with, so
130
- * it scales the whole response rather than any one part of it, whichever
131
- * interaction is in play.
132
- */
133
24
  this.reach = 1;
134
- /**
135
- * Feature size, as a multiplier on the sampled coordinates.
136
- */
137
25
  this.scale = 1;
138
- /**
139
- * How fast it drifts, as a multiplier on time.
140
- */
141
26
  this.speed = 1;
142
- /**
143
- * The field's rotation, in degrees.
144
- */
145
27
  this.tilt = 14;
146
- /**
147
- * How much the members of a population differ from one another, `0` a set
148
- * that is uniform and `1` the resting amount. Clamped to that range: these
149
- * are interpolations, so a larger number extrapolates rather than
150
- * exaggerating, and a streak whose length has passed through zero is drawn
151
- * as a bar across the whole frame.
152
- *
153
- * Read by the shapes made of many similar things, whether those are counted
154
- * or continuous: `streaks`, whose lanes draw a speed, a length, a width, a
155
- * spacing and a weight apiece; `particles`, whose motes draw a size, a
156
- * brightness and a wander; and `rays` and `aurora`, whose fan, bundles and
157
- * folds widen or even out. `braid`, `waves` and `flow` have a
158
- * single subject and nothing to vary, and `threads` is even on purpose, so on
159
- * those four this is inert.
160
- */
161
28
  this.variance = 1;
162
- /** Repaints when the palette moves, which no re-render would do on its own. */
163
29
  this.tokens = new TokenColorController(this, () => {
164
30
  this.readPalette();
165
31
  this.paintOnce();
166
32
  });
167
- /**
168
- * The four ramp stops, resolved.
169
- *
170
- * **Cached, because reading them is not free and they do not move.** Each
171
- * read sets a style, calls `getComputedStyle`, fills a pixel and reads it
172
- * back: a style recalc and a canvas readback apiece. Doing that inside
173
- * `paint` meant four of each on every frame, forever, to fetch values that
174
- * change only when the color mode does. The controller already says when
175
- * that happens, so this is filled from there and from the first paint.
176
- */
177
33
  this.palette = {
178
34
  glow: [0.29, 0.61, 1],
179
35
  ground: [0, 0, 0],
@@ -184,108 +40,22 @@ let HelixAura = class HelixAura extends HelixElement {
184
40
  this.gl = null;
185
41
  this.program = null;
186
42
  this.uniforms = {};
187
- /** The pending context release, or `0`. Canceled by a reconnection. */
188
43
  this.release = 0;
189
44
  this.frame = 0;
190
45
  this.elapsed = 0;
191
46
  this.last = 0;
192
47
  this.width = 0;
193
48
  this.height = 0;
194
- /**
195
- * Where the pointer has been, as flat triples of x, y and age.
196
- *
197
- * A ring rather than a queue: the oldest slot is overwritten, so nothing is
198
- * allocated and the cost is the same on the first second and the thousandth.
199
- */
200
49
  this.trail = new Float32Array(8 * 3).fill(1);
201
50
  this.trailNext = 0;
202
- /**
203
- * The same marks, oldest first, which is what the shader is given.
204
- *
205
- * The ring's own order is not time order, and the wake is drawn as a polyline
206
- * through consecutive entries: a segment across the wrap joined the newest
207
- * mark to the oldest and drew a bright bar clean through the middle of the
208
- * field. Unrolled once per frame, which is eight copies.
209
- */
210
51
  this.ordered = new Float32Array(9 * 3).fill(1);
211
- /**
212
- * The live end of the stroke, outside the ring.
213
- *
214
- * **In the ring it destroyed a mark every time it committed.** The head was
215
- * the slot at `trailNext`, so advancing wrote over whatever was oldest, and
216
- * the tail of the stroke lost a point instantly rather than fading. Held
217
- * apart, committing appends where the head already is: the polyline goes from
218
- * ending at P to ending at P, P, which is the same shape, and nothing jumps.
219
- */
220
52
  this.head = { x: 1, y: 1 };
221
- /**
222
- * Where the pointer is, and where the field has got to. The gap is weight.
223
- *
224
- * `presence`, not `reach`: the eased value is how far the pointer has faded
225
- * in, and `reach` is the consumer's amplitude. The two multiply.
226
- */
227
53
  this.target = { presence: 0, x: 0, y: 0 };
228
54
  this.eased = { presence: 0, x: 0, y: 0 };
229
- /**
230
- * The element's box, cached.
231
- *
232
- * **Never read per event.** `getBoundingClientRect` forces a synchronous
233
- * layout, and a pointer emits events far faster than the display refreshes: a
234
- * 1000Hz mouse flushed layout a thousand times a second to compute a number
235
- * that only changes when the page reflows. Refreshed from the resize observer
236
- * and from scroll, both of which are exactly when it can go stale, and never
237
- * from the handler that reads it.
238
- */
239
55
  this.box = { height: 1, left: 0, top: 0, width: 1 };
240
- /**
241
- * Whether the field has drawn its opening frame yet.
242
- *
243
- * **The box changes shape while a page is arriving, and this shader is scaled
244
- * by the box.** `p.y` spans [-1, 1] over the element's height, so a feature's
245
- * size in pixels is proportional to how tall the box happens to be when the
246
- * frame is drawn. A page that upgrades its custom elements, loads its fonts
247
- * and settles its images passes through several heights on the way to its
248
- * final one, and painting each of them draws the same field at several
249
- * scales: it opens coarse and tightens, which reads as the background zooming
250
- * out on load rather than as a background.
251
- *
252
- * Refusing the degenerate 0 by 0 box leaves the ordinary case: a first real
253
- * box that is simply not the last one.
254
- *
255
- * So the opening frame waits for the box to stop moving. Nothing paints until
256
- * a measurement has stood unchanged for one animation frame, which is the
257
- * cheapest definition of settled that is not a guess, and the host's own
258
- * gradient covers the wait. After that a resize repaints immediately, because
259
- * by then a change is the window moving rather than the page arriving.
260
- */
261
56
  this.opened = false;
262
- /** The pending opening frame, canceled and rescheduled by each new box. */
263
57
  this.opening = 0;
264
- /**
265
- * When to stop waiting and draw anyway.
266
- *
267
- * A page that resizes the field every frame forever would otherwise never get
268
- * an opening frame at all. Half a second is far longer than a load takes to
269
- * settle and far shorter than a reader waits before deciding the background is
270
- * simply a gradient.
271
- */
272
58
  this.openBy = 0;
273
- /**
274
- * Gives the context back, once nothing has claimed the element again.
275
- *
276
- * **The context is not released by dropping the reference.** A browser caps
277
- * live WebGL contexts at about sixteen and drops the oldest when a
278
- * seventeenth is asked for, so a page that mounts and unmounts auras kills
279
- * the ones still on screen: the symptom is an aura elsewhere going blank,
280
- * which looks like a fault in that element and is this one. The context
281
- * belongs to the canvas, and the canvas is held by the shadow root until the
282
- * element is collected, which is a moment nothing here controls and which is
283
- * far too late for a cap of sixteen. `WEBGL_lose_context` is the only way.
284
- *
285
- * **It spends the canvas**, which is what `build` is written around: the
286
- * canvas can never serve a context again and a returning element takes a
287
- * fresh one.
288
- */
289
59
  this.drop = () => {
290
60
  this.release = 0;
291
61
  if (this.gl && this.program) {
@@ -299,48 +69,13 @@ let HelixAura = class HelixAura extends HelixElement {
299
69
  if (!this.last) {
300
70
  this.last = now;
301
71
  }
302
- /* Skipped rather than rescheduled on a timer: `requestAnimationFrame` is
303
- what pauses in a background tab and what matches the display, and a
304
- `setTimeout` loop would give up both to save the same work. */
305
72
  if (!this.interactive && now - this.last < HelixAura_1.CAPPED) {
306
73
  this.frame = requestAnimationFrame(this.tick);
307
74
  return;
308
75
  }
309
- /* Clamped: a tab returning from the background delivers one enormous delta,
310
- and the field would teleport to wherever the pointer had gone. */
311
76
  const delta = Math.min((now - this.last) / 1000, 0.05);
312
77
  this.last = now;
313
- /* Accumulated rather than measured from a start stamp. A stamp reset on
314
- every pause means a reader who switched tabs and came back finds the
315
- field snapped to its opening frame, which is the one thing a background
316
- must never do. */
317
78
  this.elapsed += delta * Math.max(0, this.drifted(this.speed, 0.4, 0.043));
318
- /* Two time constants, because position and presence are two different jobs
319
- and one number serves both badly.
320
-
321
- **Position tracks.** A parallax that lags is not weighty, it is late: at
322
- 85 milliseconds it took about two tenths of a second to close nine tenths
323
- of the gap, which is well inside what a reader perceives as the page
324
- being slow rather than the field being heavy.
325
-
326
- **Presence does not.** `reach` is the effect fading in as the pointer
327
- arrives and out as it leaves, and that wants to be gradual: snapped on,
328
- the whole field flinches the instant a cursor crosses the edge.
329
-
330
- **The position constant scales with the gap, because one constant cannot
331
- do both jobs.** A fixed 28 milliseconds leaves a moving pointer a
332
- distance v * t behind it for as long as it keeps moving: about 56 pixels
333
- at a 2000 pixel per second flick and twice that at twice the speed, which
334
- is what reads as the field being unable to keep up. Lowering it for
335
- everyone would give the jitter of a resting hand straight back to the
336
- shader, which is the only thing the smoothing was ever there for. Jitter
337
- is small and a flick is large, so the size of the gap is the signal that
338
- tells them apart: at rest this eases over about 25 milliseconds, a gap of
339
- one shape unit closes over nine, and two over five.
340
-
341
- Frame-rate independent, written as a time constant rather than a
342
- per-frame factor: a factor ties the feel to the refresh rate, so a 120Hz
343
- display would chase twice as eagerly as a 60Hz one. */
344
79
  const drift = Math.hypot(this.target.x - this.eased.x, this.target.y - this.eased.y);
345
80
  const follow = 1 - Math.exp(-delta / (0.028 / (1 + drift * 2.4)));
346
81
  if (!this.interactive) {
@@ -348,13 +83,6 @@ let HelixAura = class HelixAura extends HelixElement {
348
83
  }
349
84
  this.eased.x += (this.target.x - this.eased.x) * follow;
350
85
  this.eased.y += (this.target.y - this.eased.y) * follow;
351
- /* Presence rises fast and falls slowly, which is not symmetry for its own
352
- sake. A single constant meant the effect took about four tenths of a
353
- second to reach full strength every time a pointer entered, and that
354
- ramp is indistinguishable from lag: a reader moves in, nothing much
355
- happens, and by the time it does they have decided the page is slow.
356
- Rising in 115 milliseconds it answers immediately; falling over half a
357
- second it lets go without the field flinching as the cursor crosses out. */
358
86
  const rising = this.target.presence > this.eased.presence;
359
87
  const fade = 1 - Math.exp(-delta / (rising ? 0.05 : 0.22));
360
88
  this.eased.presence += (this.target.presence - this.eased.presence) * fade;
@@ -385,15 +113,12 @@ let HelixAura = class HelixAura extends HelixElement {
385
113
  }
386
114
  };
387
115
  this.handleScroll = () => {
388
- /* Only the origin can have moved, and only what the pointer is measured
389
- against needs it, so this refreshes the cache and draws nothing. */
390
116
  const rect = this.getBoundingClientRect();
391
117
  this.box = { ...this.box, left: rect.left, top: rect.top };
392
118
  };
393
119
  }
394
120
  static { HelixAura_1 = this; }
395
121
  static { this.styles = [styles]; }
396
- /** What every context is asked for, here rather than at two call sites. */
397
122
  static { this.CONTEXT = {
398
123
  alpha: true,
399
124
  antialias: false,
@@ -402,34 +127,15 @@ let HelixAura = class HelixAura extends HelixElement {
402
127
  stencil: false,
403
128
  }; }
404
129
  render() {
405
- /* `aria-hidden` on the canvas rather than on the host, because a consumer
406
- may want to label the region this sits behind and a hidden host would
407
- take that with it. The canvas itself never has anything to announce. */
408
130
  return html `<canvas part="canvas" aria-hidden="true"></canvas>`;
409
131
  }
410
132
  firstUpdated() {
411
133
  this.start();
412
134
  }
413
- /* Everything the canvas needs, in one place both lifecycles can reach.
414
- *
415
- * `firstUpdated` runs once for the life of the element, while
416
- * `disconnectedCallback` deletes the program, drops the context and
417
- * disconnects both observers, and runs every time the element moves. Setup
418
- * that lives only in `firstUpdated` therefore leaves an aura reordered by a
419
- * framework with `this.gl` null and nothing to rebuild it: a live component
420
- * painting nothing, for the rest of the page's life, with no error anywhere.
421
- *
422
- * Guarded at the call site on `hasUpdated`, because the first connection
423
- * happens before the first render and there is no canvas yet. */
424
135
  start() {
425
- /* Client only, and by contract. There is no canvas on a server, so the
426
- shader is an enhancement over markup that already renders a gradient. */
427
136
  if (!this.renderRoot.querySelector('canvas')) {
428
137
  return;
429
138
  }
430
- /* A reconnection that outran its own release has everything already: the
431
- context is live and the program is linked, so the reorder costs the
432
- listeners and the observers and no GL work at all. */
433
139
  if (!this.program && !this.build()) {
434
140
  return;
435
141
  }
@@ -446,18 +152,8 @@ let HelixAura = class HelixAura extends HelixElement {
446
152
  });
447
153
  this.visible.observe(this);
448
154
  document.addEventListener('visibilitychange', this.handleVisibility);
449
- /* Scroll moves the box without resizing it, and the cached origin is what
450
- the pointer is measured against. Passive, because nothing here cancels. */
451
155
  window.addEventListener('scroll', this.handleScroll, { capture: true, passive: true });
452
156
  this.sized = new ResizeObserver(() => {
453
- /* **A resize repaints unconditionally rather than asking.**
454
- `measure` clears the drawing buffer whenever it resizes it, because
455
- assigning `canvas.width` is a reset and not a hint. `paintOnce` declines
456
- while the loop holds a frame handle, which is right for a property
457
- change the loop is about to draw anyway and wrong here: the canvas is
458
- already transparent by the time it declines, so the fallback gradient
459
- underneath showed through until the next tick landed. One frame, on
460
- every reflow that changed the box. */
461
157
  if (!this.measure()) {
462
158
  this.paintOnce();
463
159
  return;
@@ -475,47 +171,18 @@ let HelixAura = class HelixAura extends HelixElement {
475
171
  this.open();
476
172
  }
477
173
  }
478
- /**
479
- * The context and the program, from whatever canvas can still give one.
480
- *
481
- * **A canvas whose context was force-lost never yields a working one again.**
482
- * `getContext` hands back the very same dead object, which reports
483
- * `isContextLost()` and answers `null` to every `getShaderParameter`, so
484
- * `link` fails, `start` returns before installing a single observer, and the
485
- * element sits connected and permanently blind, holding whatever buffer it
486
- * last painted. Measured on the landing page, where one remove-and-reinsert
487
- * was enough: the frozen frame was the 2x2 the first `measure` took before
488
- * layout, stretched across two screens as a gray smear that reads as a broken
489
- * gradient rather than as a dead component. The only sound in the console was
490
- * `getShaderInfoLog` answering `null`, twice per element.
491
- *
492
- * A spent canvas is therefore replaced rather than re-asked. `restoreContext`
493
- * is the other way and is not reachable from here: it needs the `webglcontextlost`
494
- * event default-prevented and the extension held from before the loss, and it
495
- * restores asynchronously, so `start` would have to become a state machine to
496
- * use it. A fresh canvas is synchronous and cannot half-succeed.
497
- */
498
174
  build() {
499
175
  let canvas = this.renderRoot.querySelector('canvas');
500
176
  if (!canvas) {
501
177
  return false;
502
178
  }
503
- /* `antialias` off, because nothing here has a geometric edge to alias:
504
- every boundary is a gradient the shader computes. Multisampling would
505
- allocate a second screen-sized buffer to average pixels already smooth.
506
- `preserveDrawingBuffer` off too, which costs the ability to sample the
507
- canvas from a test and saves a full-screen copy on every frame. */
508
179
  let gl = canvas.getContext('webgl2', HelixAura_1.CONTEXT);
509
180
  if (gl?.isContextLost()) {
510
- /* Swapped under Lit, which is safe because the template is static: the
511
- strings never change, so no re-render ever touches this node again. */
512
181
  const fresh = document.createElement('canvas');
513
182
  fresh.setAttribute('part', 'canvas');
514
183
  fresh.setAttribute('aria-hidden', 'true');
515
184
  canvas.replaceWith(fresh);
516
185
  canvas = fresh;
517
- /* Cleared, so `measure` sizes the new buffer rather than comparing it
518
- against the spent one's dimensions and returning early. */
519
186
  this.width = 0;
520
187
  this.height = 0;
521
188
  gl = canvas.getContext('webgl2', HelixAura_1.CONTEXT);
@@ -555,9 +222,6 @@ let HelixAura = class HelixAura extends HelixElement {
555
222
  }
556
223
  connectedCallback() {
557
224
  super.connectedCallback();
558
- /* A move is a removal followed by an insertion, so the release scheduled a
559
- moment ago was never about this element going away. Canceled here, which
560
- is what makes a framework reorder cost no GL work at all. */
561
225
  if (this.release) {
562
226
  clearTimeout(this.release);
563
227
  this.release = 0;
@@ -567,9 +231,6 @@ let HelixAura = class HelixAura extends HelixElement {
567
231
  }
568
232
  }
569
233
  updated() {
570
- /* A property change has to reach the screen even when the loop is stopped,
571
- which is every reader who asked for no motion. The canvas holds its last
572
- frame and no re-render repaints it. */
573
234
  this.paintOnce();
574
235
  }
575
236
  disconnectedCallback() {
@@ -583,28 +244,8 @@ let HelixAura = class HelixAura extends HelixElement {
583
244
  window.removeEventListener('scroll', this.handleScroll, { capture: true });
584
245
  this.sized?.disconnect();
585
246
  this.sized = undefined;
586
- /* **Deferred by a task, and canceled by a reconnection.**
587
- *
588
- * The DOM has no signal for a move: a framework reordering its children
589
- * removes the node and inserts it again, and the element is told only that
590
- * it was disconnected. Releasing the context there punished every reorder
591
- * for a departure that never happened, and the landing page reorders three
592
- * auras on the way in. An insertion in the same task cancels this, so a
593
- * move is free and a real removal still pays a task later.
594
- *
595
- * A task rather than a microtask, because what has to fit inside the window
596
- * is a framework's whole commit rather than one call. */
597
247
  this.release = window.setTimeout(this.drop, 0);
598
248
  }
599
- /**
600
- * Resolves the ramp. Called when the palette moves, not when a frame draws.
601
- *
602
- * Light pages peak on a deep brand blue and dark ones on the foreground, and
603
- * the ground is what says which: mixing a saturated hue toward near-black
604
- * takes the chroma out of exactly the pixels carrying the most of it. Read
605
- * from the ground's own luminance rather than asked of the color mode, which
606
- * is a private token this tier may not reach for.
607
- */
608
249
  readPalette() {
609
250
  const ground = this.tokens.read('--helix-color-background', [0, 0, 0]);
610
251
  const light = ground[0] * 0.2126 + ground[1] * 0.7152 + ground[2] * 0.0722 > 0.5;
@@ -649,45 +290,13 @@ let HelixAura = class HelixAura extends HelixElement {
649
290
  gl.deleteShader(fs);
650
291
  return program;
651
292
  }
652
- /**
653
- * Re-reads the box and resizes the drawing buffer to match.
654
- *
655
- * **Called from the observer, never from the frame.** `clientWidth` is a
656
- * layout read, and doing it in `tick` meant a forced synchronous layout on
657
- * every single frame to learn a number that changes when the box changes and
658
- * at no other time. A `ResizeObserver` is told when that is.
659
- *
660
- * Returns whether the drawing buffer was resized, which is the same question
661
- * as whether it was cleared, and so whether the caller owes it a frame.
662
- */
663
293
  measure() {
664
- /* Read through `this` rather than destructured, which is not a style
665
- preference: `noUnusedPrivateClassMembers` does not count a destructured
666
- read, so a `const { canvas } = this` here is the field's only use and the
667
- rule offers to delete the field. `TokenColorController` carries the same
668
- false positive under a suppression; this one costs a word instead. */
669
294
  const canvas = this.canvas;
670
295
  const gl = this.gl;
671
296
  if (!canvas || !gl) {
672
297
  return false;
673
298
  }
674
299
  const rect = this.getBoundingClientRect();
675
- /* **An empty rect is layout that has not happened, not a box a pixel
676
- across.** These two were `Math.max(rect.width, 1)`, which never reports a
677
- bad measurement and instead manufactures a plausible one. Before first
678
- layout the rect is 0 by 0, so the clamp produced a 1 by 1 box, and every
679
- line below faithfully computed a drawing buffer for it: two pixels by
680
- two. The shader then painted four pixels and the compositor stretched
681
- them over the whole page.
682
-
683
- That is the settle. The field opened as one enormous soft blob, held it
684
- until a real box arrived, and snapped to its true feature size, which
685
- reads as the background scaling down. Instrumented on a reload it logged
686
- `boxH: 1, bufH: 2` at 216ms with `readyState: "complete"`.
687
-
688
- Declining is the whole fix. There is nothing worth drawing yet and the
689
- observer below is already waiting to say when there is; the host's own
690
- gradient covers the gap, which is what it is for. */
691
300
  if (rect.width < 1 || rect.height < 1) {
692
301
  return false;
693
302
  }
@@ -697,36 +306,7 @@ let HelixAura = class HelixAura extends HelixElement {
697
306
  top: rect.top,
698
307
  width: rect.width,
699
308
  };
700
- /* Capped at two, and a little under native beneath that. Every pixel runs
701
- five octaves of noise through two warps, and a 6K display at its full
702
- ratio is four times the work for a gradient nobody can resolve. Not as
703
- far under as it was: a parallax shift resolves on the buffer's own grid,
704
- so an aggressive scale makes the field step as it slides. */
705
309
  let dpr = Math.min(window.devicePixelRatio || 1, 2) * 0.85;
706
- /* **Then capped again against the box, because a ratio is not a budget.**
707
- The number above answers "how fine per CSS pixel" and says nothing about
708
- how many there are, which is fine while a field is a screen or two and
709
- stops being fine the moment one is asked to light a whole page. Measured
710
- on the landing page at 1280 by 6330: 2176 by 10761, or 23.4 million
711
- pixels of five-octave noise every frame, against the 5.3 million the same
712
- component costs over two screens.
713
-
714
- Two separate ceilings, because they fail differently.
715
-
716
- An edge past `MAX_RENDERBUFFER_SIZE` does not render slowly, it does not
717
- render. WebGL2 guarantees only 2048, and while desktops report 16384 the
718
- 8192 that older integrated parts report is under that same 10761: the
719
- aura would have been missing outright rather than expensive, and only on
720
- the machines least able to say so. 4096 clears the guarantee twice over
721
- and is far more than a field with no edge in it can show.
722
-
723
- The pixel budget is the fill rate, and 2048 squared is close to what the
724
- component already cost at the size it was designed for, so a page-length
725
- field now costs about what a hero-sized one did rather than four of them.
726
-
727
- Both are applied to `dpr` rather than to the dimensions, so width and
728
- height come down together. The shader corrects for aspect off
729
- `uResolution`, and scaling one axis alone would stretch the shape. */
730
310
  const edge = Math.max(this.box.width, this.box.height) * dpr;
731
311
  if (edge > MAX_CANVAS_EDGE) {
732
312
  dpr *= MAX_CANVAS_EDGE / edge;
@@ -750,11 +330,6 @@ let HelixAura = class HelixAura extends HelixElement {
750
330
  }
751
331
  paint() {
752
332
  const { gl, uniforms } = this;
753
- /* `width` is zero until a measurement succeeded, and a paint before that is
754
- a paint into the degenerate buffer described on `measure`. Guarded here
755
- rather than at each caller because `play` is started from the
756
- intersection observer and from `visibilitychange` as well as from setup,
757
- and one of those running early is the whole fault. */
758
333
  if (!gl || !this.program || !this.width) {
759
334
  return;
760
335
  }
@@ -765,17 +340,11 @@ let HelixAura = class HelixAura extends HelixElement {
765
340
  gl.uniform3fv(uniforms.uPeak ?? null, peak);
766
341
  gl.uniform1f(uniforms.uTime ?? null, this.elapsed);
767
342
  gl.uniform1i(uniforms.uShape ?? null, SHAPES.indexOf(this.variant ?? 'braid'));
768
- /* Each axis wanders on its own period. The seeds are deliberately not
769
- simple ratios of each other: two axes on periods that divide would come
770
- back into phase and give the whole field a beat. */
771
343
  gl.uniform1f(uniforms.uTilt ?? null, this.drifted(this.bearing, 14, 0.037));
772
344
  gl.uniform1f(uniforms.uScale ?? null, this.drifted(this.scale, 0.32, 0.061));
773
345
  gl.uniform1f(uniforms.uBloom ?? null, this.drifted(this.bloom, 0.22, 0.029));
774
346
  gl.uniform1f(uniforms.uGain ?? null, this.drifted(this.gain, 0.3, 0.053));
775
347
  gl.uniform1f(uniforms.uVariance ?? null, this.variance);
776
- /* Unrolled oldest first, with the live head appended last. `trailNext` is
777
- the next slot to be written and so the oldest again, now that the head no
778
- longer lives in the ring. */
779
348
  for (let i = 0; i < 8; i++) {
780
349
  const from = ((this.trailNext + i) % 8) * 3;
781
350
  const to = i * 3;
@@ -792,13 +361,6 @@ let HelixAura = class HelixAura extends HelixElement {
792
361
  gl.uniform1i(uniforms.uInteraction ?? null, Math.max(0, INTERACTIONS.indexOf(this.interaction ?? 'native')));
793
362
  gl.drawArrays(gl.TRIANGLES, 0, 3);
794
363
  }
795
- /**
796
- * The opening frame, one animation frame after the box last changed.
797
- *
798
- * Each new measurement cancels the pending frame and books another, so a run
799
- * of resizes collapses to a single paint at the end of it rather than one per
800
- * step. `openBy` stops that from being unbounded.
801
- */
802
364
  open() {
803
365
  if (this.opening) {
804
366
  cancelAnimationFrame(this.opening);
@@ -819,37 +381,12 @@ let HelixAura = class HelixAura extends HelixElement {
819
381
  }
820
382
  this.opening = requestAnimationFrame(draw);
821
383
  }
822
- /** One frame, now, for a change that has to show while the loop is stopped. */
823
384
  paintOnce() {
824
385
  if (this.frame) {
825
386
  return;
826
387
  }
827
388
  this.paint();
828
389
  }
829
- /**
830
- * The shortest gap between two painted frames, for a field nobody points at.
831
- *
832
- * **A drifting field does not need the display's rate and a pointer does.**
833
- * `tick` advances on `(now - this.last) / 1000`, so motion is wall-clock: at
834
- * half the frames the field moves the same distance in the same time, sampled
835
- * more coarsely. `delta` is already clamped at 0.05, which is a floor of 20
836
- * frames a second, and 30 sits inside that with room. A cap at 15 would land
837
- * on the clamp and the field would genuinely drag, which is the failure that
838
- * would be misdiagnosed as choppiness.
839
- *
840
- * **`interactive` is the exception and it is the whole exception.** The
841
- * element eases `presence` toward the pointer on a 50ms rise constant, so at
842
- * 33ms a frame the entire response is one or two samples and the follow reads
843
- * as a lag rather than a lightness. Every field on the landing page leaves
844
- * `interactive` unset; the only one that sets it is the lab on
845
- * `/helix/aura`, where it is a toggle a reader chose. So the cap applies where
846
- * nothing is being followed and lifts where something is.
847
- *
848
- * **The cost scales with the count.** Three fields run on the landing page,
849
- * one per transparent run, and with the frame limiter off they drew 2,654
850
- * times in three seconds against 1,276 for one: each instance draws once per
851
- * callback. Capping the two that nobody points at is most of that back.
852
- */
853
390
  static { this.CAPPED = 1000 / 30; }
854
391
  play() {
855
392
  if (this.frame ||
@@ -867,21 +404,8 @@ let HelixAura = class HelixAura extends HelixElement {
867
404
  cancelAnimationFrame(this.frame);
868
405
  this.frame = 0;
869
406
  }
870
- /* `last` alone is cleared, so the next frame measures no delta against a
871
- stale stamp. `elapsed` is deliberately kept. */
872
407
  this.last = 0;
873
408
  }
874
- /**
875
- * The angle actually drawn, which is `terminus` resolved against the box.
876
- *
877
- * A getter rather than a stored value because the box changes and this has no
878
- * business knowing when: it is read once per frame from numbers already
879
- * there.
880
- *
881
- * The solve is `tiltFor` in `aura-axis.ts` rather than an expression here, so
882
- * it is callable and `aura-root.dom.spec.ts` runs it against a model of the
883
- * shader in both directions.
884
- */
885
409
  get bearing() {
886
410
  if (this.terminus === undefined) {
887
411
  return this.tilt;
@@ -889,13 +413,6 @@ let HelixAura = class HelixAura extends HelixElement {
889
413
  const { height, width } = this.box;
890
414
  return tiltFor(this.terminus, width / Math.max(height, 1));
891
415
  }
892
- /*
893
- * One axis, wandering around its set value.
894
- *
895
- * Two sines at an irrational ratio rather than one, so a single axis has no
896
- * period of its own either. Bounded by construction: the weights sum to one,
897
- * so the value never leaves `base` plus or minus `span`.
898
- */
899
416
  drifted(base, span, seed) {
900
417
  if (!this.drift) {
901
418
  return base;
@@ -904,36 +421,12 @@ let HelixAura = class HelixAura extends HelixElement {
904
421
  const wave = Math.sin(t * seed) * 0.6 + Math.sin(t * seed * 1.618 + 2.1) * 0.4;
905
422
  return base + span * this.drift * wave;
906
423
  }
907
- /** Ages the wake, and drops a fresh mark where the pointer has moved far. */
908
424
  age(delta) {
909
- /* Two seconds to fade. Long enough that a wake outlives the gesture that
910
- made it, which is the whole effect, and short enough that a page left
911
- alone settles rather than keeping a drawing nobody made. */
912
425
  for (let i = 2; i < this.trail.length; i += 3) {
913
426
  const next = (this.trail[i] ?? 1) + delta / 2;
914
427
  this.trail[i] = next > 1 ? 1 : next;
915
428
  }
916
429
  }
917
- /**
918
- * Keeps the head of the wake on the cursor, and commits it as it travels.
919
- *
920
- * **The head is provisional, never a committed mark**, and holding it in the
921
- * ring is two faults at once. Marks are spaced by distance so eight slots
922
- * cover a gesture rather than the last few milliseconds of one, but if
923
- * committing is also the only time the stroke grows, its leading end sits up
924
- * to a full gate behind the pointer and catches up in jumps of exactly that
925
- * size. Latent, and jagged, for one reason.
926
- *
927
- * So the slot at `trailNext` is rewritten every frame to wherever the field
928
- * has actually eased to, which is where the cursor looks like it is, so the
929
- * stroke always reaches the pointer. Crossing the gate does not move the head,
930
- * it just stops the previous position from being overwritten, and a new
931
- * provisional head starts from there. The wake grows continuously and is still
932
- * only ever eight points.
933
- *
934
- * Measured against `eased` rather than `target`, or the stroke would reach a
935
- * place the field has not arrived at yet and lead its own parallax.
936
- */
937
430
  advanceWake() {
938
431
  if (!this.interactive) {
939
432
  return;
@@ -951,19 +444,6 @@ let HelixAura = class HelixAura extends HelixElement {
951
444
  this.trail[at + 1] = this.head.y;
952
445
  this.trail[at + 2] = 0;
953
446
  this.trailNext = (this.trailNext + 1) % 8;
954
- /* Every other mark ages a slot's worth on each commit, on top of aging
955
- with time.
956
-
957
- Time alone is not enough, because what has to be spent by the moment the
958
- ring reuses a slot is a function of *distance traveled*, not of seconds:
959
- marks commit every gate length, so a brisk gesture laps the ring long
960
- before a two second fade has taken the oldest down, and overwriting a
961
- mark that is still bright is a pop at the tail.
962
-
963
- A seventh, not an eighth. A mark is written at nought and is skipped on
964
- its own commit, so it collects exactly seven increments before its slot
965
- comes round again. Measured at an eighth, every overwritten slot stood at
966
- 0.875: faint, and not gone, and a faint point vanishing is still a pop. */
967
447
  for (let i = 2; i < this.trail.length; i += 3) {
968
448
  if (i === at + 2) {
969
449
  continue;