trama-ui 0.1.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 (285) hide show
  1. package/CATALOG.md +1237 -0
  2. package/LICENSE +21 -0
  3. package/README.md +78 -0
  4. package/THIRD-PARTY.md +4 -0
  5. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown.png +0 -0
  6. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown_inlay.png +0 -0
  7. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown_pressed.png +0 -0
  8. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey.png +0 -0
  9. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey_inlay.png +0 -0
  10. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey_pressed.png +0 -0
  11. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan.png +0 -0
  12. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan_inlay.png +0 -0
  13. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan_pressed.png +0 -0
  14. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white.png +0 -0
  15. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white_inlay.png +0 -0
  16. package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white_pressed.png +0 -0
  17. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/blue.png +0 -0
  18. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/blue_pressed.png +0 -0
  19. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/green.png +0 -0
  20. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/green_pressed.png +0 -0
  21. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/grey.png +0 -0
  22. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/grey_pressed.png +0 -0
  23. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/red.png +0 -0
  24. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/red_pressed.png +0 -0
  25. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/yellow.png +0 -0
  26. package/assets/pixel/kenney-pixel-ui/9-slice/Colored/yellow_pressed.png +0 -0
  27. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/blue.png +0 -0
  28. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/blue_pressed.png +0 -0
  29. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/green.png +0 -0
  30. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/green_pressed.png +0 -0
  31. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/red.png +0 -0
  32. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/red_pressed.png +0 -0
  33. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/yellow.png +0 -0
  34. package/assets/pixel/kenney-pixel-ui/9-slice/Outline/yellow_pressed.png +0 -0
  35. package/assets/pixel/kenney-pixel-ui/9-slice/list.png +0 -0
  36. package/assets/pixel/kenney-pixel-ui/9-slice/space.png +0 -0
  37. package/assets/pixel/kenney-pixel-ui/9-slice/space_inlay.png +0 -0
  38. package/assets/pixel/kenney-pixel-ui/License.txt +23 -0
  39. package/assets/pixel/kenney-pixel-ui/spritesheet/sheet.png +0 -0
  40. package/bin/trama-ui.mjs +27 -0
  41. package/dist/components/ui/Accordion.d.ts +12 -0
  42. package/dist/components/ui/Accordion.js +12 -0
  43. package/dist/components/ui/Alert.d.ts +15 -0
  44. package/dist/components/ui/Alert.js +15 -0
  45. package/dist/components/ui/ArticlesSection.d.ts +30 -0
  46. package/dist/components/ui/ArticlesSection.js +18 -0
  47. package/dist/components/ui/AsciiBackground.d.ts +58 -0
  48. package/dist/components/ui/AsciiBackground.js +173 -0
  49. package/dist/components/ui/AsciiCard.d.ts +78 -0
  50. package/dist/components/ui/AsciiCard.js +253 -0
  51. package/dist/components/ui/AsciiChart.d.ts +18 -0
  52. package/dist/components/ui/AsciiChart.js +47 -0
  53. package/dist/components/ui/Badge.d.ts +15 -0
  54. package/dist/components/ui/Badge.js +8 -0
  55. package/dist/components/ui/BitmapText.d.ts +25 -0
  56. package/dist/components/ui/BitmapText.js +21 -0
  57. package/dist/components/ui/BlogCard.d.ts +33 -0
  58. package/dist/components/ui/BlogCard.js +13 -0
  59. package/dist/components/ui/Breadcrumbs.d.ts +9 -0
  60. package/dist/components/ui/Breadcrumbs.js +7 -0
  61. package/dist/components/ui/Button.d.ts +74 -0
  62. package/dist/components/ui/Button.js +48 -0
  63. package/dist/components/ui/CTASection.d.ts +13 -0
  64. package/dist/components/ui/CTASection.js +7 -0
  65. package/dist/components/ui/Carousel.d.ts +30 -0
  66. package/dist/components/ui/Carousel.js +80 -0
  67. package/dist/components/ui/CheckboxGroup.d.ts +11 -0
  68. package/dist/components/ui/CheckboxGroup.js +20 -0
  69. package/dist/components/ui/CodeBlock.d.ts +11 -0
  70. package/dist/components/ui/CodeBlock.js +20 -0
  71. package/dist/components/ui/ContactForm.d.ts +25 -0
  72. package/dist/components/ui/ContactForm.js +26 -0
  73. package/dist/components/ui/CrtOverlay.d.ts +10 -0
  74. package/dist/components/ui/CrtOverlay.js +5 -0
  75. package/dist/components/ui/Divider.d.ts +12 -0
  76. package/dist/components/ui/Divider.js +7 -0
  77. package/dist/components/ui/Drawer.d.ts +16 -0
  78. package/dist/components/ui/Drawer.js +25 -0
  79. package/dist/components/ui/Dropdown.d.ts +10 -0
  80. package/dist/components/ui/Dropdown.js +21 -0
  81. package/dist/components/ui/FAQSection.d.ts +14 -0
  82. package/dist/components/ui/FAQSection.js +7 -0
  83. package/dist/components/ui/FeatureGrid.d.ts +18 -0
  84. package/dist/components/ui/FeatureGrid.js +14 -0
  85. package/dist/components/ui/Footer.d.ts +14 -0
  86. package/dist/components/ui/Footer.js +16 -0
  87. package/dist/components/ui/GlyphCursor.d.ts +22 -0
  88. package/dist/components/ui/GlyphCursor.js +50 -0
  89. package/dist/components/ui/GridBackground.d.ts +15 -0
  90. package/dist/components/ui/GridBackground.js +6 -0
  91. package/dist/components/ui/Hero.d.ts +21 -0
  92. package/dist/components/ui/Hero.js +12 -0
  93. package/dist/components/ui/HoverFX.d.ts +29 -0
  94. package/dist/components/ui/HoverFX.js +75 -0
  95. package/dist/components/ui/Icon.d.ts +33 -0
  96. package/dist/components/ui/Icon.js +29 -0
  97. package/dist/components/ui/ImageGallery.d.ts +31 -0
  98. package/dist/components/ui/ImageGallery.js +79 -0
  99. package/dist/components/ui/LogoCloud.d.ts +12 -0
  100. package/dist/components/ui/LogoCloud.js +9 -0
  101. package/dist/components/ui/MagneticButton.d.ts +12 -0
  102. package/dist/components/ui/MagneticButton.js +49 -0
  103. package/dist/components/ui/Marquee.d.ts +29 -0
  104. package/dist/components/ui/Marquee.js +15 -0
  105. package/dist/components/ui/Modal.d.ts +40 -0
  106. package/dist/components/ui/Modal.js +51 -0
  107. package/dist/components/ui/NavBar.d.ts +14 -0
  108. package/dist/components/ui/NavBar.js +12 -0
  109. package/dist/components/ui/NeonSign.d.ts +14 -0
  110. package/dist/components/ui/NeonSign.js +7 -0
  111. package/dist/components/ui/OtpInput.d.ts +9 -0
  112. package/dist/components/ui/OtpInput.js +27 -0
  113. package/dist/components/ui/Pagination.d.ts +10 -0
  114. package/dist/components/ui/Pagination.js +24 -0
  115. package/dist/components/ui/Panel.d.ts +21 -0
  116. package/dist/components/ui/Panel.js +8 -0
  117. package/dist/components/ui/PixelFrame.d.ts +61 -0
  118. package/dist/components/ui/PixelFrame.js +29 -0
  119. package/dist/components/ui/Presence.d.ts +51 -0
  120. package/dist/components/ui/Presence.js +343 -0
  121. package/dist/components/ui/PricingCard.d.ts +30 -0
  122. package/dist/components/ui/PricingCard.js +21 -0
  123. package/dist/components/ui/PricingSection.d.ts +35 -0
  124. package/dist/components/ui/PricingSection.js +21 -0
  125. package/dist/components/ui/Progress.d.ts +17 -0
  126. package/dist/components/ui/Progress.js +9 -0
  127. package/dist/components/ui/RadioGroup.d.ts +10 -0
  128. package/dist/components/ui/RadioGroup.js +11 -0
  129. package/dist/components/ui/RangeSlider.d.ts +14 -0
  130. package/dist/components/ui/RangeSlider.js +11 -0
  131. package/dist/components/ui/Reveal.d.ts +48 -0
  132. package/dist/components/ui/Reveal.js +181 -0
  133. package/dist/components/ui/SceneFlash.d.ts +14 -0
  134. package/dist/components/ui/SceneFlash.js +51 -0
  135. package/dist/components/ui/ScrambleText.d.ts +31 -0
  136. package/dist/components/ui/ScrambleText.js +51 -0
  137. package/dist/components/ui/ScrollArea.d.ts +15 -0
  138. package/dist/components/ui/ScrollArea.js +18 -0
  139. package/dist/components/ui/SectionHeader.d.ts +12 -0
  140. package/dist/components/ui/SectionHeader.js +6 -0
  141. package/dist/components/ui/Select.d.ts +17 -0
  142. package/dist/components/ui/Select.js +31 -0
  143. package/dist/components/ui/Skeleton.d.ts +12 -0
  144. package/dist/components/ui/Skeleton.js +18 -0
  145. package/dist/components/ui/Spinner.d.ts +15 -0
  146. package/dist/components/ui/Spinner.js +24 -0
  147. package/dist/components/ui/Spotlight.d.ts +16 -0
  148. package/dist/components/ui/Spotlight.js +16 -0
  149. package/dist/components/ui/Sprite.d.ts +27 -0
  150. package/dist/components/ui/Sprite.js +19 -0
  151. package/dist/components/ui/StatCounter.d.ts +24 -0
  152. package/dist/components/ui/StatCounter.js +70 -0
  153. package/dist/components/ui/StatsSection.d.ts +14 -0
  154. package/dist/components/ui/StatsSection.js +13 -0
  155. package/dist/components/ui/Stepper.d.ts +10 -0
  156. package/dist/components/ui/Stepper.js +7 -0
  157. package/dist/components/ui/Table.d.ts +10 -0
  158. package/dist/components/ui/Table.js +8 -0
  159. package/dist/components/ui/Tabs.d.ts +12 -0
  160. package/dist/components/ui/Tabs.js +18 -0
  161. package/dist/components/ui/TeamSection.d.ts +18 -0
  162. package/dist/components/ui/TeamSection.js +19 -0
  163. package/dist/components/ui/TerminalTyper.d.ts +20 -0
  164. package/dist/components/ui/TerminalTyper.js +45 -0
  165. package/dist/components/ui/Testimonial.d.ts +19 -0
  166. package/dist/components/ui/Testimonial.js +9 -0
  167. package/dist/components/ui/TestimonialSection.d.ts +20 -0
  168. package/dist/components/ui/TestimonialSection.js +15 -0
  169. package/dist/components/ui/TextField.d.ts +26 -0
  170. package/dist/components/ui/TextField.js +13 -0
  171. package/dist/components/ui/TextmodeBackground.d.ts +52 -0
  172. package/dist/components/ui/TextmodeBackground.js +83 -0
  173. package/dist/components/ui/Timeline.d.ts +13 -0
  174. package/dist/components/ui/Timeline.js +8 -0
  175. package/dist/components/ui/Toast.d.ts +30 -0
  176. package/dist/components/ui/Toast.js +47 -0
  177. package/dist/components/ui/Toggle.d.ts +13 -0
  178. package/dist/components/ui/Toggle.js +10 -0
  179. package/dist/components/ui/Tooltip.d.ts +20 -0
  180. package/dist/components/ui/Tooltip.js +20 -0
  181. package/dist/components/ui/Typewriter.d.ts +20 -0
  182. package/dist/components/ui/Typewriter.js +46 -0
  183. package/dist/components/ui/VideoPlayer.d.ts +81 -0
  184. package/dist/components/ui/VideoPlayer.js +379 -0
  185. package/dist/components/ui/fill.d.ts +32 -0
  186. package/dist/components/ui/fill.js +27 -0
  187. package/dist/components/ui/intent.d.ts +20 -0
  188. package/dist/components/ui/intent.js +23 -0
  189. package/dist/components/ui/styles/kit.css +31 -0
  190. package/dist/components/ui/styles/ui-carousel.css +113 -0
  191. package/dist/components/ui/styles/ui-kit.css +1135 -0
  192. package/dist/components/ui/styles/ui-video.css +75 -0
  193. package/dist/components/ui/swiperCss.d.ts +15 -0
  194. package/dist/components/ui/swiperCss.js +15 -0
  195. package/dist/components/ui/variants.d.ts +12 -0
  196. package/dist/components/ui/variants.js +10 -0
  197. package/dist/index.d.ts +77 -0
  198. package/dist/index.js +77 -0
  199. package/dist/lib/asciify/painters.d.ts +25 -0
  200. package/dist/lib/asciify/painters.js +604 -0
  201. package/dist/lib/asciify/pointer.d.ts +12 -0
  202. package/dist/lib/asciify/pointer.js +54 -0
  203. package/dist/lib/asciify/shape-painters.d.ts +44 -0
  204. package/dist/lib/asciify/shape-painters.js +335 -0
  205. package/dist/lib/asciify/theme-painters.d.ts +8 -0
  206. package/dist/lib/asciify/theme-painters.js +437 -0
  207. package/dist/lib/cells.d.ts +46 -0
  208. package/dist/lib/cells.js +114 -0
  209. package/dist/lib/scroll/store.d.ts +21 -0
  210. package/dist/lib/scroll/store.js +25 -0
  211. package/dist/lib/sketches/aurora.d.ts +3 -0
  212. package/dist/lib/sketches/aurora.js +42 -0
  213. package/dist/lib/sketches/fire.d.ts +3 -0
  214. package/dist/lib/sketches/fire.js +80 -0
  215. package/dist/lib/sketches/flow.d.ts +3 -0
  216. package/dist/lib/sketches/flow.js +70 -0
  217. package/dist/lib/sketches/life.d.ts +3 -0
  218. package/dist/lib/sketches/life.js +107 -0
  219. package/dist/lib/sketches/matrix.d.ts +3 -0
  220. package/dist/lib/sketches/matrix.js +64 -0
  221. package/dist/lib/sketches/ocean.d.ts +3 -0
  222. package/dist/lib/sketches/ocean.js +56 -0
  223. package/dist/lib/sketches/plasma.d.ts +3 -0
  224. package/dist/lib/sketches/plasma.js +29 -0
  225. package/dist/lib/sketches/registry.d.ts +6 -0
  226. package/dist/lib/sketches/registry.js +60 -0
  227. package/dist/lib/sketches/ripples.d.ts +3 -0
  228. package/dist/lib/sketches/ripples.js +84 -0
  229. package/dist/lib/sketches/scroll-assemble.d.ts +8 -0
  230. package/dist/lib/sketches/scroll-assemble.js +90 -0
  231. package/dist/lib/sketches/scroll-parallax.d.ts +6 -0
  232. package/dist/lib/sketches/scroll-parallax.js +76 -0
  233. package/dist/lib/sketches/scroll-rain.d.ts +6 -0
  234. package/dist/lib/sketches/scroll-rain.js +82 -0
  235. package/dist/lib/sketches/scroll-stats.d.ts +7 -0
  236. package/dist/lib/sketches/scroll-stats.js +81 -0
  237. package/dist/lib/sketches/scroll-terminal.d.ts +6 -0
  238. package/dist/lib/sketches/scroll-terminal.js +87 -0
  239. package/dist/lib/sketches/scroll-zoom.d.ts +7 -0
  240. package/dist/lib/sketches/scroll-zoom.js +49 -0
  241. package/dist/lib/sketches/starfield.d.ts +3 -0
  242. package/dist/lib/sketches/starfield.js +54 -0
  243. package/dist/lib/sketches/text-3d.d.ts +6 -0
  244. package/dist/lib/sketches/text-3d.js +62 -0
  245. package/dist/lib/sketches/text-combo-figlet.d.ts +6 -0
  246. package/dist/lib/sketches/text-combo-figlet.js +91 -0
  247. package/dist/lib/sketches/text-glitch.d.ts +3 -0
  248. package/dist/lib/sketches/text-glitch.js +57 -0
  249. package/dist/lib/sketches/text-marquee.d.ts +3 -0
  250. package/dist/lib/sketches/text-marquee.js +35 -0
  251. package/dist/lib/sketches/text-particles.d.ts +9 -0
  252. package/dist/lib/sketches/text-particles.js +91 -0
  253. package/dist/lib/sketches/text-rain.d.ts +3 -0
  254. package/dist/lib/sketches/text-rain.js +73 -0
  255. package/dist/lib/sketches/text-scramble.d.ts +6 -0
  256. package/dist/lib/sketches/text-scramble.js +49 -0
  257. package/dist/lib/sketches/text-wave.d.ts +3 -0
  258. package/dist/lib/sketches/text-wave.js +43 -0
  259. package/dist/lib/sketches/theme-orbit.d.ts +6 -0
  260. package/dist/lib/sketches/theme-orbit.js +119 -0
  261. package/dist/lib/sketches/theme-pulse.d.ts +7 -0
  262. package/dist/lib/sketches/theme-pulse.js +84 -0
  263. package/dist/lib/sketches/tunnel.d.ts +3 -0
  264. package/dist/lib/sketches/tunnel.js +28 -0
  265. package/dist/lib/text/banner.d.ts +5 -0
  266. package/dist/lib/text/banner.js +35 -0
  267. package/dist/lib/text/mask.d.ts +40 -0
  268. package/dist/lib/text/mask.js +143 -0
  269. package/dist/lib/text/store.d.ts +23 -0
  270. package/dist/lib/text/store.js +86 -0
  271. package/dist/lib/ui/card-fields.d.ts +52 -0
  272. package/dist/lib/ui/card-fields.js +193 -0
  273. package/dist/lib/ui/fonts.d.ts +56 -0
  274. package/dist/lib/ui/fonts.js +94 -0
  275. package/dist/lib/ui/fx.d.ts +42 -0
  276. package/dist/lib/ui/fx.js +162 -0
  277. package/dist/lib/ui/icons.d.ts +437 -0
  278. package/dist/lib/ui/icons.js +314 -0
  279. package/dist/lib/ui/placeholder.d.ts +11 -0
  280. package/dist/lib/ui/placeholder.js +65 -0
  281. package/dist/lib/ui/tokens.d.ts +49 -0
  282. package/dist/lib/ui/tokens.js +129 -0
  283. package/dist/lib/ui/useTokens.d.ts +10 -0
  284. package/dist/lib/ui/useTokens.js +32 -0
  285. package/package.json +80 -0
@@ -0,0 +1,91 @@
1
+ import { aspect, createPointer, gridOrigin, hsv, plot } from "../cells.js";
2
+ import { bannerLines } from "../text/banner.js";
3
+ import { textStore } from "../text/store.js";
4
+ /**
5
+ * Combinación de ambas librerías: asciify-engine genera el arte de texto (FIGlet o
6
+ * bitmap 7×7) y textmode.js lo dibuja carácter a carácter con onda y ondas de hover.
7
+ */
8
+ export function txComboFiglet(t) {
9
+ const ptr = createPointer(t);
10
+ let lines = [" "];
11
+ let key = "";
12
+ let pending = "";
13
+ let timer;
14
+ let ripple = -10;
15
+ let wasPressed = false;
16
+ const request = (text, font) => {
17
+ const k = `${font}|${text}`;
18
+ if (k === key || k === pending)
19
+ return;
20
+ pending = k;
21
+ clearTimeout(timer);
22
+ timer = setTimeout(async () => {
23
+ let out = await bannerLines(text, font);
24
+ // Si no cabe a lo ancho, prueba con fuentes más compactas
25
+ const cols = t.grid?.cols ?? 100;
26
+ for (const alt of ["Small", "Mini", "Bitmap"]) {
27
+ if (Math.max(...out.map((l) => l.length)) <= cols * 0.94)
28
+ break;
29
+ out = await bannerLines(text, alt);
30
+ }
31
+ if (pending === k) {
32
+ lines = out;
33
+ key = k;
34
+ }
35
+ }, 120);
36
+ };
37
+ t.draw(() => {
38
+ ptr.update();
39
+ const s = t.secs;
40
+ const asp = aspect(t);
41
+ const { cols, rows } = gridOrigin(t);
42
+ request(textStore.text(), textStore.get().font);
43
+ if (ptr.pressed && !wasPressed)
44
+ ripple = s;
45
+ wasPressed = ptr.pressed;
46
+ const w = Math.max(...lines.map((l) => l.length));
47
+ const h = lines.length;
48
+ // Amplía el arte en bloques kx×ky mientras quepa en pantalla
49
+ const kx = Math.max(1, Math.min(4, Math.floor((cols * 0.92) / w)));
50
+ const ky = Math.max(1, Math.min(4, Math.floor((rows * 0.8) / h), Math.round(kx / asp)));
51
+ const ox = -Math.floor((w * kx) / 2);
52
+ const oy = -Math.floor((h * ky) / 2);
53
+ const R = 12;
54
+ t.background(6, 6, 16);
55
+ for (let j = 0; j < h; j++) {
56
+ const line = lines[j];
57
+ for (let i = 0; i < line.length; i++) {
58
+ const ch = line[i];
59
+ if (ch === " ")
60
+ continue;
61
+ t.char(ch);
62
+ for (let sy = 0; sy < ky; sy++) {
63
+ for (let sx = 0; sx < kx; sx++) {
64
+ const x = ox + i * kx + sx;
65
+ const y = oy + j * ky + sy;
66
+ let px = x;
67
+ let py = y + Math.sin(x * 0.18 + s * 2.4) * 1.2;
68
+ const dx = px - ptr.x;
69
+ const dy = (py - ptr.y) * asp;
70
+ const d = Math.hypot(dx, dy) + 0.001;
71
+ if (d < R) {
72
+ const k = ((R - d) / R) ** 2;
73
+ px += (dx / d) * k * 5;
74
+ py += ((dy / d) * k * 5) / asp;
75
+ }
76
+ const age = s - ripple;
77
+ if (age < 2) {
78
+ const wave = Math.sin(d * 0.9 - age * 9) * Math.exp(-age * 1.6) * Math.exp(-d * 0.04);
79
+ py += wave * 2.5;
80
+ }
81
+ const hue = (x * 0.008 + s * 0.06 + 0.5) % 1;
82
+ t.charColor(...hsv(hue, 0.6, 0.95));
83
+ t.cellColor(...hsv(hue, 0.85, 0.12));
84
+ if (Math.abs(px) <= cols && Math.abs(py) <= rows)
85
+ plot(t, Math.round(px), Math.round(py));
86
+ }
87
+ }
88
+ }
89
+ }
90
+ });
91
+ }
@@ -0,0 +1,3 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /** Glitch: bandas desplazadas, separación cromática y ruido. El puntero corrompe lo que toca. */
3
+ export declare function txGlitch(t: Textmodifier): void;
@@ -0,0 +1,57 @@
1
+ import { aspect, createPointer, gridOrigin, plot } from "../cells.js";
2
+ import { getTextMask } from "../text/mask.js";
3
+ import { textStore } from "../text/store.js";
4
+ const GLYPHS = "01#%&@$/\\|<>";
5
+ /** Glitch: bandas desplazadas, separación cromática y ruido. El puntero corrompe lo que toca. */
6
+ export function txGlitch(t) {
7
+ const ptr = createPointer(t);
8
+ let bands = new Float32Array(0);
9
+ t.draw(() => {
10
+ ptr.update();
11
+ const asp = aspect(t);
12
+ const { cols, rows, x0, y0 } = gridOrigin(t);
13
+ const mask = getTextMask(textStore.text(), cols, rows, asp);
14
+ if (bands.length !== rows)
15
+ bands = new Float32Array(rows);
16
+ for (let j = 0; j < rows; j++)
17
+ bands[j] *= 0.82;
18
+ if (Math.random() < (ptr.pressed ? 0.9 : 0.14)) {
19
+ const j0 = Math.floor(Math.random() * rows);
20
+ const len = 1 + Math.floor(Math.random() * 5);
21
+ const off = (Math.random() - 0.5) * 22;
22
+ for (let j = j0; j < Math.min(rows, j0 + len); j++)
23
+ bands[j] = off;
24
+ }
25
+ const R = ptr.pressed ? 16 : 9;
26
+ t.background(4, 4, 10);
27
+ // Ruido de fondo
28
+ for (let n = 0; n < 50; n++) {
29
+ t.char(GLYPHS[Math.floor(Math.random() * GLYPHS.length)]);
30
+ t.charColor(30, 45, 70);
31
+ plot(t, x0 + Math.floor(Math.random() * cols), y0 + Math.floor(Math.random() * rows));
32
+ }
33
+ for (let j = 0; j < rows; j++) {
34
+ const dim = j % 3 === 0 ? 0.7 : 1; // líneas de barrido
35
+ for (let i = 0; i < cols; i++) {
36
+ if (mask.data[j * cols + i] < 90)
37
+ continue;
38
+ const x = x0 + i;
39
+ const y = y0 + j;
40
+ let ox = Math.round(bands[j]);
41
+ const dx = x - ptr.x;
42
+ const dy = (y - ptr.y) * asp;
43
+ const hot = Math.hypot(dx, dy) < R;
44
+ if (hot)
45
+ ox += Math.round((Math.random() - 0.5) * 6);
46
+ const ch = hot && Math.random() < 0.5 ? GLYPHS[Math.floor(Math.random() * GLYPHS.length)] : "#";
47
+ t.char(ch);
48
+ t.charColor(255 * dim, 40, 90 * dim);
49
+ plot(t, x + ox - 1, y);
50
+ t.charColor(30, 230 * dim, 255 * dim);
51
+ plot(t, x + ox + 1, y);
52
+ t.charColor(245 * dim, 245 * dim, 255 * dim);
53
+ plot(t, x + ox, y);
54
+ }
55
+ }
56
+ });
57
+ }
@@ -0,0 +1,3 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /** Marquesinas con `t.print()`: cada fila corre a su velocidad y sentido. El puntero ilumina la fila que toca. */
3
+ export declare function txMarquee(t: Textmodifier): void;
@@ -0,0 +1,35 @@
1
+ import { createPointer, gridOrigin, hsv } from "../cells.js";
2
+ import { textStore } from "../text/store.js";
3
+ /** Marquesinas con `t.print()`: cada fila corre a su velocidad y sentido. El puntero ilumina la fila que toca. */
4
+ export function txMarquee(t) {
5
+ const ptr = createPointer(t);
6
+ t.draw(() => {
7
+ ptr.update();
8
+ const s = t.secs;
9
+ const text = textStore.text();
10
+ const unit = `${text} // `;
11
+ const L = unit.length;
12
+ const { cols, rows, x0, y0 } = gridOrigin(t);
13
+ const str = unit.repeat(Math.ceil(cols / L) + 2);
14
+ t.background(6, 8, 18);
15
+ t.printAlign("left", "top");
16
+ for (let j = 0; j < rows; j += 2) {
17
+ const dir = (j / 2) % 2 ? 1 : -1;
18
+ const speed = 5 + 4 * Math.abs(Math.sin(j * 0.7));
19
+ const off = (s * speed) % L;
20
+ const startX = dir < 0 ? x0 - off : x0 - L + off;
21
+ const y = y0 + j;
22
+ const hot = Math.abs(y - ptr.y) < 2.5;
23
+ const hue = (j * 0.012 + s * 0.03 + 0.55) % 1;
24
+ if (hot) {
25
+ t.cellColor(...hsv(hue, 0.7, 0.28));
26
+ t.charColor(255, 240, 200);
27
+ }
28
+ else {
29
+ t.cellColor(6, 8, 18);
30
+ t.charColor(...hsv(hue, 0.55, 0.42 + 0.25 * Math.abs(Math.sin(j))));
31
+ }
32
+ t.print(str, startX, y, { markup: false });
33
+ }
34
+ });
35
+ }
@@ -0,0 +1,9 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /**
3
+ * Partículas con muelle que forman el texto. El puntero las dispersa y pulsar las
4
+ * hace explotar; al cambiar el texto se reasignan los destinos y vuelan a su sitio.
5
+ * Con `transparent` no pinta fondo, para superponerlo a otra capa.
6
+ */
7
+ export declare function txParticles(t: Textmodifier, opts?: {
8
+ transparent?: boolean;
9
+ }): void;
@@ -0,0 +1,91 @@
1
+ import { aspect, createPointer, gridOrigin, hsv, plot } from "../cells.js";
2
+ import { getTextMask } from "../text/mask.js";
3
+ import { textStore } from "../text/store.js";
4
+ /**
5
+ * Partículas con muelle que forman el texto. El puntero las dispersa y pulsar las
6
+ * hace explotar; al cambiar el texto se reasignan los destinos y vuelan a su sitio.
7
+ * Con `transparent` no pinta fondo, para superponerlo a otra capa.
8
+ */
9
+ export function txParticles(t, opts = {}) {
10
+ const ptr = createPointer(t);
11
+ const particles = [];
12
+ let key = "";
13
+ let wasPressed = false;
14
+ const retarget = (data, cols, rows, x0, y0) => {
15
+ const cells = [];
16
+ for (let j = 0; j < rows; j++)
17
+ for (let i = 0; i < cols; i++)
18
+ if (data[j * cols + i] > 140)
19
+ cells.push(x0 + i, y0 + j);
20
+ const total = cells.length / 2;
21
+ const count = Math.min(2600, total);
22
+ const step = total / Math.max(1, count);
23
+ const targets = [];
24
+ for (let k = 0; k < count; k++) {
25
+ const idx = Math.floor(k * step);
26
+ targets.push([cells[idx * 2], cells[idx * 2 + 1]]);
27
+ }
28
+ for (let k = targets.length - 1; k > 0; k--) {
29
+ const r = Math.floor(Math.random() * (k + 1));
30
+ [targets[k], targets[r]] = [targets[r], targets[k]];
31
+ }
32
+ while (particles.length < count) {
33
+ particles.push({
34
+ x: x0 + Math.random() * cols,
35
+ y: y0 + Math.random() * rows,
36
+ vx: 0,
37
+ vy: 0,
38
+ tx: 0,
39
+ ty: 0,
40
+ });
41
+ }
42
+ particles.length = count;
43
+ targets.forEach(([tx, ty], k) => {
44
+ particles[k].tx = tx;
45
+ particles[k].ty = ty;
46
+ });
47
+ };
48
+ t.draw(() => {
49
+ ptr.update();
50
+ const s = t.secs;
51
+ const asp = aspect(t);
52
+ const { cols, rows, x0, y0 } = gridOrigin(t);
53
+ const mask = getTextMask(textStore.text(), cols, rows, asp);
54
+ if (mask.key !== key) {
55
+ key = mask.key;
56
+ retarget(mask.data, cols, rows, x0, y0);
57
+ }
58
+ const burst = ptr.pressed && !wasPressed;
59
+ wasPressed = ptr.pressed;
60
+ const R = 12;
61
+ if (opts.transparent)
62
+ t.clear();
63
+ else
64
+ t.background(4, 5, 12);
65
+ for (const p of particles) {
66
+ p.vx = (p.vx + (p.tx - p.x) * 0.06) * 0.86;
67
+ p.vy = (p.vy + (p.ty - p.y) * 0.06) * 0.86;
68
+ const dx = p.x - ptr.x;
69
+ const dy = (p.y - ptr.y) * asp;
70
+ const d = Math.hypot(dx, dy) + 0.001;
71
+ if (d < R) {
72
+ const k = ((R - d) / R) * 1.8;
73
+ p.vx += (dx / d) * k;
74
+ p.vy += ((dy / d) * k) / asp;
75
+ }
76
+ if (burst && d < 40) {
77
+ p.vx += (dx / d) * 6 * (1 + Math.random());
78
+ p.vy += ((dy / d) * 6 * (1 + Math.random())) / asp;
79
+ }
80
+ p.x += p.vx;
81
+ p.y += p.vy;
82
+ const e = Math.hypot(p.vx, p.vy);
83
+ t.char(e > 1.2 ? "*" : e > 0.35 ? "+" : "#");
84
+ const hue = (p.tx * 0.007 + s * 0.05 + 0.5) % 1;
85
+ t.charColor(...hsv(hue, 0.65 - Math.min(e, 1) * 0.3, 0.6 + Math.min(e, 1) * 0.4));
86
+ if (!opts.transparent)
87
+ t.cellColor(...hsv(hue, 0.8, 0.07 + Math.min(e, 1) * 0.12));
88
+ plot(t, Math.round(p.x), Math.round(p.y));
89
+ }
90
+ });
91
+ }
@@ -0,0 +1,3 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /** Lluvia digital que se ilumina donde hay texto (con las letras de tu propio texto). El puntero deja rastro de luz. */
3
+ export declare function txRain(t: Textmodifier): void;
@@ -0,0 +1,73 @@
1
+ import { aspect, createPointer, gridOrigin, plot } from "../cells.js";
2
+ import { getTextMask } from "../text/mask.js";
3
+ import { textStore } from "../text/store.js";
4
+ const GLYPHS = "01ABCDEFGHIJKLMNOPQRSTUVWXYZ<>{}[]/\\|+=*:;#$%&@";
5
+ /** Lluvia digital que se ilumina donde hay texto (con las letras de tu propio texto). El puntero deja rastro de luz. */
6
+ export function txRain(t) {
7
+ const ptr = createPointer(t);
8
+ let W = 0;
9
+ let H = 0;
10
+ let glow = new Float32Array(0);
11
+ let heads = [];
12
+ const rebuild = () => {
13
+ W = t.grid.cols;
14
+ H = t.grid.rows;
15
+ glow = new Float32Array(W * H);
16
+ heads = Array.from({ length: W }, () => ({ y: Math.random() * H, v: 0.25 + Math.random() * 0.7 }));
17
+ };
18
+ t.draw(() => {
19
+ if (W !== t.grid.cols || H !== t.grid.rows)
20
+ rebuild();
21
+ ptr.update();
22
+ const text = textStore.text();
23
+ const asp = aspect(t);
24
+ const { x0, y0 } = gridOrigin(t);
25
+ const mask = getTextMask(text, W, H, asp);
26
+ for (let i = 0; i < W; i++) {
27
+ const h = heads[i];
28
+ h.y += h.v;
29
+ if (h.y >= H + 4) {
30
+ h.y = -Math.random() * H * 0.5;
31
+ h.v = 0.25 + Math.random() * 0.7;
32
+ }
33
+ const row = Math.floor(h.y);
34
+ if (row >= 0 && row < H)
35
+ glow[row * W + i] = 1;
36
+ }
37
+ if (ptr.raw) {
38
+ const gx = Math.round(ptr.raw.x - x0);
39
+ const gy = Math.round(ptr.raw.y - y0);
40
+ const r = ptr.pressed ? 7 : 3;
41
+ for (let dy = -r; dy <= r; dy++) {
42
+ for (let dx = -r * 2; dx <= r * 2; dx++) {
43
+ const x = gx + dx;
44
+ const y = gy + dy;
45
+ if (x >= 0 && y >= 0 && x < W && y < H && Math.hypot(dx / 2, dy) <= r)
46
+ glow[y * W + x] = 1;
47
+ }
48
+ }
49
+ }
50
+ t.background(0, 4, 2);
51
+ for (let j = 0; j < H; j++) {
52
+ for (let i = 0; i < W; i++) {
53
+ const idx = j * W + i;
54
+ const g = glow[idx];
55
+ glow[idx] = g * 0.93;
56
+ const m = mask.data[idx] / 255;
57
+ const b = Math.max(g, m * 0.55);
58
+ if (b < 0.05)
59
+ continue;
60
+ const lit = m > 0.4;
61
+ t.char(lit
62
+ ? text[(i + j * 7) % text.length] || "#"
63
+ : GLYPHS[(i * 31 + j * 17 + (g > 0.9 ? t.frameCount : 0)) % GLYPHS.length]);
64
+ if (lit)
65
+ t.charColor(120 + 135 * g, 255, 150 + 90 * g);
66
+ else
67
+ t.charColor(0, 60 + 195 * b, 40 * b);
68
+ t.cellColor(0, lit ? 22 + 30 * b : 6 + 12 * b, lit ? 10 : 3);
69
+ plot(t, x0 + i, y0 + j);
70
+ }
71
+ }
72
+ });
73
+ }
@@ -0,0 +1,6 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /**
3
+ * Decodificado: el texto se descifra de izquierda a derecha entre glifos aleatorios y
4
+ * se repite. Bajo el puntero las letras se vuelven a mezclar. Efecto típico de titulares.
5
+ */
6
+ export declare function txScramble(t: Textmodifier): void;
@@ -0,0 +1,49 @@
1
+ import { aspect, createPointer, gridOrigin, hsv, plot } from "../cells.js";
2
+ import { getTextMask } from "../text/mask.js";
3
+ import { textStore } from "../text/store.js";
4
+ const GLYPHS = "!<>-_\\/[]{}=+*^?#0123456789ABCDEF";
5
+ /**
6
+ * Decodificado: el texto se descifra de izquierda a derecha entre glifos aleatorios y
7
+ * se repite. Bajo el puntero las letras se vuelven a mezclar. Efecto típico de titulares.
8
+ */
9
+ export function txScramble(t) {
10
+ const ptr = createPointer(t);
11
+ t.draw(() => {
12
+ ptr.update();
13
+ const s = t.secs;
14
+ const asp = aspect(t);
15
+ const { cols, rows, x0, y0 } = gridOrigin(t);
16
+ const text = textStore.text();
17
+ const mask = getTextMask(text, cols, rows, asp);
18
+ // ciclo de 6 s: 3.2 s descifrando, resto en reposo
19
+ const cycle = (s % 6) / 3.2;
20
+ const frontier = Math.min(1.15, cycle) * cols;
21
+ t.background(4, 5, 12);
22
+ for (let j = 0; j < rows; j++) {
23
+ for (let i = 0; i < cols; i++) {
24
+ const m = mask.data[j * cols + i] / 255;
25
+ if (m < 0.3)
26
+ continue;
27
+ const x = x0 + i;
28
+ const y = y0 + j;
29
+ const dx = x - ptr.x;
30
+ const dy = (y - ptr.y) * asp;
31
+ const hot = Math.hypot(dx, dy) < (ptr.pressed ? 14 : 8);
32
+ const decoded = i < frontier - 6 && !hot;
33
+ const edge = !decoded && i < frontier + 6;
34
+ if (decoded) {
35
+ t.char(text[(i + j * 3) % text.length] || "#");
36
+ t.charColor(...hsv(0.5 + i * 0.002, 0.45, 0.95));
37
+ t.cellColor(...hsv(0.55, 0.7, 0.1 * m));
38
+ }
39
+ else {
40
+ t.char(GLYPHS[Math.floor(Math.random() * GLYPHS.length)]);
41
+ const hue = hot ? 0.9 : 0.35;
42
+ t.charColor(...hsv(hue, 0.7, edge || hot ? 1 : 0.35));
43
+ t.cellColor(...hsv(hue, 0.8, edge || hot ? 0.15 : 0.03));
44
+ }
45
+ plot(t, x, y);
46
+ }
47
+ }
48
+ });
49
+ }
@@ -0,0 +1,3 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /** Texto grande que ondula. El puntero aparta las letras; al pulsar, con más fuerza. */
3
+ export declare function txWave(t: Textmodifier): void;
@@ -0,0 +1,43 @@
1
+ import { aspect, createPointer, gridOrigin, hsv, plot } from "../cells.js";
2
+ import { getTextMask } from "../text/mask.js";
3
+ import { textStore } from "../text/store.js";
4
+ /** Texto grande que ondula. El puntero aparta las letras; al pulsar, con más fuerza. */
5
+ export function txWave(t) {
6
+ const ptr = createPointer(t);
7
+ const ramp = t.createGlyphRamp(" .:-=+*#%@");
8
+ const noise = "01#%&@$";
9
+ t.draw(() => {
10
+ ptr.update();
11
+ const s = t.secs;
12
+ const asp = aspect(t);
13
+ const { cols, rows, x0, y0 } = gridOrigin(t);
14
+ const mask = getTextMask(textStore.text(), cols, rows, asp);
15
+ const R = ptr.pressed ? 18 : 11;
16
+ t.background(5, 6, 16);
17
+ for (let j = 0; j < rows; j++) {
18
+ for (let i = 0; i < cols; i++) {
19
+ const v = mask.data[j * cols + i] / 255;
20
+ if (v < 0.3)
21
+ continue;
22
+ const x = x0 + i;
23
+ const y = y0 + j;
24
+ let px = x;
25
+ let py = y + Math.sin(x * 0.22 + s * 3) * 1.6;
26
+ const dx = px - ptr.x;
27
+ const dy = (py - ptr.y) * asp;
28
+ const d = Math.hypot(dx, dy) + 0.001;
29
+ const near = d < R;
30
+ if (near) {
31
+ const k = (R - d) / R;
32
+ px += (dx / d) * k * R * 0.7;
33
+ py += ((dy / d) * k * R * 0.7) / asp;
34
+ }
35
+ const hue = (x * 0.006 + s * 0.08 + 0.55) % 1;
36
+ t.char(near && Math.random() < 0.25 ? noise[Math.floor(Math.random() * noise.length)] : ramp.at(v));
37
+ t.charColor(...hsv(hue, 0.7, 0.5 + 0.5 * v));
38
+ t.cellColor(...hsv(hue, 0.8, 0.1));
39
+ plot(t, Math.round(px), Math.round(py));
40
+ }
41
+ }
42
+ });
43
+ }
@@ -0,0 +1,6 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /**
3
+ * Órbita: del pie de la rampa de lanzamiento al espacio. El cielo se oscurece, el cohete
4
+ * asciende dejando estela de fuego, aparece el limbo del planeta y, al final, la luna.
5
+ */
6
+ export declare function thOrbit(t: Textmodifier): void;
@@ -0,0 +1,119 @@
1
+ import { createPointer, eachCell, hash2, mix } from "../cells.js";
2
+ import { clamp, scrollState, smooth, span } from "../scroll/store.js";
3
+ /**
4
+ * Órbita: del pie de la rampa de lanzamiento al espacio. El cielo se oscurece, el cohete
5
+ * asciende dejando estela de fuego, aparece el limbo del planeta y, al final, la luna.
6
+ */
7
+ export function thOrbit(t) {
8
+ const ptr = createPointer(t);
9
+ t.draw(() => {
10
+ ptr.update();
11
+ const p = scrollState.p;
12
+ const s = t.secs;
13
+ const { cols, rows } = t.grid;
14
+ const ground = smooth(span(p, 0, 0.3)); // la rampa se aleja hacia abajo
15
+ const space = smooth(span(p, 0.08, 0.55));
16
+ const planetUp = smooth(span(p, 0.3, 0.75));
17
+ const moon = smooth(span(p, 0.8, 1));
18
+ const groundH = Math.max(0, rows * 0.22 - ground * rows * 0.5); // altura del suelo (celdas)
19
+ const lift = smooth(span(p, 0.03, 0.5)) * rows * 1.5;
20
+ const baseAlt = groundH + 1 + lift; // altura de la base del cohete
21
+ const R = cols * 1.4; // radio del planeta en celdas
22
+ const topRow = rows * mix(1.25, 0.6, planetUp); // fila (desde arriba) donde asoma el limbo
23
+ const pcy = topRow + R;
24
+ const skyTop = [mix(25, 2, space), mix(70, 3, space), mix(160, 14, space)];
25
+ const skyLow = [mix(120, 4, space), mix(180, 6, space), mix(235, 24, space)];
26
+ t.background(0);
27
+ eachCell(t, (x, _y, _i, j) => {
28
+ const alt = rows - 1 - j; // altura sobre el borde inferior
29
+ // rampa de lanzamiento
30
+ if (alt < groundH) {
31
+ const tower = Math.abs(x + cols * 0.16) <= 1 && alt < groundH + rows * 0.3;
32
+ t.char(tower ? (alt % 3 === 0 ? "=" : "|") : "#");
33
+ t.charColor(70, 80, 100);
34
+ t.cellColor(14, 16, 26);
35
+ return;
36
+ }
37
+ if (ground < 0.9 && Math.abs(x + cols * 0.16) <= 1 && alt < groundH + rows * 0.34) {
38
+ t.char(alt % 3 === 0 ? "=" : "|");
39
+ t.charColor(90, 100, 125);
40
+ t.cellColor(...(skyLowAt(alt / rows)));
41
+ return;
42
+ }
43
+ // cohete
44
+ const rb = alt - baseAlt;
45
+ if (rb >= 0 && rb < 10 && Math.abs(x) <= (rb < 3 ? 2 : 1)) {
46
+ const fin = rb < 3 && Math.abs(x) === 2;
47
+ t.char(rb === 9 ? "^" : fin ? (x < 0 ? "/" : "\\") : rb === 5 ? "o" : "H");
48
+ t.charColor(...(fin ? [255, 90, 80] : [245, 245, 255]));
49
+ t.cellColor(50, 54, 70);
50
+ return;
51
+ }
52
+ // llama y estela
53
+ if (lift > 0.5 || p < 0.02) {
54
+ const fd = baseAlt - alt; // profundidad bajo el cohete
55
+ if (fd > 0 && fd < rows * 0.35 && Math.abs(x) <= Math.max(0, 2.2 - fd * 0.06)) {
56
+ const f = hash2(x, Math.floor(s * 14 + alt));
57
+ if (f > fd / (rows * 0.35)) {
58
+ t.char(f > 0.8 ? "*" : "^");
59
+ t.charColor(255, 170 + f * 80, 60 + (fd / rows) * 200);
60
+ t.cellColor(70 * (1 - fd / (rows * 0.35)), 25, 0);
61
+ return;
62
+ }
63
+ }
64
+ }
65
+ // planeta
66
+ const dPlanet = Math.hypot(x + (ptr.x / cols) * 6, j - pcy);
67
+ if (planetUp > 0.01 && dPlanet < R) {
68
+ const n = t.noise(x * 0.05 + s * 0.02, j * 0.12) * 0.95;
69
+ const rim = 1 - dPlanet / R;
70
+ const cloud = n > 0.58;
71
+ const land = n > 0.4;
72
+ t.char(cloud ? "%" : land ? "+" : ".");
73
+ t.charColor(...(cloud ? [235, 245, 255] : land ? [70, 170, 110] : [40, 110, 210]));
74
+ t.cellColor(6, 20 + rim * 60, 50 + rim * 110);
75
+ return;
76
+ }
77
+ const halo = Math.exp(-(((dPlanet - R) / (rows * 0.05)) ** 2)) * planetUp;
78
+ if (halo > 0.1) {
79
+ t.char("~");
80
+ t.charColor(120, 200, 255, 200 * halo);
81
+ t.cellColor(10, 30 * halo, 80 * halo);
82
+ return;
83
+ }
84
+ // luna con cráteres
85
+ if (moon > 0.01) {
86
+ const d = Math.hypot(x - cols * 0.22, (j - rows * 0.26) * 1);
87
+ if (d < rows * 0.2 * moon) {
88
+ const crater = hash2(Math.floor(x / 2), Math.floor(j / 2)) > 0.84;
89
+ t.char(crater ? "o" : ".");
90
+ t.charColor(215, 217, 226);
91
+ t.cellColor(72, 74, 86);
92
+ return;
93
+ }
94
+ }
95
+ // cielo
96
+ const k = clamp(alt / rows);
97
+ t.cellColor(mix(skyLow[0], skyTop[0], k), mix(skyLow[1], skyTop[1], k), mix(skyLow[2], skyTop[2], k));
98
+ if (hash2(x, j) > 1 - 0.04 * space) {
99
+ const tw = Math.sin(s * 2 + hash2(j, x) * 60) * 0.5 + 0.5;
100
+ t.char(tw > 0.5 ? "*" : ".");
101
+ t.charColor(255, 255, 255, 80 + 175 * tw);
102
+ return;
103
+ }
104
+ // nubes de día
105
+ if (space < 0.4) {
106
+ const c = t.noise(x * 0.05 + s * 0.03, alt * 0.09) * (1 - space / 0.4);
107
+ if (c > 0.55 && k > 0.15 && k < 0.7) {
108
+ t.char(c > 0.66 ? "%" : "~");
109
+ t.charColor(255, 255, 255, 190);
110
+ return;
111
+ }
112
+ }
113
+ t.char(" ");
114
+ });
115
+ function skyLowAt(k) {
116
+ return [mix(skyLow[0], skyTop[0], k), mix(skyLow[1], skyTop[1], k), mix(skyLow[2], skyTop[2], k)];
117
+ }
118
+ });
119
+ }
@@ -0,0 +1,7 @@
1
+ import type { Textmodifier } from "textmode.js";
2
+ /**
3
+ * Pulso: ciudad nocturna con lluvia, tres capas de edificios con ventanas parpadeantes y
4
+ * un cartel de neón. Al bajar, la cámara sube de la calle a las azoteas y el neón vira de
5
+ * rosa a cian.
6
+ */
7
+ export declare function thPulse(t: Textmodifier): void;