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.
- package/CATALOG.md +1237 -0
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/THIRD-PARTY.md +4 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown_inlay.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/brown_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey_inlay.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/grey_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan_inlay.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/tan_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white_inlay.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Ancient/white_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/blue.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/blue_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/green.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/green_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/grey.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/grey_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/red.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/red_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/yellow.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Colored/yellow_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/blue.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/blue_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/green.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/green_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/red.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/red_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/yellow.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/Outline/yellow_pressed.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/list.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/space.png +0 -0
- package/assets/pixel/kenney-pixel-ui/9-slice/space_inlay.png +0 -0
- package/assets/pixel/kenney-pixel-ui/License.txt +23 -0
- package/assets/pixel/kenney-pixel-ui/spritesheet/sheet.png +0 -0
- package/bin/trama-ui.mjs +27 -0
- package/dist/components/ui/Accordion.d.ts +12 -0
- package/dist/components/ui/Accordion.js +12 -0
- package/dist/components/ui/Alert.d.ts +15 -0
- package/dist/components/ui/Alert.js +15 -0
- package/dist/components/ui/ArticlesSection.d.ts +30 -0
- package/dist/components/ui/ArticlesSection.js +18 -0
- package/dist/components/ui/AsciiBackground.d.ts +58 -0
- package/dist/components/ui/AsciiBackground.js +173 -0
- package/dist/components/ui/AsciiCard.d.ts +78 -0
- package/dist/components/ui/AsciiCard.js +253 -0
- package/dist/components/ui/AsciiChart.d.ts +18 -0
- package/dist/components/ui/AsciiChart.js +47 -0
- package/dist/components/ui/Badge.d.ts +15 -0
- package/dist/components/ui/Badge.js +8 -0
- package/dist/components/ui/BitmapText.d.ts +25 -0
- package/dist/components/ui/BitmapText.js +21 -0
- package/dist/components/ui/BlogCard.d.ts +33 -0
- package/dist/components/ui/BlogCard.js +13 -0
- package/dist/components/ui/Breadcrumbs.d.ts +9 -0
- package/dist/components/ui/Breadcrumbs.js +7 -0
- package/dist/components/ui/Button.d.ts +74 -0
- package/dist/components/ui/Button.js +48 -0
- package/dist/components/ui/CTASection.d.ts +13 -0
- package/dist/components/ui/CTASection.js +7 -0
- package/dist/components/ui/Carousel.d.ts +30 -0
- package/dist/components/ui/Carousel.js +80 -0
- package/dist/components/ui/CheckboxGroup.d.ts +11 -0
- package/dist/components/ui/CheckboxGroup.js +20 -0
- package/dist/components/ui/CodeBlock.d.ts +11 -0
- package/dist/components/ui/CodeBlock.js +20 -0
- package/dist/components/ui/ContactForm.d.ts +25 -0
- package/dist/components/ui/ContactForm.js +26 -0
- package/dist/components/ui/CrtOverlay.d.ts +10 -0
- package/dist/components/ui/CrtOverlay.js +5 -0
- package/dist/components/ui/Divider.d.ts +12 -0
- package/dist/components/ui/Divider.js +7 -0
- package/dist/components/ui/Drawer.d.ts +16 -0
- package/dist/components/ui/Drawer.js +25 -0
- package/dist/components/ui/Dropdown.d.ts +10 -0
- package/dist/components/ui/Dropdown.js +21 -0
- package/dist/components/ui/FAQSection.d.ts +14 -0
- package/dist/components/ui/FAQSection.js +7 -0
- package/dist/components/ui/FeatureGrid.d.ts +18 -0
- package/dist/components/ui/FeatureGrid.js +14 -0
- package/dist/components/ui/Footer.d.ts +14 -0
- package/dist/components/ui/Footer.js +16 -0
- package/dist/components/ui/GlyphCursor.d.ts +22 -0
- package/dist/components/ui/GlyphCursor.js +50 -0
- package/dist/components/ui/GridBackground.d.ts +15 -0
- package/dist/components/ui/GridBackground.js +6 -0
- package/dist/components/ui/Hero.d.ts +21 -0
- package/dist/components/ui/Hero.js +12 -0
- package/dist/components/ui/HoverFX.d.ts +29 -0
- package/dist/components/ui/HoverFX.js +75 -0
- package/dist/components/ui/Icon.d.ts +33 -0
- package/dist/components/ui/Icon.js +29 -0
- package/dist/components/ui/ImageGallery.d.ts +31 -0
- package/dist/components/ui/ImageGallery.js +79 -0
- package/dist/components/ui/LogoCloud.d.ts +12 -0
- package/dist/components/ui/LogoCloud.js +9 -0
- package/dist/components/ui/MagneticButton.d.ts +12 -0
- package/dist/components/ui/MagneticButton.js +49 -0
- package/dist/components/ui/Marquee.d.ts +29 -0
- package/dist/components/ui/Marquee.js +15 -0
- package/dist/components/ui/Modal.d.ts +40 -0
- package/dist/components/ui/Modal.js +51 -0
- package/dist/components/ui/NavBar.d.ts +14 -0
- package/dist/components/ui/NavBar.js +12 -0
- package/dist/components/ui/NeonSign.d.ts +14 -0
- package/dist/components/ui/NeonSign.js +7 -0
- package/dist/components/ui/OtpInput.d.ts +9 -0
- package/dist/components/ui/OtpInput.js +27 -0
- package/dist/components/ui/Pagination.d.ts +10 -0
- package/dist/components/ui/Pagination.js +24 -0
- package/dist/components/ui/Panel.d.ts +21 -0
- package/dist/components/ui/Panel.js +8 -0
- package/dist/components/ui/PixelFrame.d.ts +61 -0
- package/dist/components/ui/PixelFrame.js +29 -0
- package/dist/components/ui/Presence.d.ts +51 -0
- package/dist/components/ui/Presence.js +343 -0
- package/dist/components/ui/PricingCard.d.ts +30 -0
- package/dist/components/ui/PricingCard.js +21 -0
- package/dist/components/ui/PricingSection.d.ts +35 -0
- package/dist/components/ui/PricingSection.js +21 -0
- package/dist/components/ui/Progress.d.ts +17 -0
- package/dist/components/ui/Progress.js +9 -0
- package/dist/components/ui/RadioGroup.d.ts +10 -0
- package/dist/components/ui/RadioGroup.js +11 -0
- package/dist/components/ui/RangeSlider.d.ts +14 -0
- package/dist/components/ui/RangeSlider.js +11 -0
- package/dist/components/ui/Reveal.d.ts +48 -0
- package/dist/components/ui/Reveal.js +181 -0
- package/dist/components/ui/SceneFlash.d.ts +14 -0
- package/dist/components/ui/SceneFlash.js +51 -0
- package/dist/components/ui/ScrambleText.d.ts +31 -0
- package/dist/components/ui/ScrambleText.js +51 -0
- package/dist/components/ui/ScrollArea.d.ts +15 -0
- package/dist/components/ui/ScrollArea.js +18 -0
- package/dist/components/ui/SectionHeader.d.ts +12 -0
- package/dist/components/ui/SectionHeader.js +6 -0
- package/dist/components/ui/Select.d.ts +17 -0
- package/dist/components/ui/Select.js +31 -0
- package/dist/components/ui/Skeleton.d.ts +12 -0
- package/dist/components/ui/Skeleton.js +18 -0
- package/dist/components/ui/Spinner.d.ts +15 -0
- package/dist/components/ui/Spinner.js +24 -0
- package/dist/components/ui/Spotlight.d.ts +16 -0
- package/dist/components/ui/Spotlight.js +16 -0
- package/dist/components/ui/Sprite.d.ts +27 -0
- package/dist/components/ui/Sprite.js +19 -0
- package/dist/components/ui/StatCounter.d.ts +24 -0
- package/dist/components/ui/StatCounter.js +70 -0
- package/dist/components/ui/StatsSection.d.ts +14 -0
- package/dist/components/ui/StatsSection.js +13 -0
- package/dist/components/ui/Stepper.d.ts +10 -0
- package/dist/components/ui/Stepper.js +7 -0
- package/dist/components/ui/Table.d.ts +10 -0
- package/dist/components/ui/Table.js +8 -0
- package/dist/components/ui/Tabs.d.ts +12 -0
- package/dist/components/ui/Tabs.js +18 -0
- package/dist/components/ui/TeamSection.d.ts +18 -0
- package/dist/components/ui/TeamSection.js +19 -0
- package/dist/components/ui/TerminalTyper.d.ts +20 -0
- package/dist/components/ui/TerminalTyper.js +45 -0
- package/dist/components/ui/Testimonial.d.ts +19 -0
- package/dist/components/ui/Testimonial.js +9 -0
- package/dist/components/ui/TestimonialSection.d.ts +20 -0
- package/dist/components/ui/TestimonialSection.js +15 -0
- package/dist/components/ui/TextField.d.ts +26 -0
- package/dist/components/ui/TextField.js +13 -0
- package/dist/components/ui/TextmodeBackground.d.ts +52 -0
- package/dist/components/ui/TextmodeBackground.js +83 -0
- package/dist/components/ui/Timeline.d.ts +13 -0
- package/dist/components/ui/Timeline.js +8 -0
- package/dist/components/ui/Toast.d.ts +30 -0
- package/dist/components/ui/Toast.js +47 -0
- package/dist/components/ui/Toggle.d.ts +13 -0
- package/dist/components/ui/Toggle.js +10 -0
- package/dist/components/ui/Tooltip.d.ts +20 -0
- package/dist/components/ui/Tooltip.js +20 -0
- package/dist/components/ui/Typewriter.d.ts +20 -0
- package/dist/components/ui/Typewriter.js +46 -0
- package/dist/components/ui/VideoPlayer.d.ts +81 -0
- package/dist/components/ui/VideoPlayer.js +379 -0
- package/dist/components/ui/fill.d.ts +32 -0
- package/dist/components/ui/fill.js +27 -0
- package/dist/components/ui/intent.d.ts +20 -0
- package/dist/components/ui/intent.js +23 -0
- package/dist/components/ui/styles/kit.css +31 -0
- package/dist/components/ui/styles/ui-carousel.css +113 -0
- package/dist/components/ui/styles/ui-kit.css +1135 -0
- package/dist/components/ui/styles/ui-video.css +75 -0
- package/dist/components/ui/swiperCss.d.ts +15 -0
- package/dist/components/ui/swiperCss.js +15 -0
- package/dist/components/ui/variants.d.ts +12 -0
- package/dist/components/ui/variants.js +10 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +77 -0
- package/dist/lib/asciify/painters.d.ts +25 -0
- package/dist/lib/asciify/painters.js +604 -0
- package/dist/lib/asciify/pointer.d.ts +12 -0
- package/dist/lib/asciify/pointer.js +54 -0
- package/dist/lib/asciify/shape-painters.d.ts +44 -0
- package/dist/lib/asciify/shape-painters.js +335 -0
- package/dist/lib/asciify/theme-painters.d.ts +8 -0
- package/dist/lib/asciify/theme-painters.js +437 -0
- package/dist/lib/cells.d.ts +46 -0
- package/dist/lib/cells.js +114 -0
- package/dist/lib/scroll/store.d.ts +21 -0
- package/dist/lib/scroll/store.js +25 -0
- package/dist/lib/sketches/aurora.d.ts +3 -0
- package/dist/lib/sketches/aurora.js +42 -0
- package/dist/lib/sketches/fire.d.ts +3 -0
- package/dist/lib/sketches/fire.js +80 -0
- package/dist/lib/sketches/flow.d.ts +3 -0
- package/dist/lib/sketches/flow.js +70 -0
- package/dist/lib/sketches/life.d.ts +3 -0
- package/dist/lib/sketches/life.js +107 -0
- package/dist/lib/sketches/matrix.d.ts +3 -0
- package/dist/lib/sketches/matrix.js +64 -0
- package/dist/lib/sketches/ocean.d.ts +3 -0
- package/dist/lib/sketches/ocean.js +56 -0
- package/dist/lib/sketches/plasma.d.ts +3 -0
- package/dist/lib/sketches/plasma.js +29 -0
- package/dist/lib/sketches/registry.d.ts +6 -0
- package/dist/lib/sketches/registry.js +60 -0
- package/dist/lib/sketches/ripples.d.ts +3 -0
- package/dist/lib/sketches/ripples.js +84 -0
- package/dist/lib/sketches/scroll-assemble.d.ts +8 -0
- package/dist/lib/sketches/scroll-assemble.js +90 -0
- package/dist/lib/sketches/scroll-parallax.d.ts +6 -0
- package/dist/lib/sketches/scroll-parallax.js +76 -0
- package/dist/lib/sketches/scroll-rain.d.ts +6 -0
- package/dist/lib/sketches/scroll-rain.js +82 -0
- package/dist/lib/sketches/scroll-stats.d.ts +7 -0
- package/dist/lib/sketches/scroll-stats.js +81 -0
- package/dist/lib/sketches/scroll-terminal.d.ts +6 -0
- package/dist/lib/sketches/scroll-terminal.js +87 -0
- package/dist/lib/sketches/scroll-zoom.d.ts +7 -0
- package/dist/lib/sketches/scroll-zoom.js +49 -0
- package/dist/lib/sketches/starfield.d.ts +3 -0
- package/dist/lib/sketches/starfield.js +54 -0
- package/dist/lib/sketches/text-3d.d.ts +6 -0
- package/dist/lib/sketches/text-3d.js +62 -0
- package/dist/lib/sketches/text-combo-figlet.d.ts +6 -0
- package/dist/lib/sketches/text-combo-figlet.js +91 -0
- package/dist/lib/sketches/text-glitch.d.ts +3 -0
- package/dist/lib/sketches/text-glitch.js +57 -0
- package/dist/lib/sketches/text-marquee.d.ts +3 -0
- package/dist/lib/sketches/text-marquee.js +35 -0
- package/dist/lib/sketches/text-particles.d.ts +9 -0
- package/dist/lib/sketches/text-particles.js +91 -0
- package/dist/lib/sketches/text-rain.d.ts +3 -0
- package/dist/lib/sketches/text-rain.js +73 -0
- package/dist/lib/sketches/text-scramble.d.ts +6 -0
- package/dist/lib/sketches/text-scramble.js +49 -0
- package/dist/lib/sketches/text-wave.d.ts +3 -0
- package/dist/lib/sketches/text-wave.js +43 -0
- package/dist/lib/sketches/theme-orbit.d.ts +6 -0
- package/dist/lib/sketches/theme-orbit.js +119 -0
- package/dist/lib/sketches/theme-pulse.d.ts +7 -0
- package/dist/lib/sketches/theme-pulse.js +84 -0
- package/dist/lib/sketches/tunnel.d.ts +3 -0
- package/dist/lib/sketches/tunnel.js +28 -0
- package/dist/lib/text/banner.d.ts +5 -0
- package/dist/lib/text/banner.js +35 -0
- package/dist/lib/text/mask.d.ts +40 -0
- package/dist/lib/text/mask.js +143 -0
- package/dist/lib/text/store.d.ts +23 -0
- package/dist/lib/text/store.js +86 -0
- package/dist/lib/ui/card-fields.d.ts +52 -0
- package/dist/lib/ui/card-fields.js +193 -0
- package/dist/lib/ui/fonts.d.ts +56 -0
- package/dist/lib/ui/fonts.js +94 -0
- package/dist/lib/ui/fx.d.ts +42 -0
- package/dist/lib/ui/fx.js +162 -0
- package/dist/lib/ui/icons.d.ts +437 -0
- package/dist/lib/ui/icons.js +314 -0
- package/dist/lib/ui/placeholder.d.ts +11 -0
- package/dist/lib/ui/placeholder.js +65 -0
- package/dist/lib/ui/tokens.d.ts +49 -0
- package/dist/lib/ui/tokens.js +129 -0
- package/dist/lib/ui/useTokens.d.ts +10 -0
- package/dist/lib/ui/useTokens.js +32 -0
- 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,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,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,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,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;
|