privateer-agent 0.15.4 → 0.15.6

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 (229) hide show
  1. package/README.md +11 -0
  2. package/bin/boot-bundle.d.mts +2 -0
  3. package/bin/boot-bundle.mjs +44 -0
  4. package/bin/fresh-supervisor.d.mts +5 -1
  5. package/bin/fresh-supervisor.mjs +47 -10
  6. package/bin/privateer-launch.mjs +27 -3
  7. package/bin/privateer-subagent.mjs +5 -2
  8. package/bin/privateer-verify.mjs +12 -0
  9. package/bin/session-recovery.d.mts +53 -0
  10. package/bin/session-recovery.mjs +240 -0
  11. package/bin/session-seal-preload.mjs +17 -0
  12. package/bin/session-seal.d.mts +25 -0
  13. package/bin/session-seal.mjs +242 -0
  14. package/dist-boot/boot.mjs +3 -0
  15. package/dist-boot/c-27JKSMWL.mjs +1460 -0
  16. package/dist-boot/c-2BMRFV24.mjs +269 -0
  17. package/dist-boot/c-2CTF6JA3.mjs +166 -0
  18. package/dist-boot/c-2G3BBHRJ.mjs +84 -0
  19. package/dist-boot/c-2IDLKXX6.mjs +250 -0
  20. package/dist-boot/c-2NJD5VYM.mjs +8 -0
  21. package/dist-boot/c-2S5EEQPW.mjs +1602 -0
  22. package/dist-boot/c-2WRDCUVI.mjs +25 -0
  23. package/dist-boot/c-2YN3M256.mjs +14 -0
  24. package/dist-boot/c-37GM3GMU.mjs +187 -0
  25. package/dist-boot/c-3STKRSVO.mjs +2480 -0
  26. package/dist-boot/c-3TPV6TQQ.mjs +2320 -0
  27. package/dist-boot/c-3UVHLQDJ.mjs +225 -0
  28. package/dist-boot/c-42PUUZYC.mjs +697 -0
  29. package/dist-boot/c-4D5UMWVW.mjs +683 -0
  30. package/dist-boot/c-4ETZRMTA.mjs +46 -0
  31. package/dist-boot/c-4QT25BD5.mjs +1482 -0
  32. package/dist-boot/c-4WVR32AP.mjs +2579 -0
  33. package/dist-boot/c-5EMM567G.mjs +152 -0
  34. package/dist-boot/c-5FA4CV63.mjs +145 -0
  35. package/dist-boot/c-5GV3X3RB.mjs +14 -0
  36. package/dist-boot/c-5JCEPRIY.mjs +52 -0
  37. package/dist-boot/c-5NDKIIWT.mjs +16 -0
  38. package/dist-boot/c-5QL3AR26.mjs +4665 -0
  39. package/dist-boot/c-5XY6MFKN.mjs +5142 -0
  40. package/dist-boot/c-65UZIZC7.mjs +2897 -0
  41. package/dist-boot/c-6FUXKHOK.mjs +1969 -0
  42. package/dist-boot/c-6JHWQE4V.mjs +18242 -0
  43. package/dist-boot/c-6LOBR4I6.mjs +5280 -0
  44. package/dist-boot/c-6QHOZXKQ.mjs +14394 -0
  45. package/dist-boot/c-6ZO2SADQ.mjs +178 -0
  46. package/dist-boot/c-6ZORVVZP.mjs +1449 -0
  47. package/dist-boot/c-76QH4UCP.mjs +2441 -0
  48. package/dist-boot/c-77GO5L5Y.mjs +20982 -0
  49. package/dist-boot/c-7M23XFTN.mjs +5052 -0
  50. package/dist-boot/c-7TC367E2.mjs +32 -0
  51. package/dist-boot/c-7UOG7POX.mjs +1524 -0
  52. package/dist-boot/c-7VHP3FLN.mjs +376 -0
  53. package/dist-boot/c-A73JHZP2.mjs +13207 -0
  54. package/dist-boot/c-ABXULAFL.mjs +71 -0
  55. package/dist-boot/c-ANDD2AQO.mjs +74 -0
  56. package/dist-boot/c-AOY77AZL.mjs +1430 -0
  57. package/dist-boot/c-AXEPZ22I.mjs +108 -0
  58. package/dist-boot/c-B2Y7VNHU.mjs +427 -0
  59. package/dist-boot/c-B7VJUH73.mjs +77 -0
  60. package/dist-boot/c-BFW6CDVL.mjs +24 -0
  61. package/dist-boot/c-BHNIF2AR.mjs +188 -0
  62. package/dist-boot/c-BKF2O6BL.mjs +23 -0
  63. package/dist-boot/c-BOZXFTZN.mjs +8 -0
  64. package/dist-boot/c-BRNYJWZL.mjs +28 -0
  65. package/dist-boot/c-C3N4Z2HO.mjs +93 -0
  66. package/dist-boot/c-C4IV7ZFG.mjs +717 -0
  67. package/dist-boot/c-C5NK6UYV.mjs +793 -0
  68. package/dist-boot/c-C67644MB.mjs +1659 -0
  69. package/dist-boot/c-C6S2YB53.mjs +620 -0
  70. package/dist-boot/c-CDBEJSBF.mjs +37 -0
  71. package/dist-boot/c-CG47HBKU.mjs +435 -0
  72. package/dist-boot/c-CKCTWCT5.mjs +51 -0
  73. package/dist-boot/c-CN77DCGF.mjs +60 -0
  74. package/dist-boot/c-CRBXNKFO.mjs +1795 -0
  75. package/dist-boot/c-CRIHASQ6.mjs +973 -0
  76. package/dist-boot/c-CU4NGAUO.mjs +3786 -0
  77. package/dist-boot/c-CWRFLGQU.mjs +1883 -0
  78. package/dist-boot/c-CYQB2USO.mjs +32 -0
  79. package/dist-boot/c-DEE67DJO.mjs +379 -0
  80. package/dist-boot/c-DIFDBYOP.mjs +1258 -0
  81. package/dist-boot/c-DOSGVXDZ.mjs +34879 -0
  82. package/dist-boot/c-DR7XQI32.mjs +381 -0
  83. package/dist-boot/c-DTGPSB46.mjs +14666 -0
  84. package/dist-boot/c-DTHDNA4P.mjs +320 -0
  85. package/dist-boot/c-E4Z3Y5B5.mjs +3864 -0
  86. package/dist-boot/c-E66Z2TI7.mjs +203 -0
  87. package/dist-boot/c-EBU6RLRV.mjs +1527 -0
  88. package/dist-boot/c-EBZZNGSF.mjs +432 -0
  89. package/dist-boot/c-EC3LJ2KF.mjs +1032 -0
  90. package/dist-boot/c-EQBKXWNX.mjs +15829 -0
  91. package/dist-boot/c-EUEPIW4S.mjs +574 -0
  92. package/dist-boot/c-EX4YVWAT.mjs +378 -0
  93. package/dist-boot/c-EYZGSAJU.mjs +98 -0
  94. package/dist-boot/c-F75VRKY4.mjs +172 -0
  95. package/dist-boot/c-FH4NXKHV.mjs +177 -0
  96. package/dist-boot/c-FHNUCTEM.mjs +140 -0
  97. package/dist-boot/c-FJ5T42DS.mjs +5349 -0
  98. package/dist-boot/c-FPCNRL7G.mjs +1728 -0
  99. package/dist-boot/c-G4DLN7Q4.mjs +8 -0
  100. package/dist-boot/c-G56GYQFZ.mjs +2507 -0
  101. package/dist-boot/c-GLIOERDQ.mjs +1200 -0
  102. package/dist-boot/c-GMJ5HUBM.mjs +14 -0
  103. package/dist-boot/c-H3HSGMAQ.mjs +461 -0
  104. package/dist-boot/c-HIKTO6P7.mjs +275 -0
  105. package/dist-boot/c-I2MCJ34O.mjs +464 -0
  106. package/dist-boot/c-I3C6LBW4.mjs +765 -0
  107. package/dist-boot/c-I54OKQHW.mjs +387 -0
  108. package/dist-boot/c-IFSP3R4D.mjs +80 -0
  109. package/dist-boot/c-IZK77VB7.mjs +171 -0
  110. package/dist-boot/c-J3Y25UGE.mjs +54 -0
  111. package/dist-boot/c-J5IESS7W.mjs +27750 -0
  112. package/dist-boot/c-JJWZBY7L.mjs +254 -0
  113. package/dist-boot/c-JKTFXTGF.mjs +463 -0
  114. package/dist-boot/c-JN57AXQ4.mjs +77 -0
  115. package/dist-boot/c-KFIO6LUW.mjs +1096 -0
  116. package/dist-boot/c-KIEMEFWW.mjs +478 -0
  117. package/dist-boot/c-KIVXWBYD.mjs +28 -0
  118. package/dist-boot/c-KP6CRIP4.mjs +580 -0
  119. package/dist-boot/c-L26VOJX4.mjs +11558 -0
  120. package/dist-boot/c-L5GHWG5G.mjs +5988 -0
  121. package/dist-boot/c-M7NSQAKK.mjs +353 -0
  122. package/dist-boot/c-MCEWOPBW.mjs +56 -0
  123. package/dist-boot/c-MGPIEG7I.mjs +20 -0
  124. package/dist-boot/c-NREXJV3M.mjs +393 -0
  125. package/dist-boot/c-O5PP6CTX.mjs +162 -0
  126. package/dist-boot/c-OBQDHSXM.mjs +1774 -0
  127. package/dist-boot/c-OLQHHDD4.mjs +21 -0
  128. package/dist-boot/c-OXW4JQQH.mjs +319 -0
  129. package/dist-boot/c-P3D7ZUWN.mjs +1288 -0
  130. package/dist-boot/c-P4PQZVV5.mjs +948 -0
  131. package/dist-boot/c-P63T3XL2.mjs +26373 -0
  132. package/dist-boot/c-P6N5DQGZ.mjs +194 -0
  133. package/dist-boot/c-P7MLKQFC.mjs +58 -0
  134. package/dist-boot/c-PB3PZJL5.mjs +1276 -0
  135. package/dist-boot/c-PTN4S6G2.mjs +1259 -0
  136. package/dist-boot/c-PYCE5J7U.mjs +1083 -0
  137. package/dist-boot/c-Q4HYCRLB.mjs +19410 -0
  138. package/dist-boot/c-QUXMETGG.mjs +68 -0
  139. package/dist-boot/c-RDMJZCOX.mjs +356 -0
  140. package/dist-boot/c-ROGJK76M.mjs +17 -0
  141. package/dist-boot/c-RQJJ26T4.mjs +708 -0
  142. package/dist-boot/c-RSKCUPJF.mjs +7559 -0
  143. package/dist-boot/c-RVJU4O6P.mjs +37 -0
  144. package/dist-boot/c-S2RVHR3M.mjs +165 -0
  145. package/dist-boot/c-SKMK3PEE.mjs +91120 -0
  146. package/dist-boot/c-TI7SM4EG.mjs +20 -0
  147. package/dist-boot/c-TILJ6GXD.mjs +1235 -0
  148. package/dist-boot/c-TT6BCUJD.mjs +114 -0
  149. package/dist-boot/c-U4ITOXAN.mjs +2107 -0
  150. package/dist-boot/c-UGERXVO2.mjs +7120 -0
  151. package/dist-boot/c-UPBH5AXY.mjs +1363 -0
  152. package/dist-boot/c-US2PUNZL.mjs +597 -0
  153. package/dist-boot/c-UU4WZPPE.mjs +20 -0
  154. package/dist-boot/c-UWVIYPQS.mjs +39 -0
  155. package/dist-boot/c-V4RHQBPQ.mjs +17683 -0
  156. package/dist-boot/c-V5MRVK47.mjs +351 -0
  157. package/dist-boot/c-V6CL266R.mjs +1755 -0
  158. package/dist-boot/c-VJTMFKYE.mjs +14975 -0
  159. package/dist-boot/c-VJTRUKIB.mjs +773 -0
  160. package/dist-boot/c-W4IFSHPW.mjs +43 -0
  161. package/dist-boot/c-WETGB2CF.mjs +113 -0
  162. package/dist-boot/c-WO3QSZUU.mjs +1337 -0
  163. package/dist-boot/c-WQLH73TY.mjs +242 -0
  164. package/dist-boot/c-XL735JW5.mjs +500 -0
  165. package/dist-boot/c-Y7HADL5B.mjs +1107 -0
  166. package/dist-boot/c-YGQHSVSK.mjs +41 -0
  167. package/dist-boot/c-YMP2AMEB.mjs +10350 -0
  168. package/dist-boot/c-YRDO2WEF.mjs +12012 -0
  169. package/dist-boot/c-YUSTRATJ.mjs +8 -0
  170. package/dist-boot/c-Z2262R22.mjs +2697 -0
  171. package/dist-boot/c-Z4ALQMJC.mjs +709 -0
  172. package/dist-boot/c-Z5ZUQVUY.mjs +62 -0
  173. package/dist-boot/c-ZDZUKXF7.mjs +874 -0
  174. package/dist-boot/c-ZJYLGIC3.mjs +32 -0
  175. package/dist-boot/c-ZNA5CDMI.mjs +77 -0
  176. package/dist-boot/c-ZSO6DI3M.mjs +204 -0
  177. package/dist-boot/c-ZWUVHKMK.mjs +100 -0
  178. package/dist-boot/c-ZY4MESEW.mjs +832 -0
  179. package/dist-boot/c-ZZ5REI4L.mjs +329 -0
  180. package/dist-boot/cli.mjs +51 -0
  181. package/dist-boot/ext-anthropic-attribution.mjs +207 -0
  182. package/dist-boot/ext-pi-background-tasks.mjs +7234 -0
  183. package/dist-boot/ext-pi-subagents.mjs +37 -0
  184. package/dist-boot/ext-privateer-account.mjs +4426 -0
  185. package/dist-boot/ext-privateer-brand.mjs +5274 -0
  186. package/dist-boot/ext-privateer-codemode.mjs +37 -0
  187. package/dist-boot/ext-privateer-computer.mjs +626 -0
  188. package/dist-boot/ext-privateer-connect.mjs +1862 -0
  189. package/dist-boot/ext-privateer-context.mjs +323 -0
  190. package/dist-boot/ext-privateer-desktop.mjs +92 -0
  191. package/dist-boot/ext-privateer-final-audit.mjs +48 -0
  192. package/dist-boot/ext-privateer-fresh.mjs +81 -0
  193. package/dist-boot/ext-privateer-gate.mjs +5959 -0
  194. package/dist-boot/ext-privateer-hints.mjs +236 -0
  195. package/dist-boot/ext-privateer-media.mjs +2626 -0
  196. package/dist-boot/ext-privateer-models.mjs +3397 -0
  197. package/dist-boot/ext-privateer-posture.mjs +3006 -0
  198. package/dist-boot/ext-privateer-privacy.mjs +4578 -0
  199. package/dist-boot/ext-privateer-recovery.mjs +287 -0
  200. package/dist-boot/ext-privateer-speak.mjs +4754 -0
  201. package/dist-boot/ext-privateer-terminals.mjs +725 -0
  202. package/dist-boot/ext-privateer-tools.mjs +528 -0
  203. package/dist-boot/ext-privateer-truncation.mjs +74 -0
  204. package/dist-boot/ext-privateer-update.mjs +210 -0
  205. package/dist-boot/ext-privateer-vision.mjs +148 -0
  206. package/dist-boot/ext-privateer-web.mjs +543 -0
  207. package/dist-boot/ext-rpiv-ask-user-question.mjs +710 -0
  208. package/dist-boot/manifest.json +9 -0
  209. package/extensions/privateer-brand.ts +3 -1
  210. package/extensions/privateer-context.ts +4 -2
  211. package/extensions/privateer-final-audit.ts +17 -0
  212. package/extensions/privateer-gate.ts +55 -9
  213. package/extensions/privateer-recovery.ts +175 -0
  214. package/extensions/privateer-web.ts +4 -4
  215. package/package.json +3 -1
  216. package/patches/@earendil-works+pi-coding-agent+1.3.0.patch +199 -2
  217. package/patches/pi-background-tasks+2.6.10.patch +91 -7
  218. package/src/cli/chat.ts +7 -1
  219. package/src/config/moatManifest.json +2 -0
  220. package/src/config/whatsNew.json +4 -4
  221. package/src/context.ts +33 -5
  222. package/src/engine/finalAudit.ts +38 -0
  223. package/src/engine/stallWatchdog.ts +8 -1
  224. package/src/providers/account.ts +34 -3
  225. package/src/remote/attentionPush.ts +40 -0
  226. package/src/remote/liveTaskSession.ts +7 -1
  227. package/src/remote/relayClient.ts +38 -4
  228. package/src/remote/remoteBridge.ts +17 -0
  229. package/src/remote/transcriptSnapshot.ts +104 -0
@@ -0,0 +1,1107 @@
1
+ import{createRequire as __pvCR}from"node:module";import{fileURLToPath as __pvF}from"node:url";import{dirname as __pvD}from"node:path";const require=__pvCR(import.meta.url);const __pvUrl=(r)=>new URL(r,import.meta.url).href;const __pvFile=(r)=>__pvF(new URL(r,import.meta.url));
2
+ import {
3
+ ARMIN_HEIGHT,
4
+ ARMIN_WIDTH,
5
+ isArminPixel
6
+ } from "./c-JKTFXTGF.mjs";
7
+ import {
8
+ formatKeyText,
9
+ theme
10
+ } from "./c-CRBXNKFO.mjs";
11
+ import "./c-KP6CRIP4.mjs";
12
+ import "./c-RSKCUPJF.mjs";
13
+ import "./c-PTN4S6G2.mjs";
14
+ import {
15
+ backgroundAnsi,
16
+ colorToRgb,
17
+ foregroundAnsi,
18
+ getKeybindings,
19
+ indexedColor,
20
+ rgbColor,
21
+ visibleWidth
22
+ } from "./c-EQBKXWNX.mjs";
23
+ import {
24
+ __name
25
+ } from "./c-CN77DCGF.mjs";
26
+
27
+ // node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/easter-egg-3d.js
28
+ var DEPTH = 0.7;
29
+ var FLY_START = 0.1;
30
+ var FLY_DURATION = 1.3;
31
+ var START_SCALE = 0.1;
32
+ function createModel(columns, rows, pixel, options) {
33
+ const blocks = [];
34
+ for (let row = 0; row < rows; row++) {
35
+ for (let column = 0; column < columns; column++) {
36
+ const color = pixel(column, row);
37
+ if (color)
38
+ blocks.push({ home: [column, row, 0], color });
39
+ }
40
+ }
41
+ return {
42
+ columns,
43
+ rows,
44
+ blocks,
45
+ cameraDistance: options.cameraDistance,
46
+ radius: Math.hypot(columns / 2, rows / 2, 1 + DEPTH / 2),
47
+ widthShare: options.widthShare,
48
+ puzzleMoves: /* @__PURE__ */ __name((random) => options.puzzleMoves(random, blocks.length), "puzzleMoves"),
49
+ origin: options.origin
50
+ };
51
+ }
52
+ __name(createModel, "createModel");
53
+ var CORAL = [228, 138, 122];
54
+ var BLUE = [79, 142, 179];
55
+ var YELLOW = [234, 182, 93];
56
+ var PI_LOGO_PIXELS = ["ccc.", "b.c.", "bb.y", "b..y"];
57
+ var PI_LOGO_COLORS = { c: CORAL, b: BLUE, y: YELLOW };
58
+ function piLogoModel(origin) {
59
+ return createModel(4, 4, (column, row) => PI_LOGO_COLORS[PI_LOGO_PIXELS[row][column]], {
60
+ cameraDistance: 10,
61
+ widthShare: 0.35,
62
+ puzzleMoves: /* @__PURE__ */ __name((random) => random < 0.4 ? 2 : 1, "puzzleMoves"),
63
+ origin
64
+ });
65
+ }
66
+ __name(piLogoModel, "piLogoModel");
67
+ function arminModel(color) {
68
+ return createModel(ARMIN_WIDTH, ARMIN_HEIGHT, (column, row) => isArminPixel(column, row) ? color : void 0, {
69
+ // Far enough that the perspective stays mild for a figure about 36 blocks tall.
70
+ cameraDistance: 80,
71
+ widthShare: 0.45,
72
+ puzzleMoves: /* @__PURE__ */ __name((random, blockCount) => Math.round(blockCount * (0.03 + random * 0.04)), "puzzleMoves"),
73
+ origin: void 0
74
+ });
75
+ }
76
+ __name(arminModel, "arminModel");
77
+ var PUZZLE_START = FLY_START + FLY_DURATION + 3;
78
+ var PUZZLE_STEP = 0.3;
79
+ var PUZZLE_STEPS = 12;
80
+ var PUZZLE_RETURN = 1;
81
+ var PUZZLE_HOLD = 0.6;
82
+ var PUZZLE_CYCLE = PUZZLE_STEP * PUZZLE_STEPS + PUZZLE_RETURN + PUZZLE_HOLD;
83
+ var PUZZLE_MOVES = [
84
+ [1, 0, 0],
85
+ [-1, 0, 0],
86
+ [0, 1, 0],
87
+ [0, -1, 0],
88
+ [1, 0, 0],
89
+ [-1, 0, 0],
90
+ [0, 1, 0],
91
+ [0, -1, 0],
92
+ [0, 0, 1],
93
+ [0, 0, -1]
94
+ ];
95
+ function shuffleSteps(model, cycle) {
96
+ const { columns, rows } = model;
97
+ let positions = model.blocks.map((block) => block.home);
98
+ const steps = [positions];
99
+ const lastMoved = /* @__PURE__ */ new Set();
100
+ let random = cycle * 7919 + 1;
101
+ const next = /* @__PURE__ */ __name(() => hash(random++), "next");
102
+ const key = /* @__PURE__ */ __name(([x, y, z]) => ((z + 1) * rows + y) * columns + x, "key");
103
+ for (let step = 0; step < PUZZLE_STEPS; step++) {
104
+ const occupied = new Set(positions.map(key));
105
+ const nextPositions = [...positions];
106
+ const moved = /* @__PURE__ */ new Set();
107
+ const moveCount = model.puzzleMoves(next());
108
+ for (let move = 0; move < moveCount; move++) {
109
+ const candidates = [];
110
+ for (let block = 0; block < positions.length; block++) {
111
+ if (moved.has(block))
112
+ continue;
113
+ const [x, y, z] = positions[block];
114
+ for (const [dx, dy, dz] of PUZZLE_MOVES) {
115
+ const target = [x + dx, y + dy, z + dz];
116
+ if (target[0] < 0 || target[0] >= columns || target[1] < 0 || target[1] >= rows)
117
+ continue;
118
+ if (target[2] < -1 || target[2] > 1 || occupied.has(key(target)))
119
+ continue;
120
+ candidates.push({ block, target });
121
+ }
122
+ }
123
+ const fresh = candidates.filter((candidate) => !lastMoved.has(candidate.block));
124
+ const pool = fresh.length > 0 ? fresh : candidates;
125
+ const choice = pool[Math.floor(next() * pool.length)];
126
+ if (!choice)
127
+ break;
128
+ occupied.add(key(choice.target));
129
+ nextPositions[choice.block] = choice.target;
130
+ moved.add(choice.block);
131
+ }
132
+ lastMoved.clear();
133
+ for (const block of moved)
134
+ lastMoved.add(block);
135
+ positions = nextPositions;
136
+ steps.push(positions);
137
+ }
138
+ return steps;
139
+ }
140
+ __name(shuffleSteps, "shuffleSteps");
141
+ var FRAME_MS = 1e3 / 30;
142
+ var DUST_DURATION = 0.35;
143
+ var WAVE_SPREAD = 0.55;
144
+ var WAVE_JITTER = 0.12;
145
+ var DISSOLVE_END = FLY_START + WAVE_SPREAD + WAVE_JITTER + DUST_DURATION;
146
+ var BACKGROUND_FADE = 0.5;
147
+ var EXIT_DURATION = 1.1;
148
+ var STARS_START = 2.5;
149
+ var STARS_FADE = 2;
150
+ var STAR_DENSITY = 0.018;
151
+ var STAR_TINTS = [
152
+ [255, 255, 255],
153
+ [170, 195, 255],
154
+ [255, 225, 170],
155
+ [255, 190, 205]
156
+ ];
157
+ var LOGO_COLOR_STEP = 5;
158
+ var LIGHT_HALO_STRENGTH = 0.3;
159
+ var HALO_RADIUS_X = 6;
160
+ var HALO_RADIUS_Y = 3;
161
+ var HALO_LEVELS = 32;
162
+ var STAR_ALPHA_LEVELS = 8;
163
+ var STAR_FLICKER_LEVELS = 3;
164
+ var HINT_FADE = 0.5;
165
+ var DOT_BITS = [1, 8, 2, 16, 4, 32, 64, 128];
166
+ var BRAILLE = Array.from({ length: 256 }, (_, bits) => String.fromCharCode(10240 + bits));
167
+ var LIGHT = normalize([-0.45, -0.6, 0.75]);
168
+ var HALF_VECTOR = normalize([LIGHT[0], LIGHT[1], LIGHT[2] + 1]);
169
+ function normalize(v) {
170
+ const length = Math.hypot(v[0], v[1], v[2]);
171
+ return [v[0] / length, v[1] / length, v[2] / length];
172
+ }
173
+ __name(normalize, "normalize");
174
+ function clamp01(value) {
175
+ return value < 0 ? 0 : value > 1 ? 1 : value;
176
+ }
177
+ __name(clamp01, "clamp01");
178
+ function smooth(value) {
179
+ const t = clamp01(value);
180
+ return t * t * t * (t * (t * 6 - 15) + 10);
181
+ }
182
+ __name(smooth, "smooth");
183
+ function easeOut(value) {
184
+ const t = 1 - clamp01(value);
185
+ return 1 - t * t * t;
186
+ }
187
+ __name(easeOut, "easeOut");
188
+ function mix(a, b, amount) {
189
+ return [a[0] + (b[0] - a[0]) * amount, a[1] + (b[1] - a[1]) * amount, a[2] + (b[2] - a[2]) * amount];
190
+ }
191
+ __name(mix, "mix");
192
+ function hash(value) {
193
+ let x = Math.imul(value ^ 2654435769, 2246822507);
194
+ x ^= x >>> 13;
195
+ x = Math.imul(x, 3266489909);
196
+ x ^= x >>> 16;
197
+ return (x >>> 0) / 4294967296;
198
+ }
199
+ __name(hash, "hash");
200
+ function isLight([r, g, b]) {
201
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b > 128;
202
+ }
203
+ __name(isLight, "isLight");
204
+ function toRgb(color) {
205
+ const { r, g, b } = colorToRgb(color);
206
+ return [r, g, b];
207
+ }
208
+ __name(toRgb, "toRgb");
209
+ function glyphInk(text, seed) {
210
+ if (text.trim() === "")
211
+ return 0;
212
+ if (/^[.,:;'`\-_·]$/.test(text))
213
+ return 2;
214
+ if (/^[\u2500-\u257f]$/.test(text))
215
+ return 3;
216
+ return 4 + Math.floor(seed * 3);
217
+ }
218
+ __name(glyphInk, "glyphInk");
219
+ var segmenter = new Intl.Segmenter();
220
+ function parseScreen(lines, width, foreground, background) {
221
+ const palette = /* @__PURE__ */ __name((index) => toRgb(indexedColor(index)), "palette");
222
+ return lines.map((line) => {
223
+ const cells = [];
224
+ let fg;
225
+ let bg;
226
+ let dim = false;
227
+ let inverse = false;
228
+ const applySgr = /* @__PURE__ */ __name((params) => {
229
+ const codes = params === "" ? ["0"] : params.split(";");
230
+ for (let i2 = 0; i2 < codes.length; i2++) {
231
+ const parts = codes[i2].split(":").map((part) => Number.parseInt(part, 10));
232
+ const code = parts[0] ?? 0;
233
+ if (code === 38 || code === 48) {
234
+ let args;
235
+ if (parts.length > 1) {
236
+ args = parts.slice(1).filter((part) => !Number.isNaN(part));
237
+ } else {
238
+ const kind = Number.parseInt(codes[i2 + 1] ?? "", 10);
239
+ const count = kind === 5 ? 2 : kind === 2 ? 4 : 1;
240
+ args = codes.slice(i2 + 1, i2 + 1 + count).map((part) => Number.parseInt(part, 10));
241
+ i2 += count;
242
+ }
243
+ let color;
244
+ if (args[0] === 5 && args[1] !== void 0)
245
+ color = palette(args[1]);
246
+ else if (args[0] === 2 && args.length >= 4)
247
+ color = [args[1], args[2], args[3]];
248
+ if (color) {
249
+ if (code === 38)
250
+ fg = color;
251
+ else
252
+ bg = color;
253
+ }
254
+ } else if (code === 0) {
255
+ fg = void 0;
256
+ bg = void 0;
257
+ dim = false;
258
+ inverse = false;
259
+ } else if (code === 2)
260
+ dim = true;
261
+ else if (code === 22)
262
+ dim = false;
263
+ else if (code === 7)
264
+ inverse = true;
265
+ else if (code === 27)
266
+ inverse = false;
267
+ else if (code >= 30 && code <= 37)
268
+ fg = palette(code - 30);
269
+ else if (code >= 90 && code <= 97)
270
+ fg = palette(code - 90 + 8);
271
+ else if (code === 39)
272
+ fg = void 0;
273
+ else if (code >= 40 && code <= 47)
274
+ bg = palette(code - 40);
275
+ else if (code >= 100 && code <= 107)
276
+ bg = palette(code - 100 + 8);
277
+ else if (code === 49)
278
+ bg = void 0;
279
+ }
280
+ }, "applySgr");
281
+ const pushText = /* @__PURE__ */ __name((text) => {
282
+ for (const { segment } of segmenter.segment(text)) {
283
+ const glyphWidth = visibleWidth(segment);
284
+ if (glyphWidth === 0 || cells.length + glyphWidth > width)
285
+ continue;
286
+ let cellFg = fg ?? foreground;
287
+ let cellBg = bg;
288
+ if (inverse) {
289
+ cellFg = bg ?? background;
290
+ cellBg = fg ?? foreground;
291
+ }
292
+ if (dim)
293
+ cellFg = mix(cellFg, cellBg ?? background, 0.4);
294
+ const cell = { text: segment, width: glyphWidth, fg: cellFg, bg: cellBg, delay: 0, ink: 0, seed: 0 };
295
+ cells.push(cell);
296
+ if (glyphWidth === 2)
297
+ cells.push({ ...cell, text: "", width: 0 });
298
+ }
299
+ }, "pushText");
300
+ let i = 0;
301
+ while (i < line.length) {
302
+ const sequenceStart = line.indexOf("\x1B", i);
303
+ if (sequenceStart === -1) {
304
+ pushText(line.slice(i));
305
+ break;
306
+ }
307
+ if (sequenceStart > i)
308
+ pushText(line.slice(i, sequenceStart));
309
+ const kind = line[sequenceStart + 1];
310
+ if (kind === "[") {
311
+ let end = sequenceStart + 2;
312
+ while (end < line.length && (line.charCodeAt(end) < 64 || line.charCodeAt(end) > 126))
313
+ end++;
314
+ if (line[end] === "m")
315
+ applySgr(line.slice(sequenceStart + 2, end));
316
+ i = end + 1;
317
+ } else if (kind === "]" || kind === "_" || kind === "P" || kind === "^") {
318
+ const bell = line.indexOf("\x07", sequenceStart + 2);
319
+ const st = line.indexOf("\x1B\\", sequenceStart + 2);
320
+ if (bell === -1 && st === -1)
321
+ break;
322
+ i = bell !== -1 && (st === -1 || bell < st) ? bell + 1 : st + 2;
323
+ } else {
324
+ i = sequenceStart + 2;
325
+ }
326
+ }
327
+ return cells;
328
+ });
329
+ }
330
+ __name(parseScreen, "parseScreen");
331
+ function rotation(yaw, pitch, roll) {
332
+ const [sy, cy, sx, cx, sz, cz] = [
333
+ Math.sin(yaw),
334
+ Math.cos(yaw),
335
+ Math.sin(pitch),
336
+ Math.cos(pitch),
337
+ Math.sin(roll),
338
+ Math.cos(roll)
339
+ ];
340
+ const ry = [cy, 0, sy, 0, 1, 0, -sy, 0, cy];
341
+ const rx = [1, 0, 0, 0, cx, -sx, 0, sx, cx];
342
+ const rz = [cz, -sz, 0, sz, cz, 0, 0, 0, 1];
343
+ return multiply(rz, multiply(rx, ry));
344
+ }
345
+ __name(rotation, "rotation");
346
+ function multiply(a, b) {
347
+ const result = new Array(9);
348
+ for (let row = 0; row < 3; row++) {
349
+ for (let column = 0; column < 3; column++) {
350
+ result[row * 3 + column] = a[row * 3] * b[column] + a[row * 3 + 1] * b[3 + column] + a[row * 3 + 2] * b[6 + column];
351
+ }
352
+ }
353
+ return result;
354
+ }
355
+ __name(multiply, "multiply");
356
+ var SPIN_RAMP = 1.4;
357
+ var SPIN_SPEED = Math.PI * 2 / PUZZLE_CYCLE;
358
+ var SPIN_LINGER = 0.6;
359
+ var FIRST_FRONT_VIEW = PUZZLE_START + PUZZLE_STEP * PUZZLE_STEPS + PUZZLE_RETURN + PUZZLE_HOLD / 2;
360
+ function baseSpinPhase(time) {
361
+ const elapsed = time - FLY_START;
362
+ if (elapsed <= 0)
363
+ return 0;
364
+ const u = elapsed / SPIN_RAMP;
365
+ if (u < 1)
366
+ return SPIN_SPEED * SPIN_RAMP * (u ** 6 - 3 * u ** 5 + 2.5 * u ** 4);
367
+ return SPIN_SPEED * (SPIN_RAMP * 0.5 + elapsed - SPIN_RAMP);
368
+ }
369
+ __name(baseSpinPhase, "baseSpinPhase");
370
+ var SPIN_ALIGNMENT = Math.PI * 2 - baseSpinPhase(FIRST_FRONT_VIEW) % (Math.PI * 2);
371
+ function spinPhase(time) {
372
+ return baseSpinPhase(time) + SPIN_ALIGNMENT * smooth((time - FLY_START) / FLY_DURATION);
373
+ }
374
+ __name(spinPhase, "spinPhase");
375
+ function spinAngle(time) {
376
+ const phase = spinPhase(time);
377
+ return phase - SPIN_LINGER * Math.sin(phase);
378
+ }
379
+ __name(spinAngle, "spinAngle");
380
+ var BlockRaster = class {
381
+ static {
382
+ __name(this, "BlockRaster");
383
+ }
384
+ /** Braille dot bits per cell. */
385
+ bits = new Uint8Array(0);
386
+ /** Lit dots per cell. */
387
+ counts = new Uint8Array(0);
388
+ /** Summed RGB of the lit dots per cell. */
389
+ rgb = new Float32Array(0);
390
+ /** Halo tint strength per cell, from 0 to 1. Only set when a halo was requested. */
391
+ haloAmount = new Float32Array(0);
392
+ /** Halo color per cell. */
393
+ haloRgb = new Float32Array(0);
394
+ width = 0;
395
+ height = 0;
396
+ /** Ray parameter of the nearest hit per dot; smaller is nearer. */
397
+ depth = new Float32Array(0);
398
+ /** Face index + 1 of the nearest hit per dot, 0 for none. */
399
+ faceIds = new Uint16Array(0);
400
+ /** Cells written by the previous frame, cleared before the next one. */
401
+ dirty;
402
+ /** Cells with a halo from the previous frame, cleared before the next one. */
403
+ haloDirty;
404
+ cameraDistance;
405
+ constructor(cameraDistance) {
406
+ this.cameraDistance = cameraDistance;
407
+ }
408
+ render(width, height, pose, boxes, background, haloStrength) {
409
+ const dotWidth = width * 2;
410
+ const dotHeight = height * 4;
411
+ if (width !== this.width || height !== this.height) {
412
+ this.width = width;
413
+ this.height = height;
414
+ this.bits = new Uint8Array(width * height);
415
+ this.counts = new Uint8Array(width * height);
416
+ this.rgb = new Float32Array(width * height * 3);
417
+ this.haloAmount = new Float32Array(width * height);
418
+ this.haloRgb = new Float32Array(width * height * 3);
419
+ this.haloDirty = void 0;
420
+ this.depth = new Float32Array(dotWidth * dotHeight).fill(Infinity);
421
+ this.faceIds = new Uint16Array(dotWidth * dotHeight);
422
+ this.dirty = void 0;
423
+ } else if (this.dirty) {
424
+ const { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2 } = this.dirty;
425
+ for (let row = minY2; row <= maxY2; row++) {
426
+ this.bits.fill(0, row * width + minX2, row * width + maxX2 + 1);
427
+ this.counts.fill(0, row * width + minX2, row * width + maxX2 + 1);
428
+ this.rgb.fill(0, (row * width + minX2) * 3, (row * width + maxX2 + 1) * 3);
429
+ }
430
+ this.dirty = void 0;
431
+ }
432
+ if (this.haloDirty) {
433
+ const { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2 } = this.haloDirty;
434
+ for (let row = minY2; row <= maxY2; row++) {
435
+ this.haloAmount.fill(0, row * width + minX2, row * width + maxX2 + 1);
436
+ this.haloRgb.fill(0, (row * width + minX2) * 3, (row * width + maxX2 + 1) * 3);
437
+ }
438
+ this.haloDirty = void 0;
439
+ }
440
+ const m = rotation(pose.yaw, pose.pitch, pose.roll);
441
+ const { centerX, centerY, scale } = pose;
442
+ const cameraDistance = this.cameraDistance;
443
+ const origin = [m[6] * cameraDistance, m[7] * cameraDistance, m[8] * cameraDistance];
444
+ const light = isLight(background);
445
+ const faces = this.visibleFaces(m, origin, pose, boxes, dotWidth, dotHeight, light);
446
+ if (faces.length === 0)
447
+ return;
448
+ let minX = dotWidth;
449
+ let minY = dotHeight;
450
+ let maxX = -1;
451
+ let maxY = -1;
452
+ for (const face of faces) {
453
+ minX = Math.min(minX, face.minX);
454
+ minY = Math.min(minY, face.minY);
455
+ maxX = Math.max(maxX, face.maxX);
456
+ maxY = Math.max(maxY, face.maxY);
457
+ }
458
+ if (maxX < minX || maxY < minY)
459
+ return;
460
+ const depth = this.depth;
461
+ const faceIds = this.faceIds;
462
+ for (let faceIndex = 0; faceIndex < faces.length; faceIndex++) {
463
+ const face = faces[faceIndex];
464
+ const a = face.axis;
465
+ const u = (a + 1) % 3;
466
+ const v = (a + 2) % 3;
467
+ const originA = origin[a];
468
+ const originU = origin[u];
469
+ const originV = origin[v];
470
+ const stepA = m[a] / scale;
471
+ const stepU = m[u] / scale;
472
+ const stepV = m[v] / scale;
473
+ const sx = (face.minX + 0.5 - centerX) / scale;
474
+ for (let dotY = face.minY; dotY <= face.maxY; dotY++) {
475
+ const sy = (dotY + 0.5 - centerY) / scale;
476
+ let directionA = m[a] * sx + m[3 + a] * sy - m[6 + a] * cameraDistance;
477
+ let directionU = m[u] * sx + m[3 + u] * sy - m[6 + u] * cameraDistance;
478
+ let directionV = m[v] * sx + m[3 + v] * sy - m[6 + v] * cameraDistance;
479
+ let index = dotY * dotWidth + face.minX;
480
+ for (let dotX = face.minX; dotX <= face.maxX; dotX++, index++) {
481
+ const t = (face.plane - originA) / directionA;
482
+ if (t > 0 && t < depth[index]) {
483
+ const hitU = originU + t * directionU;
484
+ const hitV = originV + t * directionV;
485
+ if (hitU >= face.uMin && hitU <= face.uMax && hitV >= face.vMin && hitV <= face.vMax) {
486
+ depth[index] = t;
487
+ faceIds[index] = faceIndex + 1;
488
+ }
489
+ }
490
+ directionA += stepA;
491
+ directionU += stepU;
492
+ directionV += stepV;
493
+ }
494
+ }
495
+ }
496
+ const bits = this.bits;
497
+ const counts = this.counts;
498
+ const rgb = this.rgb;
499
+ let cellMinX = width;
500
+ let cellMinY = height;
501
+ let cellMaxX = -1;
502
+ let cellMaxY = -1;
503
+ for (let dotY = minY; dotY <= maxY; dotY++) {
504
+ let index = dotY * dotWidth + minX;
505
+ for (let dotX = minX; dotX <= maxX; dotX++, index++) {
506
+ const id = faceIds[index];
507
+ if (id === 0)
508
+ continue;
509
+ const face = faces[id - 1];
510
+ const fog = clamp01(0.15 - cameraDistance * (1 - depth[index]) * 0.12) * (light ? 0.5 : 1);
511
+ faceIds[index] = 0;
512
+ depth[index] = Infinity;
513
+ const cellX = dotX >> 1;
514
+ const cellY = dotY >> 2;
515
+ const cell = cellY * width + cellX;
516
+ bits[cell] |= DOT_BITS[(dotY & 3) * 2 + (dotX & 1)];
517
+ counts[cell]++;
518
+ rgb[cell * 3] += face.red + (background[0] - face.red) * fog;
519
+ rgb[cell * 3 + 1] += face.green + (background[1] - face.green) * fog;
520
+ rgb[cell * 3 + 2] += face.blue + (background[2] - face.blue) * fog;
521
+ if (cellX < cellMinX)
522
+ cellMinX = cellX;
523
+ if (cellX > cellMaxX)
524
+ cellMaxX = cellX;
525
+ if (cellY < cellMinY)
526
+ cellMinY = cellY;
527
+ if (cellY > cellMaxY)
528
+ cellMaxY = cellY;
529
+ }
530
+ }
531
+ if (cellMaxX >= 0)
532
+ this.dirty = { minX: cellMinX, minY: cellMinY, maxX: cellMaxX, maxY: cellMaxY };
533
+ if (haloStrength > 0)
534
+ this.renderHalo(haloStrength);
535
+ }
536
+ /**
537
+ * Blur the logo's coverage and color over neighboring cells with a separable tent filter, so the tint falls
538
+ * off smoothly past the logo's edges.
539
+ */
540
+ renderHalo(strength) {
541
+ const cells = this.dirty;
542
+ if (!cells)
543
+ return;
544
+ const { width, height, counts, rgb } = this;
545
+ const minX = Math.max(0, cells.minX - HALO_RADIUS_X);
546
+ const maxX = Math.min(width - 1, cells.maxX + HALO_RADIUS_X);
547
+ const minY = Math.max(0, cells.minY - HALO_RADIUS_Y);
548
+ const maxY = Math.min(height - 1, cells.maxY + HALO_RADIUS_Y);
549
+ const regionWidth = maxX - minX + 1;
550
+ const tent = /* @__PURE__ */ __name((radius) => {
551
+ const weights = Array.from({ length: radius * 2 + 1 }, (_, i) => radius + 1 - Math.abs(i - radius));
552
+ const total = weights.reduce((sum, weight) => sum + weight, 0);
553
+ return weights.map((weight) => weight / total);
554
+ }, "tent");
555
+ const weightsX = tent(HALO_RADIUS_X);
556
+ const weightsY = tent(HALO_RADIUS_Y);
557
+ const rows = cells.maxY - cells.minY + 1;
558
+ const horizontal = new Float32Array(rows * regionWidth * 4);
559
+ for (let y = cells.minY; y <= cells.maxY; y++) {
560
+ for (let x = minX; x <= maxX; x++) {
561
+ let coverage = 0;
562
+ let red = 0;
563
+ let green = 0;
564
+ let blue = 0;
565
+ for (let dx = -HALO_RADIUS_X; dx <= HALO_RADIUS_X; dx++) {
566
+ const sourceX = x + dx;
567
+ if (sourceX < cells.minX || sourceX > cells.maxX)
568
+ continue;
569
+ const source = y * width + sourceX;
570
+ const count = counts[source];
571
+ if (count === 0)
572
+ continue;
573
+ const weight = weightsX[dx + HALO_RADIUS_X] / 8;
574
+ coverage += count * weight;
575
+ red += rgb[source * 3] * weight;
576
+ green += rgb[source * 3 + 1] * weight;
577
+ blue += rgb[source * 3 + 2] * weight;
578
+ }
579
+ const target = ((y - cells.minY) * regionWidth + (x - minX)) * 4;
580
+ horizontal[target] = coverage;
581
+ horizontal[target + 1] = red;
582
+ horizontal[target + 2] = green;
583
+ horizontal[target + 3] = blue;
584
+ }
585
+ }
586
+ for (let y = minY; y <= maxY; y++) {
587
+ for (let x = minX; x <= maxX; x++) {
588
+ let coverage = 0;
589
+ let red = 0;
590
+ let green = 0;
591
+ let blue = 0;
592
+ for (let dy = -HALO_RADIUS_Y; dy <= HALO_RADIUS_Y; dy++) {
593
+ const sourceY = y + dy;
594
+ if (sourceY < cells.minY || sourceY > cells.maxY)
595
+ continue;
596
+ const weight = weightsY[dy + HALO_RADIUS_Y];
597
+ const source = ((sourceY - cells.minY) * regionWidth + (x - minX)) * 4;
598
+ coverage += horizontal[source] * weight;
599
+ red += horizontal[source + 1] * weight;
600
+ green += horizontal[source + 2] * weight;
601
+ blue += horizontal[source + 3] * weight;
602
+ }
603
+ const target = y * width + x;
604
+ const count = counts[target];
605
+ if (count > 0 && count / 8 > coverage) {
606
+ coverage = count / 8;
607
+ red = rgb[target * 3] / count * coverage;
608
+ green = rgb[target * 3 + 1] / count * coverage;
609
+ blue = rgb[target * 3 + 2] / count * coverage;
610
+ }
611
+ if (coverage <= 0)
612
+ continue;
613
+ const amount = Math.round(strength * Math.min(1, coverage) ** 0.7 * HALO_LEVELS) / HALO_LEVELS;
614
+ if (amount <= 0)
615
+ continue;
616
+ this.haloAmount[target] = amount;
617
+ this.haloRgb[target * 3] = Math.round(red / coverage / LOGO_COLOR_STEP) * LOGO_COLOR_STEP;
618
+ this.haloRgb[target * 3 + 1] = Math.round(green / coverage / LOGO_COLOR_STEP) * LOGO_COLOR_STEP;
619
+ this.haloRgb[target * 3 + 2] = Math.round(blue / coverage / LOGO_COLOR_STEP) * LOGO_COLOR_STEP;
620
+ }
621
+ }
622
+ this.haloDirty = { minX, minY, maxX, maxY };
623
+ }
624
+ visibleFaces(m, origin, pose, boxes, dotWidth, dotHeight, lightBackground) {
625
+ const faces = [];
626
+ const cameraDistance = this.cameraDistance;
627
+ for (const box of boxes) {
628
+ for (let a = 0; a < 3; a++) {
629
+ const u = (a + 1) % 3;
630
+ const v = (a + 2) % 3;
631
+ for (const side of [-1, 1]) {
632
+ const plane = side > 0 ? box.max[a] : box.min[a];
633
+ if ((origin[a] - plane) * side <= 0)
634
+ continue;
635
+ const covered = boxes.some((other) => other !== box && (side > 0 ? other.min[a] : other.max[a]) === plane && other.min[u] <= box.min[u] && other.max[u] >= box.max[u] && other.min[v] <= box.min[v] && other.max[v] >= box.max[v]);
636
+ if (covered)
637
+ continue;
638
+ let minX = Infinity;
639
+ let minY = Infinity;
640
+ let maxX = -Infinity;
641
+ let maxY = -Infinity;
642
+ const corner = [0, 0, 0];
643
+ for (const cornerU of [box.min[u], box.max[u]]) {
644
+ for (const cornerV of [box.min[v], box.max[v]]) {
645
+ corner[a] = plane;
646
+ corner[u] = cornerU;
647
+ corner[v] = cornerV;
648
+ const x = m[0] * corner[0] + m[1] * corner[1] + m[2] * corner[2];
649
+ const y = m[3] * corner[0] + m[4] * corner[1] + m[5] * corner[2];
650
+ const z = m[6] * corner[0] + m[7] * corner[1] + m[8] * corner[2];
651
+ const perspective = pose.scale * cameraDistance / (cameraDistance - z);
652
+ const screenX = pose.centerX + x * perspective;
653
+ const screenY = pose.centerY + y * perspective;
654
+ minX = Math.min(minX, screenX);
655
+ minY = Math.min(minY, screenY);
656
+ maxX = Math.max(maxX, screenX);
657
+ maxY = Math.max(maxY, screenY);
658
+ }
659
+ }
660
+ const face = {
661
+ minX: Math.max(0, Math.floor(minX)),
662
+ minY: Math.max(0, Math.floor(minY)),
663
+ maxX: Math.min(dotWidth - 1, Math.ceil(maxX)),
664
+ maxY: Math.min(dotHeight - 1, Math.ceil(maxY))
665
+ };
666
+ if (face.maxX < face.minX || face.maxY < face.minY)
667
+ continue;
668
+ const nx = m[a] * side;
669
+ const ny = m[3 + a] * side;
670
+ const nz = m[6 + a] * side;
671
+ const diffuse = Math.max(0, nx * LIGHT[0] + ny * LIGHT[1] + nz * LIGHT[2]);
672
+ const rim = Math.max(0, nx * 0.8 - nz * 0.3);
673
+ const specular = lightBackground ? 0 : Math.max(0, nx * HALF_VECTOR[0] + ny * HALF_VECTOR[1] + nz * HALF_VECTOR[2]) ** 24 * 0.6 * 255;
674
+ const light = lightBackground ? Math.min(1, 0.55 + diffuse * 0.45 + rim * 0.1) : 0.45 + diffuse * 0.78 + rim * 0.25;
675
+ faces.push({
676
+ axis: a,
677
+ plane,
678
+ uMin: box.min[u],
679
+ uMax: box.max[u],
680
+ vMin: box.min[v],
681
+ vMax: box.max[v],
682
+ ...face,
683
+ red: Math.min(255, box.color[0] * light + specular),
684
+ green: Math.min(255, box.color[1] * light + specular),
685
+ blue: Math.min(255, box.color[2] * light + specular)
686
+ });
687
+ }
688
+ }
689
+ }
690
+ return faces;
691
+ }
692
+ };
693
+ var playing = false;
694
+ async function playEasterEgg3d(tui, screen, egg) {
695
+ if (playing)
696
+ return;
697
+ playing = true;
698
+ const reported = await tui.queryTerminalColors({ timeoutMs: 100 });
699
+ const dark = theme.appearance === "dark";
700
+ const toRgbTuple = /* @__PURE__ */ __name((rgb, fallback) => rgb ? [rgb.r, rgb.g, rgb.b] : fallback, "toRgbTuple");
701
+ const colors = {
702
+ foreground: toRgbTuple(reported.foreground, toRgb(theme.colors.text)),
703
+ background: toRgbTuple(reported.background, dark ? [0, 0, 0] : [255, 255, 255])
704
+ };
705
+ if (tui.hasOverlay()) {
706
+ playing = false;
707
+ return;
708
+ }
709
+ const model = egg.kind === "armin" ? arminModel(toRgb(theme.colors.accent)) : piLogoModel({ column: egg.column, row: egg.row });
710
+ const animation = new EasterEgg3dAnimation(tui, screen, model, colors, () => {
711
+ playing = false;
712
+ overlay.hide();
713
+ });
714
+ const overlay = tui.showOverlay(animation, { anchor: "top-left", width: "100%", maxHeight: "100%" });
715
+ }
716
+ __name(playEasterEgg3d, "playEasterEgg3d");
717
+ var EasterEgg3dAnimation = class {
718
+ static {
719
+ __name(this, "EasterEgg3dAnimation");
720
+ }
721
+ tui;
722
+ /** The screen to dissolve, as rendered lines. */
723
+ screen;
724
+ model;
725
+ foreground;
726
+ background;
727
+ onDone;
728
+ startTime = performance.now();
729
+ lastRender = performance.now();
730
+ timer;
731
+ exit;
732
+ shuffle;
733
+ screenWidth = -1;
734
+ screenHeight = -1;
735
+ /** Star per cell index, or undefined. */
736
+ stars = [];
737
+ cells = [];
738
+ ansiCache = /* @__PURE__ */ new Map();
739
+ raster;
740
+ constructor(tui, screen, model, colors, onDone) {
741
+ this.tui = tui;
742
+ this.screen = screen;
743
+ this.model = model;
744
+ this.raster = new BlockRaster(model.cameraDistance);
745
+ this.foreground = colors.foreground;
746
+ this.background = colors.background;
747
+ this.onDone = onDone;
748
+ this.timer = setInterval(() => {
749
+ if (this.exit && this.exitProgress() >= 1 || performance.now() - this.lastRender > 1e3)
750
+ this.finish();
751
+ else
752
+ this.tui.requestRender();
753
+ }, FRAME_MS);
754
+ this.timer.unref?.();
755
+ }
756
+ /** Play the exit animation. A second call skips it. */
757
+ close() {
758
+ if (this.exit) {
759
+ this.finish();
760
+ return;
761
+ }
762
+ const time = this.elapsed();
763
+ const yaw = spinAngle(time);
764
+ const turn = Math.PI * 2;
765
+ this.exit = {
766
+ start: performance.now(),
767
+ time,
768
+ yaw,
769
+ targetYaw: Math.ceil(yaw / turn) * turn,
770
+ offsets: this.blockOffsets(time)
771
+ };
772
+ }
773
+ handleInput(data) {
774
+ const keybindings = getKeybindings();
775
+ if (keybindings.matches(data, "tui.select.cancel") || keybindings.matches(data, "app.clear"))
776
+ this.close();
777
+ }
778
+ handleMouse(event) {
779
+ if (event.type === "click")
780
+ this.close();
781
+ return { handled: true, render: false };
782
+ }
783
+ invalidate() {
784
+ this.screenWidth = -1;
785
+ this.screenHeight = -1;
786
+ this.ansiCache.clear();
787
+ }
788
+ render(width) {
789
+ const height = Math.max(1, this.tui.terminal.rows);
790
+ const foreground = this.foreground;
791
+ const background = this.background;
792
+ this.lastRender = performance.now();
793
+ if (width !== this.screenWidth || height !== this.screenHeight) {
794
+ this.screenWidth = width;
795
+ this.screenHeight = height;
796
+ this.cells = this.prepareCells(width, foreground);
797
+ this.stars = this.prepareStars(width, height);
798
+ }
799
+ let dissolveTime;
800
+ let pose;
801
+ let hintAlpha;
802
+ let starAlpha;
803
+ let offsets;
804
+ if (this.exit) {
805
+ const progress = this.exitProgress();
806
+ const landing = clamp01(progress / 0.8);
807
+ const settle = 1 - smooth(landing);
808
+ dissolveTime = Math.min(this.exit.time, DISSOLVE_END) * (1 - progress);
809
+ pose = this.pose(width, height, this.flyProgress(this.exit.time) * settle, this.exit.time);
810
+ pose.yaw = this.exit.yaw + (this.exit.targetYaw - this.exit.yaw) * easeOut(landing);
811
+ pose.pitch *= settle;
812
+ pose.roll *= settle;
813
+ hintAlpha = this.hintAlpha(this.exit.time) * (1 - smooth(progress / 0.2));
814
+ starAlpha = this.starAlpha(this.exit.time) * (1 - smooth(progress / 0.3));
815
+ const gather = 1 - smooth(progress / 0.5);
816
+ offsets = this.exit.offsets.map(([x, y, z]) => [x * gather, y * gather, z * gather]);
817
+ } else {
818
+ const time = this.elapsed();
819
+ dissolveTime = time;
820
+ pose = this.pose(width, height, this.flyProgress(time), time);
821
+ hintAlpha = this.hintAlpha(time);
822
+ starAlpha = this.starAlpha(time);
823
+ offsets = this.blockOffsets(time);
824
+ }
825
+ const { columns, rows } = this.model;
826
+ const boxes = this.model.blocks.map((block, index) => {
827
+ const [dx, dy, dz] = offsets[index];
828
+ const x = block.home[0] - columns / 2 + dx;
829
+ const y = block.home[1] - rows / 2 + dy;
830
+ return { min: [x, y, dz - DEPTH / 2], max: [x + 1, y + 1, dz + DEPTH / 2], color: block.color };
831
+ });
832
+ const raster = this.raster;
833
+ raster.render(width, height, pose, boxes, background, isLight(background) ? LIGHT_HALO_STRENGTH : 0);
834
+ const halo = /* @__PURE__ */ __name((index, base) => {
835
+ const amount = raster.haloAmount[index];
836
+ if (amount <= 0)
837
+ return base;
838
+ const color = raster.haloRgb;
839
+ return mix(base ?? background, [color[index * 3], color[index * 3 + 1], color[index * 3 + 2]], amount);
840
+ }, "halo");
841
+ const backgroundFade = smooth(dissolveTime / BACKGROUND_FADE);
842
+ const textFade = smooth(dissolveTime / 0.6) * 0.3;
843
+ const textActive = dissolveTime < DISSOLVE_END || backgroundFade < 1;
844
+ const hint = this.hint(width, height, hintAlpha, background);
845
+ const frame = Math.floor(dissolveTime * 14);
846
+ const now = this.elapsed();
847
+ const starLevel = Math.round(starAlpha * STAR_ALPHA_LEVELS) / STAR_ALPHA_LEVELS;
848
+ const starfield = /* @__PURE__ */ __name((index) => {
849
+ if (starLevel <= 0)
850
+ return void 0;
851
+ const star = this.stars[index];
852
+ if (!star)
853
+ return void 0;
854
+ const flicker = Math.round((0.5 + 0.5 * Math.sin(now * star.speed + star.phase)) * STAR_FLICKER_LEVELS) / STAR_FLICKER_LEVELS;
855
+ return {
856
+ text: star.glyph,
857
+ fg: mix(background, mix(foreground, star.tint, 0.5), star.strength * (0.7 + 0.3 * flicker) * starLevel)
858
+ };
859
+ }, "starfield");
860
+ const lines = [];
861
+ for (let row = 0; row < height; row++) {
862
+ const cells = this.cells[row] ?? [];
863
+ let line = "";
864
+ let currentFg = -1;
865
+ let currentBg = -1;
866
+ const emit = /* @__PURE__ */ __name((text, fg, bg) => {
867
+ const fgKey = fg ? this.pack(fg) : -1;
868
+ const bgKey = bg ? this.pack(bg) : -1;
869
+ if (fgKey !== currentFg && text !== " ") {
870
+ line += fg ? this.ansi(fgKey, false) : "\x1B[39m";
871
+ currentFg = fgKey;
872
+ }
873
+ if (bgKey !== currentBg) {
874
+ line += bg ? this.ansi(bgKey, true) : "\x1B[49m";
875
+ currentBg = bgKey;
876
+ }
877
+ line += text;
878
+ }, "emit");
879
+ for (let column = 0; column < width; column++) {
880
+ const index = row * width + column;
881
+ const cell = textActive ? cells[column] : void 0;
882
+ const cellBg = halo(index, cell?.bg && backgroundFade < 1 ? mix(cell.bg, background, backgroundFade) : void 0);
883
+ if (hint && row === hint.row && column >= hint.start && column < hint.start + hint.text.length) {
884
+ const offset = column - hint.start;
885
+ emit(hint.text[offset], offset < hint.keyLength ? hint.keyColor : hint.color, cellBg);
886
+ continue;
887
+ }
888
+ const dots = raster.bits[index];
889
+ if (dots) {
890
+ const step = LOGO_COLOR_STEP * raster.counts[index];
891
+ const rgb = raster.rgb;
892
+ const color = [
893
+ Math.round(rgb[index * 3] / step) * LOGO_COLOR_STEP,
894
+ Math.round(rgb[index * 3 + 1] / step) * LOGO_COLOR_STEP,
895
+ Math.round(rgb[index * 3 + 2] / step) * LOGO_COLOR_STEP
896
+ ];
897
+ emit(BRAILLE[dots], color, cellBg);
898
+ continue;
899
+ }
900
+ if (!cell) {
901
+ const star = starfield(index);
902
+ emit(star?.text ?? " ", star?.fg, cellBg);
903
+ continue;
904
+ }
905
+ const dust = (dissolveTime - cell.delay) / DUST_DURATION;
906
+ if (dust < 0 && cell.width === 2 && !raster.bits[index + 1]) {
907
+ emit(cell.text, mix(cell.fg, background, textFade), cellBg);
908
+ column++;
909
+ continue;
910
+ }
911
+ if (dust < 0 && cell.width === 1) {
912
+ emit(cell.text, mix(cell.fg, background, textFade), cellBg);
913
+ continue;
914
+ }
915
+ const dotCount = dust < 0 ? cell.ink : Math.round(cell.ink * (1 - clamp01(dust)));
916
+ if (dotCount <= 0) {
917
+ const star = starfield(index);
918
+ emit(star?.text ?? " ", star?.fg, cellBg);
919
+ continue;
920
+ }
921
+ let bits = 0;
922
+ let placed = 0;
923
+ for (let attempt = 0; placed < dotCount && attempt < 32; attempt++) {
924
+ const bit = DOT_BITS[Math.floor(hash(cell.seed * 7919 + frame * 131 + attempt) * 8)];
925
+ if (bits & bit)
926
+ continue;
927
+ bits |= bit;
928
+ placed++;
929
+ }
930
+ const fade = textFade + (1 - textFade) * clamp01(dust) ** 0.8;
931
+ emit(BRAILLE[bits], mix(cell.fg, background, fade), cellBg);
932
+ }
933
+ lines.push(`${line}\x1B[0m`);
934
+ }
935
+ return lines;
936
+ }
937
+ elapsed() {
938
+ return (performance.now() - this.startTime) / 1e3;
939
+ }
940
+ exitProgress() {
941
+ return this.exit ? clamp01((performance.now() - this.exit.start) / 1e3 / EXIT_DURATION) : 0;
942
+ }
943
+ finish() {
944
+ if (!this.timer)
945
+ return;
946
+ clearInterval(this.timer);
947
+ this.timer = void 0;
948
+ this.onDone();
949
+ }
950
+ /** Each block's displacement from its place in the model at `time`, in grid units. */
951
+ blockOffsets(time) {
952
+ const blocks = this.model.blocks;
953
+ const home = /* @__PURE__ */ __name(() => blocks.map(() => [0, 0, 0]), "home");
954
+ if (time < PUZZLE_START)
955
+ return home();
956
+ const cycle = Math.floor((time - PUZZLE_START) / PUZZLE_CYCLE);
957
+ const local = time - PUZZLE_START - cycle * PUZZLE_CYCLE;
958
+ if (this.shuffle?.cycle !== cycle)
959
+ this.shuffle = { cycle, steps: shuffleSteps(this.model, cycle) };
960
+ const steps = this.shuffle.steps;
961
+ const offset = /* @__PURE__ */ __name((position, index) => {
962
+ const block = blocks[index].home;
963
+ return [position[0] - block[0], position[1] - block[1], position[2] - block[2]];
964
+ }, "offset");
965
+ const shuffleEnd = PUZZLE_STEP * PUZZLE_STEPS;
966
+ if (local < shuffleEnd) {
967
+ const step = Math.floor(local / PUZZLE_STEP);
968
+ const progress = smooth((local - step * PUZZLE_STEP) / PUZZLE_STEP);
969
+ return steps[step].map((from, index) => {
970
+ const a = offset(from, index);
971
+ const b = offset(steps[step + 1][index], index);
972
+ return [a[0] + (b[0] - a[0]) * progress, a[1] + (b[1] - a[1]) * progress, a[2] + (b[2] - a[2]) * progress];
973
+ });
974
+ }
975
+ if (local < shuffleEnd + PUZZLE_RETURN) {
976
+ const u = (local - shuffleEnd) / PUZZLE_RETURN;
977
+ const remaining = 1 - smooth(u);
978
+ const arc = Math.sin(Math.PI * clamp01(u)) * 0.8;
979
+ return steps[PUZZLE_STEPS].map((position, index) => {
980
+ const [x, y, z] = offset(position, index);
981
+ return [x * remaining, y * remaining, z * remaining + (index % 2 === 0 ? arc : -arc)];
982
+ });
983
+ }
984
+ return home();
985
+ }
986
+ flyProgress(time) {
987
+ return smooth((time - FLY_START) / FLY_DURATION);
988
+ }
989
+ starAlpha(time) {
990
+ return smooth((time - STARS_START) / STARS_FADE);
991
+ }
992
+ hintAlpha(time) {
993
+ return smooth((time - FLY_START - FLY_DURATION) / HINT_FADE);
994
+ }
995
+ pose(width, height, progress, time) {
996
+ const { columns, rows, cameraDistance, radius, widthShare, origin } = this.model;
997
+ const reach = radius * (cameraDistance / (cameraDistance - radius));
998
+ const startScale = origin ? 2 * (cameraDistance - DEPTH / 2) / cameraDistance : START_SCALE;
999
+ const endScale = Math.max(startScale, Math.min(width * 2 * widthShare, (height * 4 - 8) * 0.48) / reach);
1000
+ const endX = width;
1001
+ const endY = height * 2 - 2;
1002
+ const startX = origin ? origin.column * 2 + columns : endX;
1003
+ const startY = origin ? origin.row * 4 + rows : endY;
1004
+ return {
1005
+ centerX: startX + (endX - startX) * progress,
1006
+ centerY: startY + (endY - startY) * progress,
1007
+ // Interpolate the zoom geometrically so it feels uniform.
1008
+ scale: startScale * (endScale / startScale) ** progress,
1009
+ yaw: spinAngle(time),
1010
+ // Tilts are zero at whole turns, so the camera looks straight at the front of the reassembled logo.
1011
+ pitch: 0.3 * Math.sin(spinPhase(time)) * progress,
1012
+ roll: 0.06 * Math.sin(2 * spinPhase(time)) * progress
1013
+ };
1014
+ }
1015
+ hint(width, height, alpha, background) {
1016
+ if (alpha <= 0)
1017
+ return void 0;
1018
+ const key = formatKeyText(getKeybindings().getKeys("tui.select.cancel")[0] ?? "escape");
1019
+ const text = `${key} to return`;
1020
+ if (text.length > width)
1021
+ return void 0;
1022
+ return {
1023
+ row: height - 2,
1024
+ start: Math.floor((width - text.length) / 2),
1025
+ text,
1026
+ keyLength: key.length,
1027
+ keyColor: mix(background, toRgb(theme.colors.muted), alpha),
1028
+ color: mix(background, toRgb(theme.colors.dim), alpha)
1029
+ };
1030
+ }
1031
+ /** A sparse, deterministic starfield: one braille dot in about STAR_DENSITY of all cells. */
1032
+ prepareStars(width, height) {
1033
+ const stars = new Array(width * height);
1034
+ for (let index = 0; index < width * height; index++) {
1035
+ if (hash(index * 3 + 20973) >= STAR_DENSITY)
1036
+ continue;
1037
+ const random = /* @__PURE__ */ __name((salt) => hash(index * 7 + salt * 40503), "random");
1038
+ stars[index] = {
1039
+ glyph: BRAILLE[DOT_BITS[Math.floor(random(1) * 8)]],
1040
+ tint: STAR_TINTS[Math.floor(random(2) * STAR_TINTS.length)],
1041
+ strength: 0.1 + random(3) * 0.12,
1042
+ phase: random(4) * Math.PI * 2,
1043
+ speed: 0.4 + random(5) * 0.8
1044
+ };
1045
+ }
1046
+ return stars;
1047
+ }
1048
+ prepareCells(width, foreground) {
1049
+ const cells = parseScreen(this.screen, width, foreground, this.background);
1050
+ const height = Math.max(1, this.tui.terminal.rows);
1051
+ const { columns, rows, origin } = this.model;
1052
+ const centerX = origin ? origin.column + columns / 2 : width / 2;
1053
+ const centerY = origin ? origin.row + rows / 4 : height / 2;
1054
+ const farthest = Math.hypot(Math.max(centerX, width - centerX), Math.max(centerY, height - centerY) * 2);
1055
+ for (let row = 0; row < cells.length; row++) {
1056
+ const line = cells[row];
1057
+ for (let column = 0; column < line.length; column++) {
1058
+ const cell = line[column];
1059
+ const owner = cell.width === 0 ? line[column - 1] : cell;
1060
+ const seed = hash(row * 65537 + column);
1061
+ if (cell.width !== 0) {
1062
+ const distance = Math.hypot(column - centerX, (row - centerY) * 2) / farthest;
1063
+ cell.delay = FLY_START + distance * WAVE_SPREAD + seed * WAVE_JITTER;
1064
+ } else {
1065
+ cell.delay = owner.delay;
1066
+ }
1067
+ cell.seed = row * 65537 + column;
1068
+ cell.ink = glyphInk(owner.text, seed);
1069
+ }
1070
+ }
1071
+ if (origin) {
1072
+ for (let row = origin.row; row < origin.row + Math.ceil(rows / 2); row++) {
1073
+ const line = cells[row];
1074
+ if (!line)
1075
+ continue;
1076
+ for (let column = origin.column; column < origin.column + columns; column++) {
1077
+ const cell = line[column];
1078
+ if (cell) {
1079
+ cell.text = " ";
1080
+ cell.width = 1;
1081
+ cell.ink = 0;
1082
+ cell.bg = void 0;
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+ return cells;
1088
+ }
1089
+ pack(color) {
1090
+ return Math.round(color[0]) << 16 | Math.round(color[1]) << 8 | Math.round(color[2]);
1091
+ }
1092
+ ansi(key, isBackground) {
1093
+ const cacheKey = key * 2 + (isBackground ? 1 : 0);
1094
+ let value = this.ansiCache.get(cacheKey);
1095
+ if (value === void 0) {
1096
+ const color = rgbColor(key >> 16 & 255, key >> 8 & 255, key & 255);
1097
+ const mode = theme.getColorMode();
1098
+ value = isBackground ? backgroundAnsi(color, mode) : foregroundAnsi(color, mode);
1099
+ this.ansiCache.set(cacheKey, value);
1100
+ }
1101
+ return value;
1102
+ }
1103
+ };
1104
+ export {
1105
+ EasterEgg3dAnimation,
1106
+ playEasterEgg3d
1107
+ };