@hjmds/design-contracts 1.6.0 → 1.8.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 (228) hide show
  1. package/THIRD_PARTY_NOTICES.md +58 -0
  2. package/dist/agreement.d.ts +3 -3
  3. package/dist/agreement.js +1 -1
  4. package/dist/agreement.js.map +1 -1
  5. package/dist/asset.d.ts +1 -1
  6. package/dist/asset.js +1 -1
  7. package/dist/asset.js.map +1 -1
  8. package/dist/base-recipes.d.ts +12 -12
  9. package/dist/base-recipes.d.ts.map +1 -1
  10. package/dist/base-recipes.js +15 -14
  11. package/dist/base-recipes.js.map +1 -1
  12. package/dist/behaviors.d.ts +1 -1
  13. package/dist/catalog.d.ts +417 -561
  14. package/dist/catalog.d.ts.map +1 -1
  15. package/dist/catalog.js +138 -90
  16. package/dist/catalog.js.map +1 -1
  17. package/dist/command-palette.d.ts +3 -3
  18. package/dist/component-contracts.d.ts +4 -4
  19. package/dist/component-contracts.d.ts.map +1 -1
  20. package/dist/component-contracts.js +5 -4
  21. package/dist/component-contracts.js.map +1 -1
  22. package/dist/component-definitions.d.ts +1 -4
  23. package/dist/component-definitions.d.ts.map +1 -1
  24. package/dist/component-definitions.js +1 -4
  25. package/dist/component-definitions.js.map +1 -1
  26. package/dist/component-recipes.d.ts +76 -83
  27. package/dist/component-recipes.d.ts.map +1 -1
  28. package/dist/component-recipes.js +29 -49
  29. package/dist/component-recipes.js.map +1 -1
  30. package/dist/component-references.d.ts +0 -15
  31. package/dist/component-references.d.ts.map +1 -1
  32. package/dist/component-references.js +0 -3
  33. package/dist/component-references.js.map +1 -1
  34. package/dist/data-table.d.ts +3 -3
  35. package/dist/data-table.js +1 -1
  36. package/dist/data-table.js.map +1 -1
  37. package/dist/date-picker.d.ts +2 -2
  38. package/dist/icon-button-recipe.d.ts +2 -2
  39. package/dist/icon-button-recipe.js +1 -1
  40. package/dist/icon-button-recipe.js.map +1 -1
  41. package/dist/image.d.ts +2 -2
  42. package/dist/image.js +2 -2
  43. package/dist/image.js.map +1 -1
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/internal/thinking-orb/braid.d.ts +3 -0
  49. package/dist/internal/thinking-orb/braid.d.ts.map +1 -0
  50. package/dist/internal/thinking-orb/braid.js +47 -0
  51. package/dist/internal/thinking-orb/braid.js.map +1 -0
  52. package/dist/internal/thinking-orb/core.d.ts +60 -0
  53. package/dist/internal/thinking-orb/core.d.ts.map +1 -0
  54. package/dist/internal/thinking-orb/core.js +86 -0
  55. package/dist/internal/thinking-orb/core.js.map +1 -0
  56. package/dist/internal/thinking-orb/lattice.d.ts +5 -0
  57. package/dist/internal/thinking-orb/lattice.d.ts.map +1 -0
  58. package/dist/internal/thinking-orb/lattice.js +187 -0
  59. package/dist/internal/thinking-orb/lattice.js.map +1 -0
  60. package/dist/internal/thinking-orb/morph.d.ts +3 -0
  61. package/dist/internal/thinking-orb/morph.d.ts.map +1 -0
  62. package/dist/internal/thinking-orb/morph.js +127 -0
  63. package/dist/internal/thinking-orb/morph.js.map +1 -0
  64. package/dist/internal/thinking-orb/orbits.d.ts +3 -0
  65. package/dist/internal/thinking-orb/orbits.d.ts.map +1 -0
  66. package/dist/internal/thinking-orb/orbits.js +68 -0
  67. package/dist/internal/thinking-orb/orbits.js.map +1 -0
  68. package/dist/internal/thinking-orb/presets.d.ts +21 -0
  69. package/dist/internal/thinking-orb/presets.d.ts.map +1 -0
  70. package/dist/internal/thinking-orb/presets.js +77 -0
  71. package/dist/internal/thinking-orb/presets.js.map +1 -0
  72. package/dist/internal/thinking-orb/profiles.d.ts +8 -0
  73. package/dist/internal/thinking-orb/profiles.d.ts.map +1 -0
  74. package/dist/internal/thinking-orb/profiles.js +158 -0
  75. package/dist/internal/thinking-orb/profiles.js.map +1 -0
  76. package/dist/internal/thinking-orb/registry.d.ts +9 -0
  77. package/dist/internal/thinking-orb/registry.d.ts.map +1 -0
  78. package/dist/internal/thinking-orb/registry.js +27 -0
  79. package/dist/internal/thinking-orb/registry.js.map +1 -0
  80. package/dist/internal/thinking-orb/ribbon.d.ts +3 -0
  81. package/dist/internal/thinking-orb/ribbon.d.ts.map +1 -0
  82. package/dist/internal/thinking-orb/ribbon.js +87 -0
  83. package/dist/internal/thinking-orb/ribbon.js.map +1 -0
  84. package/dist/internal/thinking-orb/types.d.ts +15 -0
  85. package/dist/internal/thinking-orb/types.d.ts.map +1 -0
  86. package/dist/internal/thinking-orb/types.js +4 -0
  87. package/dist/internal/thinking-orb/types.js.map +1 -0
  88. package/dist/internal/thinking-orb/web.d.ts +3 -0
  89. package/dist/internal/thinking-orb/web.d.ts.map +1 -0
  90. package/dist/internal/thinking-orb/web.js +92 -0
  91. package/dist/internal/thinking-orb/web.js.map +1 -0
  92. package/dist/masonry.d.ts +17 -0
  93. package/dist/masonry.d.ts.map +1 -0
  94. package/dist/masonry.js +18 -0
  95. package/dist/masonry.js.map +1 -0
  96. package/dist/menubar.d.ts +3 -3
  97. package/dist/menubar.js +1 -1
  98. package/dist/menubar.js.map +1 -1
  99. package/dist/number-field.d.ts +2 -2
  100. package/dist/otp-field.d.ts +1 -1
  101. package/dist/password-field.d.ts +2 -2
  102. package/dist/popover.d.ts +7 -8
  103. package/dist/popover.d.ts.map +1 -1
  104. package/dist/popover.js +2 -0
  105. package/dist/popover.js.map +1 -1
  106. package/dist/qr-code-recipe.d.ts +7 -0
  107. package/dist/qr-code-recipe.d.ts.map +1 -0
  108. package/dist/qr-code-recipe.js +2 -0
  109. package/dist/qr-code-recipe.js.map +1 -0
  110. package/dist/qr-code.d.ts +16 -0
  111. package/dist/qr-code.d.ts.map +1 -0
  112. package/dist/qr-code.js +37 -0
  113. package/dist/qr-code.js.map +1 -0
  114. package/dist/semantic-colors.d.ts +1 -1
  115. package/dist/semantic-colors.js +1 -1
  116. package/dist/semantic-colors.js.map +1 -1
  117. package/dist/showcase.d.ts +5 -1
  118. package/dist/showcase.d.ts.map +1 -1
  119. package/dist/showcase.js +51 -13
  120. package/dist/showcase.js.map +1 -1
  121. package/dist/sidebar.d.ts +3 -3
  122. package/dist/sidebar.js +1 -1
  123. package/dist/sidebar.js.map +1 -1
  124. package/dist/tag.d.ts +4 -4
  125. package/dist/tag.js +3 -3
  126. package/dist/tag.js.map +1 -1
  127. package/dist/tags-input.d.ts +3 -3
  128. package/dist/tags-input.js +1 -1
  129. package/dist/tags-input.js.map +1 -1
  130. package/dist/text-formats.d.ts +2 -2
  131. package/dist/text-formats.js +2 -2
  132. package/dist/text-formats.js.map +1 -1
  133. package/dist/thinking-orb-recipe.d.ts +15 -0
  134. package/dist/thinking-orb-recipe.d.ts.map +1 -0
  135. package/dist/thinking-orb-recipe.js +9 -0
  136. package/dist/thinking-orb-recipe.js.map +1 -0
  137. package/dist/thinking-orb.d.ts +25 -0
  138. package/dist/thinking-orb.d.ts.map +1 -0
  139. package/dist/thinking-orb.js +40 -0
  140. package/dist/thinking-orb.js.map +1 -0
  141. package/dist/toast-liquid.d.ts +116 -0
  142. package/dist/toast-liquid.d.ts.map +1 -0
  143. package/dist/toast-liquid.js +100 -0
  144. package/dist/toast-liquid.js.map +1 -0
  145. package/dist/toast.d.ts +7 -1
  146. package/dist/toast.d.ts.map +1 -1
  147. package/dist/toast.js +5 -0
  148. package/dist/toast.js.map +1 -1
  149. package/dist/toggle-group.d.ts +2 -2
  150. package/dist/toggle-group.js +3 -3
  151. package/dist/toggle-group.js.map +1 -1
  152. package/dist/transfer-list.d.ts +3 -3
  153. package/dist/transfer-list.js +1 -1
  154. package/dist/transfer-list.js.map +1 -1
  155. package/dist/tree.d.ts +2 -2
  156. package/dist/version.d.ts +1 -1
  157. package/dist/version.js +1 -1
  158. package/dist/version.js.map +1 -1
  159. package/dist/virtual-list.d.ts +13 -0
  160. package/dist/virtual-list.d.ts.map +1 -0
  161. package/dist/virtual-list.js +13 -0
  162. package/dist/virtual-list.js.map +1 -0
  163. package/docs/anchor.md +5 -4
  164. package/docs/ant-design-coverage.md +2 -2
  165. package/docs/architecture.md +6 -2
  166. package/docs/authoring-brief.md +3 -2
  167. package/docs/bottom-navigation.md +7 -6
  168. package/docs/breadcrumb.md +5 -2
  169. package/docs/calendar.md +6 -3
  170. package/docs/carousel.md +2 -2
  171. package/docs/cascader.md +6 -0
  172. package/docs/catalog-cleanup.md +7 -0
  173. package/docs/catalog-decision-status.md +3 -3
  174. package/docs/catalog-freeze.json +9 -7
  175. package/docs/collapsible.md +12 -0
  176. package/docs/command-palette.md +5 -3
  177. package/docs/consumer-policy.md +29 -12
  178. package/docs/context-menu.md +12 -2
  179. package/docs/data-table.md +11 -6
  180. package/docs/date-picker.md +6 -4
  181. package/docs/date-range.md +4 -2
  182. package/docs/description-list.md +8 -9
  183. package/docs/dialog.md +39 -0
  184. package/docs/expansion-roadmap.md +11 -7
  185. package/docs/file-picker.md +5 -3
  186. package/docs/form.md +16 -4
  187. package/docs/generated/component-maturity.md +88 -91
  188. package/docs/generated/renderer-evidence.json +1848 -1023
  189. package/docs/generated/renderer-evidence.md +153 -145
  190. package/docs/generated/showcase-manifest.json +431 -497
  191. package/docs/layout.md +8 -9
  192. package/docs/library-gap-analysis.md +1 -1
  193. package/docs/masonry.md +11 -0
  194. package/docs/mentions.md +14 -7
  195. package/docs/optional-adapters.md +106 -0
  196. package/docs/otp-field.md +2 -1
  197. package/docs/pagination.md +4 -1
  198. package/docs/password-field.md +2 -1
  199. package/docs/popover.md +9 -6
  200. package/docs/promotion-candidates.md +2 -1
  201. package/docs/qr-code.md +11 -65
  202. package/docs/react-native-completion.md +1 -1
  203. package/docs/result.md +8 -5
  204. package/docs/screen-chrome.md +2 -1
  205. package/docs/sheet.md +16 -3
  206. package/docs/showcase.md +10 -2
  207. package/docs/side-panel.md +12 -6
  208. package/docs/sidebar.md +3 -0
  209. package/docs/splitter.md +6 -6
  210. package/docs/stable-core.md +72 -0
  211. package/docs/stable-promotion.md +47 -43
  212. package/docs/tags-input.md +5 -2
  213. package/docs/theme-palette.md +27 -0
  214. package/docs/thinking-orb.md +124 -0
  215. package/docs/timeline.md +2 -3
  216. package/docs/toast.md +6 -0
  217. package/docs/tooltip.md +2 -1
  218. package/docs/tour.md +14 -8
  219. package/docs/transfer-list.md +24 -21
  220. package/docs/tree-select.md +2 -1
  221. package/docs/tree.md +12 -7
  222. package/docs/upload-item.md +7 -3
  223. package/docs/virtual-list.md +10 -67
  224. package/package.json +30 -3
  225. package/docs/app-provider.md +0 -50
  226. package/docs/border-beam.md +0 -66
  227. package/docs/chart.md +0 -33
  228. package/docs/utility.md +0 -53
@@ -0,0 +1 @@
1
+ {"version":3,"file":"braid.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/braid.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjD,eAAO,MAAM,UAAU,EAAE,SA0CxB,CAAC"}
@@ -0,0 +1,47 @@
1
+ // Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.
2
+ // Braid: three strands plait around the sphere — the "weaving" state.
3
+ // Each strand runs pole to pole on a helix, and a radial breathing term
4
+ // makes them trade places, reading as the over/under of a plait.
5
+ import { fibDir, finalizeFrame, frac, makeProj, radiusScale } from './core.js';
6
+ export const frameBraid = (size, t, o) => {
7
+ const cx = size / 2;
8
+ const cy = size / 2;
9
+ const R = (size / 2) * 0.76;
10
+ const pt = makeProj(t * 0.4, 0.3, cx, cy, 1);
11
+ const rs = radiusScale(size, o.rsPow ?? 0.6);
12
+ const dots = [];
13
+ const ghostN = o.ghostN ?? 150;
14
+ for (let i = 0; i < ghostN; i++) {
15
+ const d = fibDir(i, ghostN);
16
+ const [px, py, z] = pt(d[0] * R, d[1] * R, d[2] * R);
17
+ const depth = (z / R + 1) / 2;
18
+ dots.push({ x: px, y: py, z, r: 0.8 * rs, white: 0.78, a: 0.1 + 0.22 * depth });
19
+ }
20
+ const strandN = o.strandN ?? 52;
21
+ const turns = o.turns ?? 3;
22
+ for (let s = 0; s < 3; s++) {
23
+ const phase = (s / 3) * 2 * Math.PI;
24
+ for (let i = 0; i < strandN; i++) {
25
+ // u walks pole to pole; the frac() drift slides the whole strand along
26
+ const u = (frac(i / strandN + t * 0.045) * 2 - 1) * 0.96;
27
+ const surf = Math.sqrt(Math.max(0, 1 - u * u));
28
+ const endFade = Math.min(1, (1 - Math.abs(u)) / 0.1);
29
+ const a = u * Math.PI * turns + phase;
30
+ // radial breathing: strands trade places — the over/under of a plait
31
+ const weave = 1 + 0.075 * Math.sin(u * Math.PI * turns * 2 + phase * 2 + t * 0.8);
32
+ const rr = surf * R * weave;
33
+ const [px, py, zr] = pt(Math.cos(a) * rr, u * R * weave, Math.sin(a) * rr);
34
+ const depth = (zr / R + 1) / 2;
35
+ dots.push({
36
+ x: px,
37
+ y: py,
38
+ z: zr,
39
+ r: ((o.rBase ?? 1.2) + (o.rDepth ?? 1.8) * depth) * rs,
40
+ white: 0.55 - 0.45 * depth,
41
+ a: endFade * (0.45 + 0.55 * depth)
42
+ });
43
+ }
44
+ }
45
+ return finalizeFrame(dots, [], o.rMin);
46
+ };
47
+ //# sourceMappingURL=braid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"braid.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/braid.ts"],"names":[],"mappings":"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","sourcesContent":["// Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.\n// Braid: three strands plait around the sphere — the \"weaving\" state.\n// Each strand runs pole to pole on a helix, and a radial breathing term\n// makes them trade places, reading as the over/under of a plait.\n\nimport type { Dot, ModeFrame } from './types.js';\nimport { fibDir, finalizeFrame, frac, makeProj, radiusScale } from './core.js';\n\nexport const frameBraid: ModeFrame = (size, t, o) => {\n const cx = size / 2;\n const cy = size / 2;\n const R = (size / 2) * 0.76;\n const pt = makeProj(t * 0.4, 0.3, cx, cy, 1);\n const rs = radiusScale(size, o.rsPow ?? 0.6);\n\n const dots: Dot[] = [];\n const ghostN = o.ghostN ?? 150;\n for (let i = 0; i < ghostN; i++) {\n const d = fibDir(i, ghostN);\n const [px, py, z] = pt(d[0] * R, d[1] * R, d[2] * R);\n const depth = (z / R + 1) / 2;\n dots.push({ x: px, y: py, z, r: 0.8 * rs, white: 0.78, a: 0.1 + 0.22 * depth });\n }\n\n const strandN = o.strandN ?? 52;\n const turns = o.turns ?? 3;\n for (let s = 0; s < 3; s++) {\n const phase = (s / 3) * 2 * Math.PI;\n for (let i = 0; i < strandN; i++) {\n // u walks pole to pole; the frac() drift slides the whole strand along\n const u = (frac(i / strandN + t * 0.045) * 2 - 1) * 0.96;\n const surf = Math.sqrt(Math.max(0, 1 - u * u));\n const endFade = Math.min(1, (1 - Math.abs(u)) / 0.1);\n const a = u * Math.PI * turns + phase;\n // radial breathing: strands trade places — the over/under of a plait\n const weave = 1 + 0.075 * Math.sin(u * Math.PI * turns * 2 + phase * 2 + t * 0.8);\n const rr = surf * R * weave;\n const [px, py, zr] = pt(Math.cos(a) * rr, u * R * weave, Math.sin(a) * rr);\n const depth = (zr / R + 1) / 2;\n dots.push({\n x: px,\n y: py,\n z: zr,\n r: ((o.rBase ?? 1.2) + (o.rDepth ?? 1.8) * depth) * rs,\n white: 0.55 - 0.45 * depth,\n a: endFade * (0.45 + 0.55 * depth)\n });\n }\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n"]}
@@ -0,0 +1,60 @@
1
+ export interface Dot {
2
+ x: number;
3
+ y: number;
4
+ z: number;
5
+ r: number;
6
+ /** Ink value: 0 = darkest ink on paper. Mirrored on dark themes. */
7
+ white: number;
8
+ a?: number;
9
+ }
10
+ /** A stroked edge between two projected points (the `connecting` web). */
11
+ export interface Line {
12
+ x1: number;
13
+ y1: number;
14
+ x2: number;
15
+ y2: number;
16
+ /** Ink value, same convention as `Dot.white`. */
17
+ white: number;
18
+ a?: number;
19
+ w: number;
20
+ }
21
+ /**
22
+ * One rendered instant: a complete, final set of draw instructions.
23
+ * `dots` is already z-sorted into draw order and radius-clamped; `lines`
24
+ * are drawn first. Nothing here needs further interpretation, which is what
25
+ * makes a frame portable to any 2D renderer.
26
+ */
27
+ export interface OrbFrame {
28
+ dots: Dot[];
29
+ lines: Line[];
30
+ }
31
+ export type Projector = (x: number, y: number, z: number) => [number, number, number];
32
+ export declare function lerp(a: number, b: number, f: number): number;
33
+ export declare function frac(x: number): number;
34
+ /** Value noise on a 2D lattice — smooth, deterministic, cheap. */
35
+ export declare function vnoise(x: number, y: number): number;
36
+ /** Deterministic hash in [0, 1). */
37
+ export declare function hashD(a: number, b: number): number;
38
+ /** Stable directions on a unit sphere (Fibonacci lattice). */
39
+ export declare function fibDir(i: number, n: number): [number, number, number];
40
+ /** Shortest signed angular distance, wrapped to (-π, π]. */
41
+ export declare function angleDelta(a: number, b: number): number;
42
+ /** Shared spin + tilt + orthographic projection. */
43
+ export declare function makeProj(yaw: number, tilt: number, cx: number, cy: number, scale: number): Projector;
44
+ /**
45
+ * Turn raw mode output into a finished frame: drop invisible marks, clamp
46
+ * radii to the mode's floor, and z-sort far→near into draw order.
47
+ *
48
+ * This runs in the GEOMETRY step, not the painter, so a frame is a complete
49
+ * set of draw instructions: every value is final and the array order is the
50
+ * order to draw in. That is what lets the RN and SwiftUI ports share this
51
+ * output verbatim — a port draws the list, it never re-derives anything —
52
+ * and what lets the golden-vector tests compare numbers instead of pixels.
53
+ */
54
+ export declare function finalizeFrame(dots: Dot[], lines: Line[], rMin?: number): OrbFrame;
55
+ /**
56
+ * Dot radii were tuned for a 300pt frame; sub-linear scaling keeps small
57
+ * spinners legible. Lower pow = radii shrink less with size.
58
+ */
59
+ export declare function radiusScale(size: number, pow: number): number;
60
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/core.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,0EAA0E;AAC1E,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtF,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAED,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAYnD;AAED,oCAAoC;AACpC,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED,8DAA8D;AAC9D,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAMrE;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,oDAAoD;AACpD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAYpG;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,SAAM,GAAG,QAAQ,CAS9E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,86 @@
1
+ // Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.
2
+ // Shared primitives for the dotted 3D thought-orbs. Ported from inkform
3
+ // (PlotterLab's HalftoneSphere lineage): honestly 3D — rotated,
4
+ // depth-shaded, z-sorted. Depth is carried by dot size and ink weight
5
+ // alone. Plain 2D canvas fills only: no ctx.filter, no SVG filters, so
6
+ // every mode renders identically in Chrome, Safari and Firefox.
7
+ export function lerp(a, b, f) {
8
+ return a + (b - a) * f;
9
+ }
10
+ export function frac(x) {
11
+ return x - Math.floor(x);
12
+ }
13
+ /** Value noise on a 2D lattice — smooth, deterministic, cheap. */
14
+ export function vnoise(x, y) {
15
+ const xi = Math.floor(x);
16
+ const yi = Math.floor(y);
17
+ let fx = x - xi;
18
+ let fy = y - yi;
19
+ fx = fx * fx * (3 - 2 * fx);
20
+ fy = fy * fy * (3 - 2 * fy);
21
+ const a = hashD(xi, yi);
22
+ const b = hashD(xi + 1, yi);
23
+ const c = hashD(xi, yi + 1);
24
+ const d = hashD(xi + 1, yi + 1);
25
+ return a + (b - a) * fx + (c - a) * fy + (a - b - c + d) * fx * fy;
26
+ }
27
+ /** Deterministic hash in [0, 1). */
28
+ export function hashD(a, b) {
29
+ const h = Math.sin(a * 12.9898 + b * 78.233) * 43758.5453;
30
+ return h - Math.floor(h);
31
+ }
32
+ /** Stable directions on a unit sphere (Fibonacci lattice). */
33
+ export function fibDir(i, n) {
34
+ const golden = Math.PI * (3 - Math.sqrt(5));
35
+ const y = 1 - (2 * (i + 0.5)) / n;
36
+ const rad = Math.sqrt(1 - y * y);
37
+ const a = i * golden;
38
+ return [rad * Math.cos(a), y, rad * Math.sin(a)];
39
+ }
40
+ /** Shortest signed angular distance, wrapped to (-π, π]. */
41
+ export function angleDelta(a, b) {
42
+ return Math.atan2(Math.sin(a - b), Math.cos(a - b));
43
+ }
44
+ /** Shared spin + tilt + orthographic projection. */
45
+ export function makeProj(yaw, tilt, cx, cy, scale) {
46
+ const st = Math.sin(tilt);
47
+ const ct = Math.cos(tilt);
48
+ const sy = Math.sin(yaw);
49
+ const cyw = Math.cos(yaw);
50
+ return (x, y, z) => {
51
+ const x1 = x * cyw + z * sy;
52
+ const z1 = -x * sy + z * cyw;
53
+ const y1 = y * ct - z1 * st;
54
+ const z2 = y * st + z1 * ct;
55
+ return [cx + x1 * scale, cy - y1 * scale, z2];
56
+ };
57
+ }
58
+ /**
59
+ * Turn raw mode output into a finished frame: drop invisible marks, clamp
60
+ * radii to the mode's floor, and z-sort far→near into draw order.
61
+ *
62
+ * This runs in the GEOMETRY step, not the painter, so a frame is a complete
63
+ * set of draw instructions: every value is final and the array order is the
64
+ * order to draw in. That is what lets the RN and SwiftUI ports share this
65
+ * output verbatim — a port draws the list, it never re-derives anything —
66
+ * and what lets the golden-vector tests compare numbers instead of pixels.
67
+ */
68
+ export function finalizeFrame(dots, lines, rMin = 0.3) {
69
+ const visible = [];
70
+ for (const d of dots) {
71
+ if ((d.a ?? 1) < 0.02)
72
+ continue;
73
+ d.r = Math.max(rMin, d.r);
74
+ visible.push(d);
75
+ }
76
+ visible.sort((a, b) => a.z - b.z);
77
+ return { dots: visible, lines: lines.filter((l) => (l.a ?? 1) >= 0.02) };
78
+ }
79
+ /**
80
+ * Dot radii were tuned for a 300pt frame; sub-linear scaling keeps small
81
+ * spinners legible. Lower pow = radii shrink less with size.
82
+ */
83
+ export function radiusScale(size, pow) {
84
+ return (size / 300) ** pow;
85
+ }
86
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/core.ts"],"names":[],"mappings":"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","sourcesContent":["// Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.\n// Shared primitives for the dotted 3D thought-orbs. Ported from inkform\n// (PlotterLab's HalftoneSphere lineage): honestly 3D — rotated,\n// depth-shaded, z-sorted. Depth is carried by dot size and ink weight\n// alone. Plain 2D canvas fills only: no ctx.filter, no SVG filters, so\n// every mode renders identically in Chrome, Safari and Firefox.\n\nexport interface Dot {\n x: number;\n y: number;\n z: number;\n r: number;\n /** Ink value: 0 = darkest ink on paper. Mirrored on dark themes. */\n white: number;\n a?: number;\n}\n\n/** A stroked edge between two projected points (the `connecting` web). */\nexport interface Line {\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n /** Ink value, same convention as `Dot.white`. */\n white: number;\n a?: number;\n w: number;\n}\n\n/**\n * One rendered instant: a complete, final set of draw instructions.\n * `dots` is already z-sorted into draw order and radius-clamped; `lines`\n * are drawn first. Nothing here needs further interpretation, which is what\n * makes a frame portable to any 2D renderer.\n */\nexport interface OrbFrame {\n dots: Dot[];\n lines: Line[];\n}\n\nexport type Projector = (x: number, y: number, z: number) => [number, number, number];\n\nexport function lerp(a: number, b: number, f: number): number {\n return a + (b - a) * f;\n}\n\nexport function frac(x: number): number {\n return x - Math.floor(x);\n}\n\n/** Value noise on a 2D lattice — smooth, deterministic, cheap. */\nexport function vnoise(x: number, y: number): number {\n const xi = Math.floor(x);\n const yi = Math.floor(y);\n let fx = x - xi;\n let fy = y - yi;\n fx = fx * fx * (3 - 2 * fx);\n fy = fy * fy * (3 - 2 * fy);\n const a = hashD(xi, yi);\n const b = hashD(xi + 1, yi);\n const c = hashD(xi, yi + 1);\n const d = hashD(xi + 1, yi + 1);\n return a + (b - a) * fx + (c - a) * fy + (a - b - c + d) * fx * fy;\n}\n\n/** Deterministic hash in [0, 1). */\nexport function hashD(a: number, b: number): number {\n const h = Math.sin(a * 12.9898 + b * 78.233) * 43758.5453;\n return h - Math.floor(h);\n}\n\n/** Stable directions on a unit sphere (Fibonacci lattice). */\nexport function fibDir(i: number, n: number): [number, number, number] {\n const golden = Math.PI * (3 - Math.sqrt(5));\n const y = 1 - (2 * (i + 0.5)) / n;\n const rad = Math.sqrt(1 - y * y);\n const a = i * golden;\n return [rad * Math.cos(a), y, rad * Math.sin(a)];\n}\n\n/** Shortest signed angular distance, wrapped to (-π, π]. */\nexport function angleDelta(a: number, b: number): number {\n return Math.atan2(Math.sin(a - b), Math.cos(a - b));\n}\n\n/** Shared spin + tilt + orthographic projection. */\nexport function makeProj(yaw: number, tilt: number, cx: number, cy: number, scale: number): Projector {\n const st = Math.sin(tilt);\n const ct = Math.cos(tilt);\n const sy = Math.sin(yaw);\n const cyw = Math.cos(yaw);\n return (x, y, z) => {\n const x1 = x * cyw + z * sy;\n const z1 = -x * sy + z * cyw;\n const y1 = y * ct - z1 * st;\n const z2 = y * st + z1 * ct;\n return [cx + x1 * scale, cy - y1 * scale, z2];\n };\n}\n\n/**\n * Turn raw mode output into a finished frame: drop invisible marks, clamp\n * radii to the mode's floor, and z-sort far→near into draw order.\n *\n * This runs in the GEOMETRY step, not the painter, so a frame is a complete\n * set of draw instructions: every value is final and the array order is the\n * order to draw in. That is what lets the RN and SwiftUI ports share this\n * output verbatim — a port draws the list, it never re-derives anything —\n * and what lets the golden-vector tests compare numbers instead of pixels.\n */\nexport function finalizeFrame(dots: Dot[], lines: Line[], rMin = 0.3): OrbFrame {\n const visible: Dot[] = [];\n for (const d of dots) {\n if ((d.a ?? 1) < 0.02) continue;\n d.r = Math.max(rMin, d.r);\n visible.push(d);\n }\n visible.sort((a, b) => a.z - b.z);\n return { dots: visible, lines: lines.filter((l) => (l.a ?? 1) >= 0.02) };\n}\n\n/**\n * Dot radii were tuned for a 300pt frame; sub-linear scaling keeps small\n * spinners legible. Lower pow = radii shrink less with size.\n */\nexport function radiusScale(size: number, pow: number): number {\n return (size / 300) ** pow;\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import type { ModeFrame } from './types.js';
2
+ export declare const frameGlobe: ModeFrame;
3
+ export declare const frameRubik: ModeFrame;
4
+ export declare const frameWave: ModeFrame;
5
+ //# sourceMappingURL=lattice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lattice.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/lattice.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,YAAY,CAAC;AAoFjD,eAAO,MAAM,UAAU,EAAE,SAuCxB,CAAC;AAIF,eAAO,MAAM,UAAU,EAAE,SAkCxB,CAAC;AAIF,eAAO,MAAM,SAAS,EAAE,SAmCvB,CAAC"}
@@ -0,0 +1,187 @@
1
+ // Indexed reads are bounded by the populated array length or modulo; assertions preserve upstream geometry.
2
+ // Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.
3
+ // The sphere-lattice modes: globe (searching), rubik (solving) and
4
+ // wave (listening). All draw a lat/long dot field with mode-specific
5
+ // motion, then hand off to the shared z-sorted painter.
6
+ import { angleDelta, finalizeFrame, hashD, makeProj, radiusScale } from './core.js';
7
+ function solveCycle(time, count, slotDur, rest) {
8
+ const cyc = 2 * count * slotDur + rest;
9
+ const tc = time % cyc;
10
+ const amount = new Array(count).fill(0);
11
+ let active = -1;
12
+ if (tc < 2 * count * slotDur) {
13
+ const slot = Math.floor(tc / slotDur);
14
+ const p = (tc - slot * slotDur) / slotDur;
15
+ const cl = Math.min(1, p / 0.7);
16
+ const ep = 1 - (1 - cl) ** 3; // machine ease-out
17
+ if (slot < count) {
18
+ for (let i = 0; i < slot; i++)
19
+ amount[i] = 1;
20
+ amount[slot] = ep;
21
+ active = slot;
22
+ }
23
+ else {
24
+ const u = 2 * count - 1 - slot;
25
+ for (let i = 0; i < u; i++)
26
+ amount[i] = 1;
27
+ amount[u] = 1 - ep;
28
+ active = u;
29
+ }
30
+ }
31
+ return { amount, active };
32
+ }
33
+ function applyMoves(pt3, moves, sc) {
34
+ let [x, y, z] = pt3;
35
+ let inActive = false;
36
+ for (let i = 0; i < moves.length; i++) {
37
+ if (sc.amount[i] <= 0)
38
+ continue;
39
+ const mv = moves[i];
40
+ const coord = mv.axis === 0 ? x : mv.axis === 1 ? y : z;
41
+ if (coord < mv.lo || coord >= mv.hi)
42
+ continue;
43
+ if (i === sc.active)
44
+ inActive = true;
45
+ const a = mv.ang * sc.amount[i];
46
+ const ca = Math.cos(a);
47
+ const sa = Math.sin(a);
48
+ if (mv.axis === 0) {
49
+ const y2 = y * ca - z * sa;
50
+ z = y * sa + z * ca;
51
+ y = y2;
52
+ }
53
+ else if (mv.axis === 1) {
54
+ const x2 = x * ca + z * sa;
55
+ z = -x * sa + z * ca;
56
+ x = x2;
57
+ }
58
+ else {
59
+ const x2 = x * ca - y * sa;
60
+ y = x * sa + y * ca;
61
+ x = x2;
62
+ }
63
+ }
64
+ return [x, y, z, inActive];
65
+ }
66
+ function makeMoves(count) {
67
+ const moves = [];
68
+ for (let i = 0; i < count; i++) {
69
+ const axis = Math.min(2, Math.floor(hashD(i, 2.3) * 3));
70
+ const lo = -1.0 + 0.5 * Math.min(3, Math.floor(hashD(i, 5.9) * 4));
71
+ const dir = hashD(i, 7.7) < 0.5 ? 1 : -1;
72
+ moves.push({ axis, lo, hi: lo + 0.5, ang: (dir * Math.PI) / 2 });
73
+ }
74
+ return moves;
75
+ }
76
+ // --- Globe: lat/long field, a scan meridian sweeps — searching --------
77
+ export const frameGlobe = (size, t, o) => {
78
+ const spin = 0.5;
79
+ const cx = size / 2;
80
+ const cy = size / 2;
81
+ const radius = (size / 2) * 0.82;
82
+ const tilt = 0.4 + 0.06 * Math.sin(t * 0.35);
83
+ const pt = makeProj(t * spin, tilt, cx, cy, radius);
84
+ // scan sweeps relative to the spin; scanMul scales that relative rate
85
+ const scan = t * (spin + (1.7 - spin) * (o.scanMul ?? 1));
86
+ const rs = radiusScale(size, o.rsPow ?? 0.6);
87
+ const dimBase = o.dimBase ?? 1;
88
+ const dots = [];
89
+ const latRings = o.latRings ?? 17;
90
+ const lonDensity = o.lonDensity ?? 44;
91
+ for (let li = 0; li <= latRings; li++) {
92
+ const lat = -Math.PI / 2 + (li / latRings) * Math.PI;
93
+ const cosLat = Math.cos(lat);
94
+ const sinLat = Math.sin(lat);
95
+ const lonCount = Math.max(1, Math.round(Math.abs(cosLat) * lonDensity));
96
+ for (let lj = 0; lj < lonCount; lj++) {
97
+ const lon = (lj / lonCount) * 2 * Math.PI;
98
+ const [px, py, z] = pt(cosLat * Math.cos(lon), sinLat, cosLat * Math.sin(lon));
99
+ const depth = (z + 1) / 2;
100
+ // the scan: a moving meridian read as a size ripple, not a shine
101
+ const d = angleDelta(lon + t * spin, scan);
102
+ const boost = Math.exp(-(d * d) / 0.18) * Math.max(0, z);
103
+ dots.push({
104
+ x: px,
105
+ y: py,
106
+ z,
107
+ r: ((o.rBase ?? 0.6) + (o.rDepth ?? 1.7) * depth + (o.rBoost ?? 1) * boost) * rs,
108
+ white: (o.inkFar ?? 0.62) - (o.inkSpan ?? 0.54) * depth,
109
+ // dimBase < 1 fades un-scanned dots so the meridian reads clearly
110
+ a: dimBase + (1 - dimBase) * Math.min(1, boost)
111
+ });
112
+ }
113
+ }
114
+ return finalizeFrame(dots, [], o.rMin);
115
+ };
116
+ // --- Rubik: bands twist in quarter turns, scramble → solve — solving --
117
+ export const frameRubik = (size, t, o) => {
118
+ const cx = size / 2;
119
+ const cy = size / 2;
120
+ const R = (size / 2) * 0.82;
121
+ const pt = makeProj(t * 0.55, 0.35 + 0.1 * Math.sin(t * 0.9), cx, cy, R);
122
+ const rs = radiusScale(size, o.rsPow ?? 0.6);
123
+ const moveCount = o.moveCount ?? 14;
124
+ const moves = makeMoves(moveCount);
125
+ const sc = solveCycle(t, moveCount, 0.42, 1.2);
126
+ const dots = [];
127
+ const latRings = o.latRings ?? 15;
128
+ const lonDensity = o.lonDensity ?? 40;
129
+ for (let li = 0; li <= latRings; li++) {
130
+ const lat = -Math.PI / 2 + (li / latRings) * Math.PI;
131
+ const cosLat = Math.cos(lat);
132
+ const sinLat = Math.sin(lat);
133
+ const lonCount = Math.max(1, Math.round(Math.abs(cosLat) * lonDensity));
134
+ for (let lj = 0; lj < lonCount; lj++) {
135
+ const lon = (lj / lonCount) * 2 * Math.PI;
136
+ const [x, y, z, inActive] = applyMoves([cosLat * Math.cos(lon), sinLat, cosLat * Math.sin(lon)], moves, sc);
137
+ const [px, py, zr] = pt(x, y, z);
138
+ const depth = (zr + 1) / 2;
139
+ // the band being turned inks a touch darker — the "hand"
140
+ dots.push({
141
+ x: px,
142
+ y: py,
143
+ z: zr,
144
+ r: ((o.rBase ?? 0.6) + (o.rDepth ?? 1.7) * depth + (inActive ? (o.rActive ?? 0.3) : 0)) * rs,
145
+ white: (o.inkFar ?? 0.62) - (o.inkSpan ?? 0.54) * depth - (inActive ? 0.14 : 0)
146
+ });
147
+ }
148
+ }
149
+ return finalizeFrame(dots, [], o.rMin);
150
+ };
151
+ // --- Wave: a waveform rolls through the rings — listening -------------
152
+ export const frameWave = (size, t, o) => {
153
+ const cx = size / 2;
154
+ const cy = size / 2;
155
+ // 0.76 base × 1.15 — the undulation pulls the sphere inward, so wave read
156
+ // ~15% smaller than the other lattice modes; scaled up to match them
157
+ const R = (size / 2) * 0.874;
158
+ const pt = makeProj(t * 0.18, 0.38, cx, cy, 1);
159
+ const rs = radiusScale(size, o.rsPow ?? 0.6);
160
+ const dots = [];
161
+ const rings = o.rings ?? 15;
162
+ const lonDensity = o.lonDensity ?? 40;
163
+ for (let ri = 0; ri <= rings; ri++) {
164
+ const lat = -Math.PI / 2 + (ri / rings) * Math.PI;
165
+ const cosLat = Math.cos(lat);
166
+ const sinLat = Math.sin(lat);
167
+ // two waves, different tempi — organic, never quite repeating
168
+ const w = 0.62 * Math.sin(t * 2.1 - ri * 0.52) + 0.38 * Math.sin(t * 1.27 + ri * 0.83);
169
+ const rr = R * (0.88 + 0.105 * w);
170
+ const lonCount = Math.max(1, Math.round(Math.abs(cosLat) * lonDensity));
171
+ for (let lj = 0; lj < lonCount; lj++) {
172
+ const lon = (lj / lonCount) * 2 * Math.PI;
173
+ const [px, py, z] = pt(cosLat * Math.cos(lon) * rr, sinLat * rr, cosLat * Math.sin(lon) * rr);
174
+ const depth = (z / R + 1) / 2;
175
+ const crest = Math.max(0, w);
176
+ dots.push({
177
+ x: px,
178
+ y: py,
179
+ z,
180
+ r: ((o.rBase ?? 0.6) + (o.rDepth ?? 1.7) * depth) * (1 + 0.4 * crest) * rs,
181
+ white: 0.66 - 0.56 * depth - 0.1 * crest
182
+ });
183
+ }
184
+ }
185
+ return finalizeFrame(dots, [], o.rMin);
186
+ };
187
+ //# sourceMappingURL=lattice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lattice.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/lattice.ts"],"names":[],"mappings":"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","sourcesContent":["// Indexed reads are bounded by the populated array length or modulo; assertions preserve upstream geometry.\n// Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.\n// The sphere-lattice modes: globe (searching), rubik (solving) and\n// wave (listening). All draw a lat/long dot field with mode-specific\n// motion, then hand off to the shared z-sorted painter.\n\nimport type { Dot, ModeFrame } from './types.js';\nimport { angleDelta, finalizeFrame, hashD, makeProj, radiusScale } from './core.js';\n\n// --- the shared solver heartbeat (rubik) ------------------------------\n// Rapid eased moves scramble, then replay in reverse (palindrome) so\n// everything clicks back to solved, rests, repeats.\n\ninterface Move {\n axis: 0 | 1 | 2;\n lo: number;\n hi: number;\n ang: number;\n}\n\nfunction solveCycle(time: number, count: number, slotDur: number, rest: number) {\n const cyc = 2 * count * slotDur + rest;\n const tc = time % cyc;\n const amount = new Array<number>(count).fill(0);\n let active = -1;\n if (tc < 2 * count * slotDur) {\n const slot = Math.floor(tc / slotDur);\n const p = (tc - slot * slotDur) / slotDur;\n const cl = Math.min(1, p / 0.7);\n const ep = 1 - (1 - cl) ** 3; // machine ease-out\n if (slot < count) {\n for (let i = 0; i < slot; i++) amount[i] = 1;\n amount[slot] = ep;\n active = slot;\n } else {\n const u = 2 * count - 1 - slot;\n for (let i = 0; i < u; i++) amount[i] = 1;\n amount[u] = 1 - ep;\n active = u;\n }\n }\n return { amount, active };\n}\n\nfunction applyMoves(\n pt3: [number, number, number],\n moves: Move[],\n sc: { amount: number[]; active: number }\n): [number, number, number, boolean] {\n let [x, y, z] = pt3;\n let inActive = false;\n for (let i = 0; i < moves.length; i++) {\n if (sc.amount[i]! <= 0) continue;\n const mv = moves[i]!;\n const coord = mv.axis === 0 ? x : mv.axis === 1 ? y : z;\n if (coord < mv.lo || coord >= mv.hi) continue;\n if (i === sc.active) inActive = true;\n const a = mv.ang * sc.amount[i]!;\n const ca = Math.cos(a);\n const sa = Math.sin(a);\n if (mv.axis === 0) {\n const y2 = y * ca - z * sa;\n z = y * sa + z * ca;\n y = y2;\n } else if (mv.axis === 1) {\n const x2 = x * ca + z * sa;\n z = -x * sa + z * ca;\n x = x2;\n } else {\n const x2 = x * ca - y * sa;\n y = x * sa + y * ca;\n x = x2;\n }\n }\n return [x, y, z, inActive];\n}\n\nfunction makeMoves(count: number): Move[] {\n const moves: Move[] = [];\n for (let i = 0; i < count; i++) {\n const axis = Math.min(2, Math.floor(hashD(i, 2.3) * 3)) as 0 | 1 | 2;\n const lo = -1.0 + 0.5 * Math.min(3, Math.floor(hashD(i, 5.9) * 4));\n const dir = hashD(i, 7.7) < 0.5 ? 1 : -1;\n moves.push({ axis, lo, hi: lo + 0.5, ang: (dir * Math.PI) / 2 });\n }\n return moves;\n}\n\n// --- Globe: lat/long field, a scan meridian sweeps — searching --------\n\nexport const frameGlobe: ModeFrame = (size, t, o) => {\n const spin = 0.5;\n const cx = size / 2;\n const cy = size / 2;\n const radius = (size / 2) * 0.82;\n const tilt = 0.4 + 0.06 * Math.sin(t * 0.35);\n const pt = makeProj(t * spin, tilt, cx, cy, radius);\n // scan sweeps relative to the spin; scanMul scales that relative rate\n const scan = t * (spin + (1.7 - spin) * (o.scanMul ?? 1));\n const rs = radiusScale(size, o.rsPow ?? 0.6);\n const dimBase = o.dimBase ?? 1;\n\n const dots: Dot[] = [];\n const latRings = o.latRings ?? 17;\n const lonDensity = o.lonDensity ?? 44;\n for (let li = 0; li <= latRings; li++) {\n const lat = -Math.PI / 2 + (li / latRings) * Math.PI;\n const cosLat = Math.cos(lat);\n const sinLat = Math.sin(lat);\n const lonCount = Math.max(1, Math.round(Math.abs(cosLat) * lonDensity));\n for (let lj = 0; lj < lonCount; lj++) {\n const lon = (lj / lonCount) * 2 * Math.PI;\n const [px, py, z] = pt(cosLat * Math.cos(lon), sinLat, cosLat * Math.sin(lon));\n const depth = (z + 1) / 2;\n // the scan: a moving meridian read as a size ripple, not a shine\n const d = angleDelta(lon + t * spin, scan);\n const boost = Math.exp(-(d * d) / 0.18) * Math.max(0, z);\n dots.push({\n x: px,\n y: py,\n z,\n r: ((o.rBase ?? 0.6) + (o.rDepth ?? 1.7) * depth + (o.rBoost ?? 1) * boost) * rs,\n white: (o.inkFar ?? 0.62) - (o.inkSpan ?? 0.54) * depth,\n // dimBase < 1 fades un-scanned dots so the meridian reads clearly\n a: dimBase + (1 - dimBase) * Math.min(1, boost)\n });\n }\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n\n// --- Rubik: bands twist in quarter turns, scramble → solve — solving --\n\nexport const frameRubik: ModeFrame = (size, t, o) => {\n const cx = size / 2;\n const cy = size / 2;\n const R = (size / 2) * 0.82;\n const pt = makeProj(t * 0.55, 0.35 + 0.1 * Math.sin(t * 0.9), cx, cy, R);\n const rs = radiusScale(size, o.rsPow ?? 0.6);\n const moveCount = o.moveCount ?? 14;\n const moves = makeMoves(moveCount);\n const sc = solveCycle(t, moveCount, 0.42, 1.2);\n\n const dots: Dot[] = [];\n const latRings = o.latRings ?? 15;\n const lonDensity = o.lonDensity ?? 40;\n for (let li = 0; li <= latRings; li++) {\n const lat = -Math.PI / 2 + (li / latRings) * Math.PI;\n const cosLat = Math.cos(lat);\n const sinLat = Math.sin(lat);\n const lonCount = Math.max(1, Math.round(Math.abs(cosLat) * lonDensity));\n for (let lj = 0; lj < lonCount; lj++) {\n const lon = (lj / lonCount) * 2 * Math.PI;\n const [x, y, z, inActive] = applyMoves([cosLat * Math.cos(lon), sinLat, cosLat * Math.sin(lon)], moves, sc);\n const [px, py, zr] = pt(x, y, z);\n const depth = (zr + 1) / 2;\n // the band being turned inks a touch darker — the \"hand\"\n dots.push({\n x: px,\n y: py,\n z: zr,\n r: ((o.rBase ?? 0.6) + (o.rDepth ?? 1.7) * depth + (inActive ? (o.rActive ?? 0.3) : 0)) * rs,\n white: (o.inkFar ?? 0.62) - (o.inkSpan ?? 0.54) * depth - (inActive ? 0.14 : 0)\n });\n }\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n\n// --- Wave: a waveform rolls through the rings — listening -------------\n\nexport const frameWave: ModeFrame = (size, t, o) => {\n const cx = size / 2;\n const cy = size / 2;\n // 0.76 base × 1.15 — the undulation pulls the sphere inward, so wave read\n // ~15% smaller than the other lattice modes; scaled up to match them\n const R = (size / 2) * 0.874;\n const pt = makeProj(t * 0.18, 0.38, cx, cy, 1);\n const rs = radiusScale(size, o.rsPow ?? 0.6);\n\n const dots: Dot[] = [];\n const rings = o.rings ?? 15;\n const lonDensity = o.lonDensity ?? 40;\n for (let ri = 0; ri <= rings; ri++) {\n const lat = -Math.PI / 2 + (ri / rings) * Math.PI;\n const cosLat = Math.cos(lat);\n const sinLat = Math.sin(lat);\n // two waves, different tempi — organic, never quite repeating\n const w = 0.62 * Math.sin(t * 2.1 - ri * 0.52) + 0.38 * Math.sin(t * 1.27 + ri * 0.83);\n const rr = R * (0.88 + 0.105 * w);\n const lonCount = Math.max(1, Math.round(Math.abs(cosLat) * lonDensity));\n for (let lj = 0; lj < lonCount; lj++) {\n const lon = (lj / lonCount) * 2 * Math.PI;\n const [px, py, z] = pt(cosLat * Math.cos(lon) * rr, sinLat * rr, cosLat * Math.sin(lon) * rr);\n const depth = (z / R + 1) / 2;\n const crest = Math.max(0, w);\n dots.push({\n x: px,\n y: py,\n z,\n r: ((o.rBase ?? 0.6) + (o.rDepth ?? 1.7) * depth) * (1 + 0.4 * crest) * rs,\n white: 0.66 - 0.56 * depth - 0.1 * crest\n });\n }\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ModeFrame } from './types.js';
2
+ export declare const frameMorph: ModeFrame;
3
+ //# sourceMappingURL=morph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morph.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/morph.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,YAAY,CAAC;AAsEjD,eAAO,MAAM,UAAU,EAAE,SA2DxB,CAAC"}
@@ -0,0 +1,127 @@
1
+ // Indexed reads are bounded by the populated array length or modulo; assertions preserve upstream geometry.
2
+ // Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.
3
+ // Morph: a dotted outline cycling circle → triangle → square → circle —
4
+ // the "shaping" state. Each shape is a continuous closed path
5
+ // parameterised by arc length (top-centre start, clockwise). Every
6
+ // frame the engine blends the two neighbouring paths, then lays the
7
+ // dots EVENLY along the blended outline — spacing stays uniform at
8
+ // every instant of the morph, holds and transitions alike. Plain
9
+ // circle fills only: no canvas/SVG filters, fully cross-browser.
10
+ import { finalizeFrame } from './core.js';
11
+ function smoothE(x) {
12
+ return x * x * (3 - 2 * x);
13
+ }
14
+ function polyPath(verts) {
15
+ const V = verts.length;
16
+ const L = [];
17
+ let total = 0;
18
+ for (let i = 0; i < V; i++) {
19
+ const a = verts[i];
20
+ const b = verts[(i + 1) % V];
21
+ const l = Math.hypot(b[0] - a[0], b[1] - a[1]);
22
+ L.push(l);
23
+ total += l;
24
+ }
25
+ return (f) => {
26
+ let target = f * total;
27
+ let i = 0;
28
+ while (target > L[i] && i < V - 1) {
29
+ target -= L[i];
30
+ i++;
31
+ }
32
+ const a = verts[i];
33
+ const b = verts[(i + 1) % V];
34
+ const ff = L[i] ? Math.min(1, target / L[i]) : 0;
35
+ return [a[0] + (b[0] - a[0]) * ff, a[1] + (b[1] - a[1]) * ff];
36
+ };
37
+ }
38
+ const CIRCLE = (f) => {
39
+ const a = -Math.PI / 2 + f * 2 * Math.PI;
40
+ return [Math.cos(a) * 0.24, Math.sin(a) * 0.24];
41
+ };
42
+ const TRIANGLE = polyPath([
43
+ [0.0, -0.26],
44
+ [0.24, 0.16],
45
+ [-0.24, 0.16]
46
+ ]);
47
+ // 5-vertex walk so the path STARTS at top-centre like the other shapes
48
+ const SQUARE = polyPath([
49
+ [0, -0.2],
50
+ [0.2, -0.2],
51
+ [0.2, 0.2],
52
+ [-0.2, 0.2],
53
+ [-0.2, -0.2]
54
+ ]);
55
+ const CYCLE = [CIRCLE, TRIANGLE, SQUARE];
56
+ // low floor keeps sparse outlines possible while never degenerating
57
+ function morphN(d) {
58
+ return Math.max(6, Math.round(34 * d));
59
+ }
60
+ const HOLD = 1.4;
61
+ const MORPH = 0.9;
62
+ const SEG = HOLD + MORPH;
63
+ // This state was tuned in inkform, which paints it through a blur +
64
+ // threshold "goo" filter; we draw plain circles instead, since `ctx.filter`
65
+ // and SVG filter refs are not safe to rely on across Chrome / Safari /
66
+ // Firefox. The dot GEOMETRY is identical either way — the threshold just
67
+ // yields a hard edge where a plain fill has an antialiased one, so these
68
+ // dots read a touch softer than inkform's. Don't "correct" for that by
69
+ // shrinking the radius: it makes the mark genuinely smaller than the tuning.
70
+ export const frameMorph = (size, t, o) => {
71
+ const K = CYCLE.length;
72
+ const tc = t % (SEG * K);
73
+ const k = Math.floor(tc / SEG);
74
+ const local = tc - k * SEG;
75
+ const m = local > HOLD ? smoothE((local - HOLD) / MORPH) : 0;
76
+ const sprd = o.spread ?? 1;
77
+ // blend the two shape PATHS at m, then measure the blended outline
78
+ const pA = CYCLE[k];
79
+ const pB = CYCLE[(k + 1) % K];
80
+ const M = 160;
81
+ const pts = [];
82
+ for (let i = 0; i < M; i++) {
83
+ const f = i / M;
84
+ const a = pA(f);
85
+ const b = pB(f);
86
+ pts.push([(a[0] + (b[0] - a[0]) * m) * sprd, (a[1] + (b[1] - a[1]) * m) * sprd]);
87
+ }
88
+ const L = [];
89
+ let total = 0;
90
+ for (let i = 0; i < M; i++) {
91
+ const a = pts[i];
92
+ const b = pts[(i + 1) % M];
93
+ const l = Math.hypot(b[0] - a[0], b[1] - a[1]);
94
+ L.push(l);
95
+ total += l;
96
+ }
97
+ // dot radius depends ONLY on rDot (the size knob); the count sets the
98
+ // gaps. Formed shapes breathe a little (uniform pulse).
99
+ const n = morphN(o.iconD ?? 1);
100
+ const re = (o.rDot ?? 0.021) * 1.35 * sprd;
101
+ const pulse = 1 + 0.02 * Math.sin(local * 3.1);
102
+ const dots = [];
103
+ const c2 = size / 2;
104
+ let seg = 0;
105
+ let acc = 0;
106
+ for (let k2 = 0; k2 < n; k2++) {
107
+ const target = (k2 / n) * total;
108
+ while (acc + L[seg] < target && seg < M - 1) {
109
+ acc += L[seg];
110
+ seg++;
111
+ }
112
+ const a = pts[seg];
113
+ const b = pts[(seg + 1) % M];
114
+ const f = L[seg] ? Math.min(1, (target - acc) / L[seg]) : 0;
115
+ const x = (a[0] + (b[0] - a[0]) * f) * pulse;
116
+ const y = (a[1] + (b[1] - a[1]) * f) * pulse;
117
+ dots.push({
118
+ x: c2 + x * size,
119
+ y: c2 + y * size,
120
+ z: 0,
121
+ r: Math.max(0.35, re * size),
122
+ white: 0.1
123
+ });
124
+ }
125
+ return finalizeFrame(dots, [], o.rMin);
126
+ };
127
+ //# sourceMappingURL=morph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morph.js","sourceRoot":"","sources":["../../../src/internal/thinking-orb/morph.ts"],"names":[],"mappings":"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","sourcesContent":["// Indexed reads are bounded by the populated array length or modulo; assertions preserve upstream geometry.\n// Adapted from Thinking Orbs de85557 (MIT); see THIRD_PARTY_NOTICES.md.\n// Morph: a dotted outline cycling circle → triangle → square → circle —\n// the \"shaping\" state. Each shape is a continuous closed path\n// parameterised by arc length (top-centre start, clockwise). Every\n// frame the engine blends the two neighbouring paths, then lays the\n// dots EVENLY along the blended outline — spacing stays uniform at\n// every instant of the morph, holds and transitions alike. Plain\n// circle fills only: no canvas/SVG filters, fully cross-browser.\n\nimport type { Dot, ModeFrame } from './types.js';\nimport { finalizeFrame } from './core.js';\n\ntype Path = (f: number) => [number, number];\n\nfunction smoothE(x: number): number {\n return x * x * (3 - 2 * x);\n}\n\nfunction polyPath(verts: ReadonlyArray<readonly [number, number]>): Path {\n const V = verts.length;\n const L: number[] = [];\n let total = 0;\n for (let i = 0; i < V; i++) {\n const a = verts[i]!;\n const b = verts[(i + 1) % V]!;\n const l = Math.hypot(b[0] - a[0], b[1] - a[1]);\n L.push(l);\n total += l;\n }\n return (f) => {\n let target = f * total;\n let i = 0;\n while (target > L[i]! && i < V - 1) {\n target -= L[i]!;\n i++;\n }\n const a = verts[i]!;\n const b = verts[(i + 1) % V]!;\n const ff = L[i]! ? Math.min(1, target / L[i]!) : 0;\n return [a[0] + (b[0] - a[0]) * ff, a[1] + (b[1] - a[1]) * ff];\n };\n}\n\nconst CIRCLE: Path = (f) => {\n const a = -Math.PI / 2 + f * 2 * Math.PI;\n return [Math.cos(a) * 0.24, Math.sin(a) * 0.24];\n};\nconst TRIANGLE = polyPath([\n [0.0, -0.26],\n [0.24, 0.16],\n [-0.24, 0.16]\n]);\n// 5-vertex walk so the path STARTS at top-centre like the other shapes\nconst SQUARE = polyPath([\n [0, -0.2],\n [0.2, -0.2],\n [0.2, 0.2],\n [-0.2, 0.2],\n [-0.2, -0.2]\n]);\nconst CYCLE: Path[] = [CIRCLE, TRIANGLE, SQUARE];\n\n// low floor keeps sparse outlines possible while never degenerating\nfunction morphN(d: number): number {\n return Math.max(6, Math.round(34 * d));\n}\n\nconst HOLD = 1.4;\nconst MORPH = 0.9;\nconst SEG = HOLD + MORPH;\n\n// This state was tuned in inkform, which paints it through a blur +\n// threshold \"goo\" filter; we draw plain circles instead, since `ctx.filter`\n// and SVG filter refs are not safe to rely on across Chrome / Safari /\n// Firefox. The dot GEOMETRY is identical either way — the threshold just\n// yields a hard edge where a plain fill has an antialiased one, so these\n// dots read a touch softer than inkform's. Don't \"correct\" for that by\n// shrinking the radius: it makes the mark genuinely smaller than the tuning.\n\nexport const frameMorph: ModeFrame = (size, t, o) => {\n const K = CYCLE.length;\n const tc = t % (SEG * K);\n const k = Math.floor(tc / SEG);\n const local = tc - k * SEG;\n const m = local > HOLD ? smoothE((local - HOLD) / MORPH) : 0;\n const sprd = o.spread ?? 1;\n\n // blend the two shape PATHS at m, then measure the blended outline\n const pA = CYCLE[k]!;\n const pB = CYCLE[(k + 1) % K]!;\n const M = 160;\n const pts: Array<[number, number]> = [];\n for (let i = 0; i < M; i++) {\n const f = i / M;\n const a = pA(f);\n const b = pB(f);\n pts.push([(a[0] + (b[0] - a[0]) * m) * sprd, (a[1] + (b[1] - a[1]) * m) * sprd]);\n }\n const L: number[] = [];\n let total = 0;\n for (let i = 0; i < M; i++) {\n const a = pts[i]!;\n const b = pts[(i + 1) % M]!;\n const l = Math.hypot(b[0] - a[0], b[1] - a[1]);\n L.push(l);\n total += l;\n }\n\n // dot radius depends ONLY on rDot (the size knob); the count sets the\n // gaps. Formed shapes breathe a little (uniform pulse).\n const n = morphN(o.iconD ?? 1);\n const re = (o.rDot ?? 0.021) * 1.35 * sprd;\n const pulse = 1 + 0.02 * Math.sin(local * 3.1);\n\n const dots: Dot[] = [];\n const c2 = size / 2;\n let seg = 0;\n let acc = 0;\n for (let k2 = 0; k2 < n; k2++) {\n const target = (k2 / n) * total;\n while (acc + L[seg]! < target && seg < M - 1) {\n acc += L[seg]!;\n seg++;\n }\n const a = pts[seg]!;\n const b = pts[(seg + 1) % M]!;\n const f = L[seg]! ? Math.min(1, (target - acc) / L[seg]!) : 0;\n const x = (a[0] + (b[0] - a[0]) * f) * pulse;\n const y = (a[1] + (b[1] - a[1]) * f) * pulse;\n dots.push({\n x: c2 + x * size,\n y: c2 + y * size,\n z: 0,\n r: Math.max(0.35, re * size),\n white: 0.1\n });\n }\n return finalizeFrame(dots, [], o.rMin);\n};\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ModeFrame } from './types.js';
2
+ export declare const frameOrbits: ModeFrame;
3
+ //# sourceMappingURL=orbits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orbits.d.ts","sourceRoot":"","sources":["../../../src/internal/thinking-orb/orbits.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAO,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjD,eAAO,MAAM,WAAW,EAAE,SAwEzB,CAAC"}