@heyramzi/ui 2.9.0 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/dist/agents/helpers.js +52 -0
  2. package/dist/agents/index.js +3 -0
  3. package/dist/agents/page-state.js +65 -0
  4. package/dist/agents/types.js +1 -0
  5. package/dist/agents/vendor/color.js +149 -0
  6. package/dist/agents/vendor/draw.js +548 -0
  7. package/dist/agents/vendor/engine.js +632 -0
  8. package/dist/agents/vendor/mesh.js +727 -0
  9. package/dist/agents/vendor/plastic.js +3273 -0
  10. package/dist/agents/vendor/presets.js +171 -0
  11. package/dist/agents/vendor/shapes.js +24 -0
  12. package/dist/agents/vendor/ticker.js +56 -0
  13. package/dist/agents/vendor/types.js +0 -0
  14. package/dist/agents/vendor/wear.js +1525 -0
  15. package/dist/ai/ai-button/index.js +2 -0
  16. package/dist/ai/confirmation/confirmation-context.svelte.js +12 -0
  17. package/dist/ai/confirmation/index.js +9 -0
  18. package/dist/ai/generation-progress/index.js +2 -0
  19. package/dist/ai/index.js +11 -0
  20. package/dist/ai/loading-state/index.js +3 -0
  21. package/dist/ai/prompt-input/index.js +6 -0
  22. package/dist/ai/reasoning/index.js +4 -0
  23. package/dist/ai/reasoning/reasoning-context.svelte.js +12 -0
  24. package/dist/ai/response/index.js +3 -0
  25. package/dist/ai/suggestion/index.js +3 -0
  26. package/dist/ai/thinking-dots/index.js +3 -0
  27. package/dist/ai/typing-dots/index.js +2 -0
  28. package/dist/ai/voice-waveform/index.js +3 -0
  29. package/dist/animations/text-swap.js +30 -0
  30. package/dist/brand/index.js +65 -0
  31. package/dist/canvas/card/resize.js +10 -0
  32. package/dist/canvas/edges/edge-path.js +284 -0
  33. package/dist/canvas/editor/context-menu.js +42 -0
  34. package/dist/canvas/editor/dispatch.svelte.js +157 -0
  35. package/dist/canvas/editor/editor-context.js +8 -0
  36. package/dist/canvas/editor/editor-mode.js +0 -0
  37. package/dist/canvas/editor/frame.js +87 -0
  38. package/dist/canvas/editor/hand-context.js +8 -0
  39. package/dist/canvas/editor/history-core.js +221 -0
  40. package/dist/canvas/editor/keymap.js +193 -0
  41. package/dist/canvas/editor/layout-actions.js +170 -0
  42. package/dist/canvas/editor/lock.js +65 -0
  43. package/dist/canvas/editor/rebase.js +279 -0
  44. package/dist/canvas/editor/style.js +174 -0
  45. package/dist/canvas/editor/text-field-context.js +8 -0
  46. package/dist/canvas/editor/z-order.js +82 -0
  47. package/dist/canvas/headless/alignment.js +20 -0
  48. package/dist/canvas/headless/break-apart-find.js +324 -0
  49. package/dist/canvas/headless/break-apart-pieces.js +74 -0
  50. package/dist/canvas/headless/break-apart-plan.js +378 -0
  51. package/dist/canvas/headless/break-apart-style.js +93 -0
  52. package/dist/canvas/headless/break-apart.js +206 -0
  53. package/dist/canvas/headless/canvas-cleanup.js +70 -0
  54. package/dist/canvas/headless/edge-anchors.js +134 -0
  55. package/dist/canvas/headless/edge-memo.js +28 -0
  56. package/dist/canvas/headless/edge-serialization.js +31 -0
  57. package/dist/canvas/headless/figure-geometry.js +331 -0
  58. package/dist/canvas/headless/fit-viewport.js +82 -0
  59. package/dist/canvas/headless/grid.js +96 -0
  60. package/dist/canvas/headless/icon-node.js +45 -0
  61. package/dist/canvas/headless/index.js +1 -0
  62. package/dist/canvas/headless/linkify.js +25 -0
  63. package/dist/canvas/headless/pen-marks.js +115 -0
  64. package/dist/canvas/headless/sketch.js +250 -0
  65. package/dist/canvas/headless/snap-guides.js +100 -0
  66. package/dist/canvas/headless/svg-figure.js +137 -0
  67. package/dist/canvas/headless/table-layout.js +161 -0
  68. package/dist/canvas/index.js +25 -0
  69. package/dist/canvas/lod/lod-mode.svelte.js +22 -0
  70. package/dist/canvas/lod/render-all.svelte.js +45 -0
  71. package/dist/canvas/ops/arrange.js +83 -0
  72. package/dist/canvas/ops/ops.js +318 -0
  73. package/dist/canvas/pen/colors.js +41 -0
  74. package/dist/canvas/pen/eraser.js +35 -0
  75. package/dist/canvas/pen/geometry.js +143 -0
  76. package/dist/canvas/pen/index.js +9 -0
  77. package/dist/canvas/pen/ops.js +15 -0
  78. package/dist/canvas/pen/pen-session.js +171 -0
  79. package/dist/canvas/pen/plugin.js +129 -0
  80. package/dist/canvas/pen/shapes.js +80 -0
  81. package/dist/canvas/pen/stroke-path.js +37 -0
  82. package/dist/canvas/pen/types.js +30 -0
  83. package/dist/canvas/pen/ui.js +20 -0
  84. package/dist/canvas/plugin.js +51 -0
  85. package/dist/canvas/screen/glyphs.js +24 -0
  86. package/dist/canvas/screen/labels.js +24 -0
  87. package/dist/canvas/screen/parts.js +140 -0
  88. package/dist/canvas/screen/plugin.js +71 -0
  89. package/dist/canvas/screen/types.js +44 -0
  90. package/dist/canvas/screen/ui.js +13 -0
  91. package/dist/canvas/test-utils.js +18 -0
  92. package/dist/canvas/types.js +0 -0
  93. package/dist/canvas/ui/forward-wheel.js +27 -0
  94. package/dist/canvas/ui/icons.js +133 -0
  95. package/dist/canvas/ui/place-panel.js +57 -0
  96. package/dist/canvas/ui/shortcut-tip.js +18 -0
  97. package/dist/canvas/ui/tools.js +411 -0
  98. package/dist/charts/dashboard/chart.js +1 -0
  99. package/dist/charts/dashboard/data-table.js +7 -0
  100. package/dist/charts/dashboard/index.js +13 -0
  101. package/dist/charts/dashboard/windows.js +5 -0
  102. package/dist/charts/edge-fade.js +7 -0
  103. package/dist/charts/hover-band.js +13 -0
  104. package/dist/charts/index.js +19 -0
  105. package/dist/charts/motion.js +15 -0
  106. package/dist/charts/primitives/chart-utils.js +22 -0
  107. package/dist/charts/primitives/index.js +4 -0
  108. package/dist/components/copy/clipboard.js +38 -0
  109. package/dist/components/copy/copied.svelte.js +26 -0
  110. package/dist/components/copy/index.js +3 -0
  111. package/dist/components/data-table/data-table.js +55 -0
  112. package/dist/components/data-table/index.js +7 -0
  113. package/dist/components/docs/index.js +3 -0
  114. package/dist/components/docs/scroll-spy.svelte.js +71 -0
  115. package/dist/components/field-row/index.js +1 -0
  116. package/dist/components/hold-to-confirm/index.js +1 -0
  117. package/dist/components/icon/index.js +1 -0
  118. package/dist/components/language-flag/index.js +1 -0
  119. package/dist/components/list-page/filter-section.js +4 -0
  120. package/dist/components/list-page/index.js +25 -0
  121. package/dist/components/list-page/list-table.js +5 -0
  122. package/dist/components/list-page/queue-rail.js +3 -0
  123. package/dist/components/list-page/section-host.js +8 -0
  124. package/dist/components/list-page/step.js +5 -0
  125. package/dist/components/list-page/types.js +0 -0
  126. package/dist/components/locale-switch/index.js +1 -0
  127. package/dist/components/mark/index.js +1 -0
  128. package/dist/components/open-in/index.js +1 -0
  129. package/dist/components/picker/index.js +3 -0
  130. package/dist/components/picker/trigger.js +33 -0
  131. package/dist/components/picker/types.js +0 -0
  132. package/dist/components/section-card/index.js +1 -0
  133. package/dist/components/section-header/index.js +2 -0
  134. package/dist/components/segmented/collapse.js +32 -0
  135. package/dist/components/segmented/index.js +8 -0
  136. package/dist/components/segmented/segmented.js +50 -0
  137. package/dist/components/star-rating-input/index.js +2 -0
  138. package/dist/components/svg/index.js +1 -0
  139. package/dist/components/table-view/index.js +1 -0
  140. package/dist/components/table-view/types.js +0 -0
  141. package/dist/components/tags-input/index.js +2 -0
  142. package/dist/components/tags-input/tags.js +90 -0
  143. package/dist/components/theme/index.js +3 -0
  144. package/dist/components/toolbar/index.js +3 -0
  145. package/dist/components/toolbar/toolbar-trigger.js +4 -0
  146. package/dist/editor/anchors.js +17 -0
  147. package/dist/editor/block-id.js +62 -0
  148. package/dist/editor/block-ops.js +105 -0
  149. package/dist/editor/doc-blocks.js +181 -0
  150. package/dist/editor/extensions.js +200 -0
  151. package/dist/editor/index.js +4 -0
  152. package/dist/editor/markdown-test-helpers.js +6 -0
  153. package/dist/editor/markdown.js +486 -0
  154. package/dist/editor/serializer.js +268 -0
  155. package/dist/editor/slash-items.js +104 -0
  156. package/dist/editor/youtube-url.js +27 -0
  157. package/dist/effects/animated-beam/index.js +1 -0
  158. package/dist/effects/animated-beam/path-calculator.svelte.js +42 -0
  159. package/dist/effects/animated-beam/types.js +0 -0
  160. package/dist/effects/border-beam/css.js +420 -0
  161. package/dist/effects/border-beam/presets.js +1792 -0
  162. package/dist/effects/border-beam/register-properties.js +39 -0
  163. package/dist/effects/border-beam/types.js +0 -0
  164. package/dist/effects/image-comparison/compare.js +4 -0
  165. package/dist/effects/image-reveal/index.js +1 -0
  166. package/dist/effects/image-reveal/types.js +0 -0
  167. package/dist/effects/magnetic/magnetic.js +54 -0
  168. package/dist/effects/reveal/index.js +4 -0
  169. package/dist/effects/reveal/observe.js +43 -0
  170. package/dist/effects/reveal/types.js +0 -0
  171. package/dist/effects/shader-gradient/color.js +34 -0
  172. package/dist/effects/shader-gradient/index.js +1 -0
  173. package/dist/effects/shader-gradient/renderer.js +320 -0
  174. package/dist/effects/shader-gradient/shaders.js +280 -0
  175. package/dist/effects/shader-gradient/types.js +0 -0
  176. package/dist/icons/apple-symbol-exports.js +126 -0
  177. package/dist/icons/sf-symbols.js +465 -0
  178. package/dist/icons/trades.js +34 -0
  179. package/dist/inbox/index.js +4 -0
  180. package/dist/inbox/logic.js +156 -0
  181. package/dist/inbox/types.js +46 -0
  182. package/dist/index.js +18 -0
  183. package/dist/lib/arrive.js +13 -0
  184. package/dist/lib/icon-types.js +0 -0
  185. package/dist/lib/initials.js +17 -0
  186. package/dist/lib/layout.js +1 -0
  187. package/dist/lib/panel.js +3 -0
  188. package/dist/lib/result.js +26 -0
  189. package/dist/lib/sliding-pill.js +45 -0
  190. package/dist/lib/theme-transition.js +53 -0
  191. package/dist/lib/tone.js +32 -0
  192. package/dist/lib/utils.js +5 -0
  193. package/dist/onboarding/define-tours.js +28 -0
  194. package/dist/onboarding/index.js +4 -0
  195. package/dist/onboarding/onboarding.svelte.js +15 -0
  196. package/dist/onboarding/pick.js +16 -0
  197. package/dist/onboarding/stores.js +50 -0
  198. package/dist/onboarding/types.js +1 -0
  199. package/dist/onboarding/wait.js +25 -0
  200. package/dist/panel/index.js +1 -0
  201. package/dist/panel/side-panel-types.js +0 -0
  202. package/dist/record/demo-data.js +512 -0
  203. package/dist/record/fields.js +148 -0
  204. package/dist/record/format.js +97 -0
  205. package/dist/record/gutter.js +1 -0
  206. package/dist/record/index.js +15 -0
  207. package/dist/record/kinds.js +110 -0
  208. package/dist/record/logic.js +255 -0
  209. package/dist/record/types.js +52 -0
  210. package/dist/shadcn/accordion/index.js +5 -0
  211. package/dist/shadcn/alert/index.js +5 -0
  212. package/dist/shadcn/alert-dialog/index.js +12 -0
  213. package/dist/shadcn/attachment/index.js +10 -0
  214. package/dist/shadcn/avatar/index.js +7 -0
  215. package/dist/shadcn/badge/index.js +2 -0
  216. package/dist/shadcn/breadcrumb/index.js +8 -0
  217. package/dist/shadcn/bubble/index.js +5 -0
  218. package/dist/shadcn/button/index.js +2 -0
  219. package/dist/shadcn/calendar/index.js +19 -0
  220. package/dist/shadcn/card/index.js +8 -0
  221. package/dist/shadcn/checkbox/index.js +2 -0
  222. package/dist/shadcn/code-block/index.js +9 -0
  223. package/dist/shadcn/collapsible/index.js +4 -0
  224. package/dist/shadcn/command/index.js +13 -0
  225. package/dist/shadcn/context-menu/index.js +17 -0
  226. package/dist/shadcn/dialog/index.js +11 -0
  227. package/dist/shadcn/dropdown-menu/index.js +19 -0
  228. package/dist/shadcn/dropdown-menu/menu-item.js +23 -0
  229. package/dist/shadcn/empty/index.js +7 -0
  230. package/dist/shadcn/field/index.js +12 -0
  231. package/dist/shadcn/hooks/highlighter.js +92 -0
  232. package/dist/shadcn/hooks/is-mobile.svelte.js +7 -0
  233. package/dist/shadcn/hooks/use-highlighted-code.svelte.js +65 -0
  234. package/dist/shadcn/hover-card/index.js +5 -0
  235. package/dist/shadcn/input/index.js +3 -0
  236. package/dist/shadcn/input-otp/index.js +5 -0
  237. package/dist/shadcn/kbd/index.js +3 -0
  238. package/dist/shadcn/label/index.js +2 -0
  239. package/dist/shadcn/marker/index.js +4 -0
  240. package/dist/shadcn/message/index.js +7 -0
  241. package/dist/shadcn/message-scroller/index.js +8 -0
  242. package/dist/shadcn/popover/index.js +9 -0
  243. package/dist/shadcn/progress/index.js +2 -0
  244. package/dist/shadcn/progress/tone.js +11 -0
  245. package/dist/shadcn/radio-group/index.js +3 -0
  246. package/dist/shadcn/scroll-area/index.js +3 -0
  247. package/dist/shadcn/select/index.js +12 -0
  248. package/dist/shadcn/separator/index.js +2 -0
  249. package/dist/shadcn/sheet/index.js +11 -0
  250. package/dist/shadcn/sidebar/constants.js +6 -0
  251. package/dist/shadcn/sidebar/context.svelte.js +38 -0
  252. package/dist/shadcn/sidebar/index.js +25 -0
  253. package/dist/shadcn/skeleton/index.js +2 -0
  254. package/dist/shadcn/slider/index.js +2 -0
  255. package/dist/shadcn/sonner/index.js +1 -0
  256. package/dist/shadcn/spinner/index.js +1 -0
  257. package/dist/shadcn/switch/index.js +2 -0
  258. package/dist/shadcn/table/index.js +9 -0
  259. package/dist/shadcn/tabs/index.js +5 -0
  260. package/dist/shadcn/textarea/index.js +2 -0
  261. package/dist/shadcn/toggle/index.js +3 -0
  262. package/dist/shadcn/toggle-group/index.js +3 -0
  263. package/dist/shadcn/tooltip/context.js +8 -0
  264. package/dist/shadcn/tooltip/index.js +6 -0
  265. package/dist/shadcn/trace/index.js +9 -0
  266. package/dist/slides/bridges.js +66 -0
  267. package/dist/slides/deck-controller.svelte.js +221 -0
  268. package/dist/slides/export/capture.js +81 -0
  269. package/dist/slides/export/ffmpeg.js +85 -0
  270. package/dist/slides/export/index.js +4 -0
  271. package/dist/slides/export/launch.js +8 -0
  272. package/dist/slides/export/pdf.js +78 -0
  273. package/dist/slides/export/types.js +0 -0
  274. package/dist/slides/index.js +7 -0
  275. package/dist/slides/labels.js +26 -0
  276. package/dist/slides/layout.js +47 -0
  277. package/dist/slides/model.js +9 -0
  278. package/dist/slides/navigation.js +89 -0
  279. package/dist/slides/types.js +6 -0
  280. package/dist/status/define-statuses.js +16 -0
  281. package/dist/status/index.js +4 -0
  282. package/dist/status/status-types.js +0 -0
  283. package/dist/test-setup.js +26 -0
  284. package/dist/thread/index.js +3 -0
  285. package/dist/thread/logic.js +94 -0
  286. package/dist/thread/types.js +23 -0
  287. package/dist/work/board-order.js +109 -0
  288. package/dist/work/dates.js +19 -0
  289. package/dist/work/detail/detail-types.js +20 -0
  290. package/dist/work/docs/edited.js +39 -0
  291. package/dist/work/docs/index.js +7 -0
  292. package/dist/work/docs/labels.js +38 -0
  293. package/dist/work/docs/menu.js +121 -0
  294. package/dist/work/docs/outline.js +39 -0
  295. package/dist/work/gantt/logic.js +260 -0
  296. package/dist/work/inbox/inbox-logic.js +94 -0
  297. package/dist/work/inbox/inbox-statuses.js +86 -0
  298. package/dist/work/inbox/inbox-types.js +0 -0
  299. package/dist/work/inbox/index.js +1 -0
  300. package/dist/work/index.js +21 -0
  301. package/dist/work/kanban-drag.js +25 -0
  302. package/dist/work/kanban-types.js +0 -0
  303. package/dist/work/presets/sales.js +35 -0
  304. package/dist/work/reorder.js +10 -0
  305. package/dist/work/task-types.js +0 -0
  306. package/dist/work/time/duration.js +60 -0
  307. package/dist/work/time/time-types.js +25 -0
  308. package/dist/work/use-kanban-dnd.svelte.js +128 -0
  309. package/package.json +45 -3
  310. package/src/components/toolbar/toolbar-trigger.ts +8 -2
  311. package/src/record/demo-data.ts +4 -4
  312. package/src/record/record-demo.svelte +2 -2
  313. package/src/status/status-dot.svelte +0 -2
@@ -0,0 +1,727 @@
1
+ export function makeView(m, o, L, H, px) {
2
+ return {
3
+ m,
4
+ o,
5
+ L,
6
+ H,
7
+ px,
8
+ toScreen: (p)=>{
9
+ const x = p[0] - o[0], y = p[1] - o[1], z = p[2] - o[2];
10
+ return [
11
+ m[0] * x + m[1] * y + m[2] * z,
12
+ m[3] * x + m[4] * y + m[5] * z
13
+ ];
14
+ },
15
+ depth: (p)=>m[6] * (p[0] - o[0]) + m[7] * (p[1] - o[1]) + m[8] * (p[2] - o[2]),
16
+ dir: (v)=>norm([
17
+ m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
18
+ m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
19
+ m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
20
+ ])
21
+ };
22
+ }
23
+ export const sub = (a, b)=>[
24
+ a[0] - b[0],
25
+ a[1] - b[1],
26
+ a[2] - b[2]
27
+ ];
28
+ export const cross = (a, b)=>[
29
+ a[1] * b[2] - a[2] * b[1],
30
+ a[2] * b[0] - a[0] * b[2],
31
+ a[0] * b[1] - a[1] * b[0]
32
+ ];
33
+ export const dot = (a, b)=>a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
34
+ export const norm = (v)=>{
35
+ const l = Math.hypot(v[0], v[1], v[2]) || 1;
36
+ return [
37
+ v[0] / l,
38
+ v[1] / l,
39
+ v[2] / l
40
+ ];
41
+ };
42
+ const TAU = Math.PI * 2;
43
+ export function segs(view, len, lo, hi, quad = 11) {
44
+ return Math.max(lo, Math.min(hi, Math.round(len * view.px / quad)));
45
+ }
46
+ export function makeMesh(surf, nu, nv, inside, smooth = true) {
47
+ const W = nu + 1, N = W * (nv + 1);
48
+ const pos = new Float64Array(N * 3);
49
+ let ext = 0;
50
+ for(let j = 0, k = 0; j <= nv; j++){
51
+ for(let i = 0; i <= nu; i++, k++){
52
+ const p = surf(i / nu, j / nv);
53
+ pos[k * 3] = p[0];
54
+ pos[k * 3 + 1] = p[1];
55
+ pos[k * 3 + 2] = p[2];
56
+ ext = Math.max(ext, Math.abs(p[0] - pos[0]) + Math.abs(p[1] - pos[1]) + Math.abs(p[2] - pos[2]));
57
+ }
58
+ }
59
+ const P = (k)=>[
60
+ pos[k * 3],
61
+ pos[k * 3 + 1],
62
+ pos[k * 3 + 2]
63
+ ];
64
+ const fn = new Float64Array(nu * nv * 3);
65
+ for(let j = 0; j < nv; j++){
66
+ for(let i = 0; i < nu; i++){
67
+ const a = j * W + i;
68
+ const A = P(a), B = P(a + 1), C = P(a + W + 1), D = P(a + W);
69
+ let n = cross(sub(C, A), sub(D, B));
70
+ const mid = [
71
+ (A[0] + B[0] + C[0] + D[0]) / 4,
72
+ (A[1] + B[1] + C[1] + D[1]) / 4,
73
+ (A[2] + B[2] + C[2] + D[2]) / 4
74
+ ];
75
+ const ins = typeof inside === "function" ? inside((i + 0.5) / nu, (j + 0.5) / nv) : inside;
76
+ if (dot(n, sub(mid, ins)) < 0) n = [
77
+ -n[0],
78
+ -n[1],
79
+ -n[2]
80
+ ];
81
+ n = norm(n);
82
+ const f = (j * nu + i) * 3;
83
+ fn[f] = n[0];
84
+ fn[f + 1] = n[1];
85
+ fn[f + 2] = n[2];
86
+ }
87
+ }
88
+ const eps = 1e-6 + ext * 1e-5;
89
+ const same = (p, q)=>Math.abs(pos[p * 3] - pos[q * 3]) + Math.abs(pos[p * 3 + 1] - pos[q * 3 + 1]) + Math.abs(pos[p * 3 + 2] - pos[q * 3 + 2]) < eps;
90
+ let closed = true;
91
+ for(let j = 0; j <= nv && closed; j++)closed = same(j * W, j * W + nu);
92
+ let vn = null;
93
+ if (smooth) {
94
+ const acc = new Float64Array(N * 3);
95
+ for(let j = 0; j < nv; j++){
96
+ for(let i = 0; i < nu; i++){
97
+ const f = (j * nu + i) * 3;
98
+ const a = j * W + i;
99
+ for (const k of [
100
+ a,
101
+ a + 1,
102
+ a + W + 1,
103
+ a + W
104
+ ]){
105
+ acc[k * 3] += fn[f];
106
+ acc[k * 3 + 1] += fn[f + 1];
107
+ acc[k * 3 + 2] += fn[f + 2];
108
+ }
109
+ }
110
+ }
111
+ const join = (ks)=>{
112
+ let x = 0, y = 0, z = 0;
113
+ for (const k of ks){
114
+ x += acc[k * 3];
115
+ y += acc[k * 3 + 1];
116
+ z += acc[k * 3 + 2];
117
+ }
118
+ for (const k of ks){
119
+ acc[k * 3] = x;
120
+ acc[k * 3 + 1] = y;
121
+ acc[k * 3 + 2] = z;
122
+ }
123
+ };
124
+ if (closed) for(let j = 0; j <= nv; j++)join([
125
+ j * W,
126
+ j * W + nu
127
+ ]);
128
+ for (const j of [
129
+ 0,
130
+ nv
131
+ ]){
132
+ let pole = true;
133
+ for(let i = 1; i <= nu && pole; i++)pole = same(j * W, j * W + i);
134
+ if (pole) join(Array.from({
135
+ length: W
136
+ }, (_, i)=>j * W + i));
137
+ }
138
+ for(let k = 0; k < N; k++){
139
+ const x = acc[k * 3], y = acc[k * 3 + 1], z = acc[k * 3 + 2];
140
+ const l = Math.hypot(x, y, z) || 1;
141
+ acc[k * 3] = x / l;
142
+ acc[k * 3 + 1] = y / l;
143
+ acc[k * 3 + 2] = z / l;
144
+ }
145
+ vn = acc;
146
+ }
147
+ return {
148
+ nu,
149
+ nv,
150
+ closed,
151
+ pos,
152
+ fn,
153
+ vn
154
+ };
155
+ }
156
+ export function makeTube(path, up, prof, nu, nv, closed = false) {
157
+ const e = 1e-3;
158
+ const at = (u)=>path(closed ? (u % 1 + 1) % 1 : Math.max(0, Math.min(1, u)));
159
+ return makeMesh((u, v)=>{
160
+ const c = path(u);
161
+ const T = norm(sub(at(u + e), at(u - e)));
162
+ const k = dot(up, T);
163
+ const Nn = norm([
164
+ up[0] - T[0] * k,
165
+ up[1] - T[1] * k,
166
+ up[2] - T[2] * k
167
+ ]);
168
+ const Bn = cross(T, Nn);
169
+ const [a, b] = prof(u, v * TAU);
170
+ return [
171
+ c[0] + Nn[0] * a + Bn[0] * b,
172
+ c[1] + Nn[1] * a + Bn[1] * b,
173
+ c[2] + Nn[2] * a + Bn[2] * b
174
+ ];
175
+ }, nu, nv, (u)=>path(u));
176
+ }
177
+ export const section = (a, b, p = 1)=>(_u, ph)=>{
178
+ const c = Math.cos(ph), s = Math.sin(ph);
179
+ return [
180
+ a * Math.sign(c) * Math.pow(Math.abs(c), p),
181
+ b * Math.sign(s) * Math.pow(Math.abs(s), p)
182
+ ];
183
+ };
184
+ export function projectMesh(view, mesh) {
185
+ const { nu, nv, pos, fn, vn } = mesh;
186
+ const W = nu + 1, N = W * (nv + 1), C = nu * nv;
187
+ const [m0, m1, m2, m3, m4, m5, m6, m7, m8] = view.m;
188
+ const [ox, oy, oz] = view.o;
189
+ const x = new Float64Array(N), y = new Float64Array(N), d = new Float64Array(N);
190
+ for(let k = 0; k < N; k++){
191
+ const X = pos[k * 3] - ox, Y = pos[k * 3 + 1] - oy, Z = pos[k * 3 + 2] - oz;
192
+ x[k] = m0 * X + m1 * Y + m2 * Z;
193
+ y[k] = m3 * X + m4 * Y + m5 * Z;
194
+ d[k] = m6 * X + m7 * Y + m8 * Z;
195
+ }
196
+ const turn = (src, dst, count)=>{
197
+ for(let k = 0; k < count; k++){
198
+ const a = src[k * 3], b = src[k * 3 + 1], c = src[k * 3 + 2];
199
+ const X = m0 * a + m1 * b + m2 * c, Y = m3 * a + m4 * b + m5 * c, Z = m6 * a + m7 * b + m8 * c;
200
+ const l = Math.hypot(X, Y, Z) || 1;
201
+ dst[k * 3] = X / l;
202
+ dst[k * 3 + 1] = Y / l;
203
+ dst[k * 3 + 2] = Z / l;
204
+ }
205
+ };
206
+ let n = null;
207
+ if (vn) turn(vn, n = new Float64Array(N * 3), N);
208
+ const f = new Float64Array(C * 3), cd = new Float64Array(C);
209
+ turn(fn, f, C);
210
+ for(let j = 0, c = 0; j < nv; j++){
211
+ for(let i = 0; i < nu; i++, c++){
212
+ const a = j * W + i;
213
+ cd[c] = (d[a] + d[a + 1] + d[a + W] + d[a + W + 1]) / 4;
214
+ }
215
+ }
216
+ return {
217
+ nu,
218
+ nv,
219
+ closed: mesh.closed,
220
+ x,
221
+ y,
222
+ d,
223
+ n,
224
+ f,
225
+ cd
226
+ };
227
+ }
228
+ export function boundsOf(ps) {
229
+ let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
230
+ for (const p of ps){
231
+ for(let k = 0; k < p.x.length; k++){
232
+ if (p.x[k] < x0) x0 = p.x[k];
233
+ if (p.x[k] > x1) x1 = p.x[k];
234
+ if (p.y[k] < y0) y0 = p.y[k];
235
+ if (p.y[k] > y1) y1 = p.y[k];
236
+ }
237
+ }
238
+ return {
239
+ x0,
240
+ y0,
241
+ x1,
242
+ y1,
243
+ cx: (x0 + x1) / 2,
244
+ cy: (y0 + y1) / 2,
245
+ w: x1 - x0,
246
+ h: y1 - y0
247
+ };
248
+ }
249
+ function monotone(mx, my, s, e) {
250
+ const ax = mx[e] - mx[s], ay = my[e] - my[s];
251
+ let prev = -Infinity;
252
+ for(let k = s; k <= e; k++){
253
+ const t = (mx[k] - mx[s]) * ax + (my[k] - my[s]) * ay;
254
+ if (t < prev - 1e-9) return false;
255
+ prev = t;
256
+ }
257
+ return true;
258
+ }
259
+ const clampByte = (v)=>v < 0 ? 0 : v > 255 ? 255 : Math.round(v);
260
+ export const css = (c)=>`rgb(${clampByte(c[0])},${clampByte(c[1])},${clampByte(c[2])})`;
261
+ export function paintLayers(ctx, layers, px) {
262
+ const pieces = [];
263
+ const corners = [];
264
+ for (const l of layers){
265
+ const bias = l.bias ?? 0, keep = l.keep, cull = l.cull !== false;
266
+ for (const P of l.parts){
267
+ const { nu, nv, f, cd, x, y } = P, W = nu + 1;
268
+ const vis = (c)=>(!cull || f[c * 3 + 2] > -0.04) && (!keep || keep(cd[c]));
269
+ for(let j = 0; j < nv; j++){
270
+ if (l.flat) {
271
+ for(let i = 0; i < nu; i++){
272
+ const c = j * nu + i;
273
+ if (!vis(c)) continue;
274
+ pieces.push({
275
+ d: cd[c] + bias,
276
+ l,
277
+ p: P,
278
+ j,
279
+ cols: [
280
+ i,
281
+ i + 1
282
+ ],
283
+ cells: [
284
+ c
285
+ ]
286
+ });
287
+ corners.push([
288
+ x[j * W + i],
289
+ y[j * W + i]
290
+ ], [
291
+ x[(j + 1) * W + i + 1],
292
+ y[(j + 1) * W + i + 1]
293
+ ]);
294
+ }
295
+ continue;
296
+ }
297
+ const runs = [];
298
+ let cur = null;
299
+ for(let i = 0; i < nu; i++){
300
+ if (vis(j * nu + i)) {
301
+ if (!cur) runs.push(cur = []);
302
+ cur.push(i);
303
+ } else cur = null;
304
+ }
305
+ if (P.closed && runs.length > 1 && runs[0][0] === 0 && runs[runs.length - 1][runs[runs.length - 1].length - 1] === nu - 1) {
306
+ runs[0] = runs.pop().concat(runs[0]);
307
+ }
308
+ for (const run of runs){
309
+ const cols = run.concat(run[run.length - 1] + 1);
310
+ const mx = [], my = [];
311
+ for(let k = 0; k < cols.length; k++){
312
+ const t = j * W + cols[k], b = t + W;
313
+ mx.push((x[t] + x[b]) / 2);
314
+ my.push((y[t] + y[b]) / 2);
315
+ if (k === 0 || k === cols.length - 1) corners.push([
316
+ x[t],
317
+ y[t]
318
+ ], [
319
+ x[b],
320
+ y[b]
321
+ ]);
322
+ else if (j === 0) corners.push([
323
+ x[t],
324
+ y[t]
325
+ ]);
326
+ else if (j === nv - 1) corners.push([
327
+ x[b],
328
+ y[b]
329
+ ]);
330
+ }
331
+ let s = 0;
332
+ while(s < cols.length - 1){
333
+ let e = s + 1;
334
+ while(e + 1 < cols.length && monotone(mx, my, s, e + 1))e++;
335
+ let dd = 0;
336
+ for(let k = s; k < e; k++)dd += cd[j * nu + run[k]];
337
+ pieces.push({
338
+ d: dd / (e - s) + bias,
339
+ l,
340
+ p: P,
341
+ j,
342
+ cols: cols.slice(s, e + 1),
343
+ cells: run.slice(s, e)
344
+ });
345
+ s = e;
346
+ }
347
+ }
348
+ }
349
+ }
350
+ }
351
+ pieces.sort((a, b)=>a.d - b.d);
352
+ const grow = 0.5 / px;
353
+ for (const pc of pieces){
354
+ const { p: P, l, j, cols, cells } = pc;
355
+ const { x, y, n, f } = P, W = P.nu + 1;
356
+ const nc = cols.length;
357
+ const tx = [], ty = [], bx = [], by = [];
358
+ const t0 = j * W + cols[0], tn = j * W + cols[nc - 1];
359
+ let ax = (x[tn] + x[tn + W]) / 2 - (x[t0] + x[t0 + W]) / 2, ay = (y[tn] + y[tn + W]) / 2 - (y[t0] + y[t0 + W]) / 2;
360
+ const al = Math.hypot(ax, ay);
361
+ const ux = al > 1e-9 ? ax / al : 0, uy = al > 1e-9 ? ay / al : 0;
362
+ for(let k = 0; k < nc; k++){
363
+ const t = j * W + cols[k], b = t + W;
364
+ let dx = x[t] - x[b], dy = y[t] - y[b];
365
+ const dl = Math.hypot(dx, dy);
366
+ if (dl > 1e-9) dx /= dl, dy /= dl;
367
+ else dx = dy = 0;
368
+ const e = k === 0 ? -grow : k === nc - 1 ? grow : 0;
369
+ tx.push(x[t] + dx * grow + ux * e);
370
+ ty.push(y[t] + dy * grow + uy * e);
371
+ bx.push(x[b] - dx * grow + ux * e);
372
+ by.push(y[b] - dy * grow + uy * e);
373
+ }
374
+ const colour = (k)=>{
375
+ if (n && !l.flat) {
376
+ const t = (j * W + cols[k]) * 3, b = t + W * 3;
377
+ return l.shade(norm([
378
+ n[t] + n[b],
379
+ n[t + 1] + n[b + 1],
380
+ n[t + 2] + n[b + 2]
381
+ ]));
382
+ }
383
+ const c0 = cells[Math.max(0, Math.min(cells.length - 1, k - 1))] * 3, c1 = cells[Math.min(cells.length - 1, k)] * 3;
384
+ return l.shade(l.flat ? [
385
+ f[c1],
386
+ f[c1 + 1],
387
+ f[c1 + 2]
388
+ ] : norm([
389
+ f[c0] + f[c1],
390
+ f[c0 + 1] + f[c1 + 1],
391
+ f[c0 + 2] + f[c1 + 2]
392
+ ]));
393
+ };
394
+ let style;
395
+ if (l.flat || al < 1e-6) style = css(colour(0));
396
+ else {
397
+ const g = ctx.createLinearGradient((x[t0] + x[t0 + W]) / 2, (y[t0] + y[t0 + W]) / 2, (x[tn] + x[tn + W]) / 2, (y[tn] + y[tn + W]) / 2);
398
+ let last = null;
399
+ const m0x = (x[t0] + x[t0 + W]) / 2, m0y = (y[t0] + y[t0 + W]) / 2;
400
+ for(let k = 0; k < nc; k++){
401
+ const c = colour(k);
402
+ if (last && k < nc - 1 && Math.abs(c[0] - last[0]) + Math.abs(c[1] - last[1]) + Math.abs(c[2] - last[2]) < 5) continue;
403
+ const t = j * W + cols[k];
404
+ const off = (((x[t] + x[t + W]) / 2 - m0x) * ax + ((y[t] + y[t + W]) / 2 - m0y) * ay) / (al * al);
405
+ g.addColorStop(off < 0 ? 0 : off > 1 ? 1 : off, css(c));
406
+ last = c;
407
+ }
408
+ style = g;
409
+ }
410
+ ctx.fillStyle = style;
411
+ ctx.beginPath();
412
+ ctx.moveTo(tx[0], ty[0]);
413
+ for(let k = 1; k < nc; k++)ctx.lineTo(tx[k], ty[k]);
414
+ for(let k = nc - 1; k >= 0; k--)ctx.lineTo(bx[k], by[k]);
415
+ ctx.closePath();
416
+ ctx.fill();
417
+ }
418
+ return corners;
419
+ }
420
+ export function hull(pts) {
421
+ const p = pts.slice().sort((a, b)=>a[0] - b[0] || a[1] - b[1]);
422
+ if (p.length < 3) return p;
423
+ const cr = (o, a, b)=>(a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
424
+ const lo = [], up = [];
425
+ for (const q of p){
426
+ while(lo.length >= 2 && cr(lo[lo.length - 2], lo[lo.length - 1], q) <= 0)lo.pop();
427
+ lo.push(q);
428
+ }
429
+ for(let i = p.length - 1; i >= 0; i--){
430
+ const q = p[i];
431
+ while(up.length >= 2 && cr(up[up.length - 2], up[up.length - 1], q) <= 0)up.pop();
432
+ up.push(q);
433
+ }
434
+ lo.pop();
435
+ up.pop();
436
+ return lo.concat(up);
437
+ }
438
+ const clamp01 = (x)=>x < 0 ? 0 : x > 1 ? 1 : x;
439
+ export const mix = (a, b, t)=>[
440
+ a[0] + (b[0] - a[0]) * t,
441
+ a[1] + (b[1] - a[1]) * t,
442
+ a[2] + (b[2] - a[2]) * t
443
+ ];
444
+ export const scale = (a, k)=>[
445
+ a[0] * k,
446
+ a[1] * k,
447
+ a[2] * k
448
+ ];
449
+ const WHITE = [
450
+ 255,
451
+ 255,
452
+ 255
453
+ ];
454
+ export function felt(view, base, k = 1) {
455
+ const L = view.L;
456
+ return (n)=>{
457
+ const nl = dot(n, L);
458
+ const dif = Math.pow(clamp01((nl + 0.4) / 1.4), 1.35);
459
+ const graze = Math.pow(1 - clamp01(n[2]), 2);
460
+ const lit = (0.22 + 0.95 * dif + 0.22 * graze * clamp01(nl + 0.6)) * k;
461
+ const floor = 26 * dif * k;
462
+ return [
463
+ base[0] * lit + floor,
464
+ base[1] * lit + floor,
465
+ base[2] * lit + floor * 1.05
466
+ ];
467
+ };
468
+ }
469
+ export function velvet(view, base) {
470
+ const L = view.L, sheen = mix(base, WHITE, 0.3);
471
+ return (n)=>{
472
+ const nl = dot(n, L);
473
+ const dif = clamp01((nl + 0.3) / 1.3);
474
+ const graze = Math.pow(1 - clamp01(n[2]), 1.6);
475
+ return mix(scale(base, 0.2 + 0.7 * dif), sheen, 0.6 * graze * (0.4 + 0.6 * dif));
476
+ };
477
+ }
478
+ export function paper(view, base) {
479
+ const L = view.L, H = view.H;
480
+ return (n)=>{
481
+ const dif = clamp01((dot(n, L) + 0.2) / 1.2);
482
+ const spec = Math.pow(clamp01(dot(n, H)), 22) * 0.3;
483
+ return mix(scale(base, 0.36 + 0.7 * dif), WHITE, spec);
484
+ };
485
+ }
486
+ export function plastic(view, base, gloss = 1) {
487
+ const L = view.L, H = view.H;
488
+ return (n)=>{
489
+ const dif = clamp01((dot(n, L) + 0.25) / 1.25);
490
+ const nh = clamp01(dot(n, H));
491
+ const spec = (Math.pow(nh, 16) * 0.2 + Math.pow(nh, 80) * 0.6) * gloss;
492
+ const rim = Math.pow(1 - clamp01(n[2]), 3) * 0.14 * gloss;
493
+ return mix(scale(base, 0.28 + 0.78 * dif), WHITE, clamp01(spec + rim));
494
+ };
495
+ }
496
+ export function satin(view, base) {
497
+ const L = view.L, H = view.H, deep = scale(base, 0.42), sheen = mix(base, WHITE, 0.55);
498
+ return (n)=>{
499
+ const dif = clamp01((dot(n, L) + 0.35) / 1.35);
500
+ const nh = clamp01(dot(n, H));
501
+ const s = Math.pow(nh, 6) * 0.5 + Math.pow(nh, 40) * 0.35;
502
+ return mix(mix(deep, base, dif), sheen, clamp01(s));
503
+ };
504
+ }
505
+ export function metal(view, tint, dark, glint) {
506
+ const H = view.H, L = view.L;
507
+ return (n)=>{
508
+ const rz = 2 * n[2] * n[2] - 1, ry = 2 * n[2] * n[1];
509
+ const up = -ry;
510
+ const sky = clamp01(0.45 + up * 0.85 + rz * 0.1);
511
+ const horizon = Math.exp(-Math.pow((up + 0.12) / 0.16, 2)) * 0.55;
512
+ const nl = clamp01(dot(n, L));
513
+ const c = mix(dark, tint, clamp01(0.1 + sky * 0.72 + nl * 0.3));
514
+ const spec = Math.pow(clamp01(dot(n, H)), 70) + horizon * 0.4;
515
+ return mix(c, glint, clamp01(spec));
516
+ };
517
+ }
518
+ export const gold = (view)=>metal(view, [
519
+ 255,
520
+ 200,
521
+ 88
522
+ ], [
523
+ 86,
524
+ 50,
525
+ 8
526
+ ], [
527
+ 255,
528
+ 247,
529
+ 220
530
+ ]);
531
+ export const silver = (view)=>metal(view, [
532
+ 232,
533
+ 236,
534
+ 242
535
+ ], [
536
+ 58,
537
+ 62,
538
+ 72
539
+ ], [
540
+ 255,
541
+ 255,
542
+ 255
543
+ ]);
544
+ export function pearl(view) {
545
+ const L = view.L, H = view.H;
546
+ return (n)=>{
547
+ const dif = clamp01((dot(n, L) + 0.4) / 1.4);
548
+ const base = mix([
549
+ 238,
550
+ 228,
551
+ 228
552
+ ], [
553
+ 212,
554
+ 222,
555
+ 242
556
+ ], 1 - clamp01(n[2]));
557
+ return mix(scale(base, 0.62 + 0.42 * dif), WHITE, Math.pow(clamp01(dot(n, H)), 40) * 0.8);
558
+ };
559
+ }
560
+ export function gem(view, base) {
561
+ const L = view.L, H = view.H, deep = scale(base, 0.22), clear = mix(base, WHITE, 0.3);
562
+ return (n)=>{
563
+ const c = mix(deep, clear, clamp01(clamp01(n[2]) * 0.75 + dot(n, L) * 0.4));
564
+ return mix(c, WHITE, Math.pow(clamp01(dot(n, H)), 24) * 0.95);
565
+ };
566
+ }
567
+ const SPRITE = {
568
+ gold: [
569
+ [
570
+ 0,
571
+ "#fffbe8"
572
+ ],
573
+ [
574
+ 0.08,
575
+ "#ffe7a0"
576
+ ],
577
+ [
578
+ 0.3,
579
+ "#eeb546"
580
+ ],
581
+ [
582
+ 0.62,
583
+ "#ad7214"
584
+ ],
585
+ [
586
+ 0.87,
587
+ "#5a3806"
588
+ ],
589
+ [
590
+ 1,
591
+ "#8c5c18"
592
+ ]
593
+ ],
594
+ silver: [
595
+ [
596
+ 0,
597
+ "#ffffff"
598
+ ],
599
+ [
600
+ 0.08,
601
+ "#f3f5f9"
602
+ ],
603
+ [
604
+ 0.32,
605
+ "#c6ccd6"
606
+ ],
607
+ [
608
+ 0.64,
609
+ "#7a808c"
610
+ ],
611
+ [
612
+ 0.88,
613
+ "#3d4149"
614
+ ],
615
+ [
616
+ 1,
617
+ "#6b717c"
618
+ ]
619
+ ],
620
+ pearl: [
621
+ [
622
+ 0,
623
+ "#ffffff"
624
+ ],
625
+ [
626
+ 0.1,
627
+ "#fdf9f7"
628
+ ],
629
+ [
630
+ 0.45,
631
+ "#ebe4e6"
632
+ ],
633
+ [
634
+ 0.8,
635
+ "#c6bccb"
636
+ ],
637
+ [
638
+ 1,
639
+ "#a89db5"
640
+ ]
641
+ ]
642
+ };
643
+ export function sphereSprite(ctx, view, c, rad, kind) {
644
+ const s = view.toScreen(c);
645
+ const H = view.H;
646
+ const g = ctx.createRadialGradient(s[0] + H[0] * rad * 0.85, s[1] + H[1] * rad * 0.85, 0, s[0], s[1], rad);
647
+ if (typeof kind === "string") for (const [t, col] of SPRITE[kind])g.addColorStop(t, col);
648
+ else {
649
+ g.addColorStop(0, css(mix(kind, WHITE, 0.8)));
650
+ g.addColorStop(0.1, css(mix(kind, WHITE, 0.3)));
651
+ g.addColorStop(0.35, css(kind));
652
+ g.addColorStop(0.85, css(scale(kind, 0.5)));
653
+ g.addColorStop(1, css(scale(kind, 0.62)));
654
+ }
655
+ ctx.fillStyle = g;
656
+ ctx.beginPath();
657
+ ctx.arc(s[0], s[1], rad, 0, TAU);
658
+ ctx.fill();
659
+ }
660
+ export function cutGem(ctx, view, c, N, T, rad, col) {
661
+ const B = cross(N, T);
662
+ const at = (r, a, h)=>{
663
+ const x = r * Math.cos(a), y = r * Math.sin(a);
664
+ return [
665
+ c[0] + x * T[0] + y * B[0] + h * N[0],
666
+ c[1] + x * T[1] + y * B[1] + h * N[1],
667
+ c[2] + x * T[2] + y * B[2] + h * N[2]
668
+ ];
669
+ };
670
+ const K = 8, tr = 0.55, th = 0.36 * rad;
671
+ const girdle = [], table = [];
672
+ for(let k = 0; k < K; k++){
673
+ const a = (k + 0.5) / K * TAU;
674
+ girdle.push(at(rad, a, 0));
675
+ table.push(at(rad * tr, a, th));
676
+ }
677
+ const shade = gem(view, col);
678
+ const poly = (pts, n)=>{
679
+ const nv = view.dir(n);
680
+ if (nv[2] <= 0.02) return;
681
+ ctx.fillStyle = css(shade(nv));
682
+ ctx.beginPath();
683
+ pts.forEach((p, i)=>{
684
+ const s = view.toScreen(p);
685
+ if (i) ctx.lineTo(s[0], s[1]);
686
+ else ctx.moveTo(s[0], s[1]);
687
+ });
688
+ ctx.closePath();
689
+ ctx.fill();
690
+ ctx.strokeStyle = ctx.fillStyle;
691
+ ctx.stroke();
692
+ };
693
+ ctx.lineWidth = Math.min(0.3, 1 / view.px);
694
+ ctx.lineJoin = "round";
695
+ for(let k = 0; k < K; k++){
696
+ const g0 = girdle[k], g1 = girdle[(k + 1) % K], t1 = table[(k + 1) % K], t0 = table[k];
697
+ let n = cross(sub(t1, g0), sub(t0, g1));
698
+ if (dot(n, N) < 0) n = [
699
+ -n[0],
700
+ -n[1],
701
+ -n[2]
702
+ ];
703
+ poly([
704
+ g0,
705
+ g1,
706
+ t1,
707
+ t0
708
+ ], norm(n));
709
+ }
710
+ poly(table, N);
711
+ const nv = view.dir(N);
712
+ if (nv[2] > 0.1) {
713
+ const s0 = view.toScreen(at(0, 0, th));
714
+ const L = view.L;
715
+ ctx.fillStyle = "rgba(255,255,255,0.3)";
716
+ ctx.beginPath();
717
+ const s1 = view.toScreen(at(rad * tr * 0.8, Math.atan2(-L[1], -L[0]) + 2.2, th));
718
+ const s2 = view.toScreen(at(rad * tr * 0.9, Math.atan2(-L[1], -L[0]) + Math.PI, th));
719
+ const s3 = view.toScreen(at(rad * tr * 0.8, Math.atan2(-L[1], -L[0]) + Math.PI + 0.94, th));
720
+ ctx.moveTo(s0[0], s0[1]);
721
+ ctx.lineTo(s1[0], s1[1]);
722
+ ctx.lineTo(s2[0], s2[1]);
723
+ ctx.lineTo(s3[0], s3[1]);
724
+ ctx.closePath();
725
+ ctx.fill();
726
+ }
727
+ }