life-pulse 2.3.1 → 2.3.2
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/dist/tui.js +89 -24
- package/package.json +1 -1
package/dist/tui.js
CHANGED
|
@@ -26,13 +26,13 @@ function out(text) {
|
|
|
26
26
|
else
|
|
27
27
|
console.log(text);
|
|
28
28
|
}
|
|
29
|
-
// ───
|
|
29
|
+
// ─── Intro ───
|
|
30
30
|
import chalk from 'chalk';
|
|
31
31
|
const _sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
32
|
-
//
|
|
33
|
-
const G1 = chalk.hex('#d4a574'); //
|
|
34
|
-
const G2 = chalk.hex('#a8885c'); //
|
|
35
|
-
const G3 = chalk.hex('#7a6544'); //
|
|
32
|
+
// Warm amber palette — fades like candlelight
|
|
33
|
+
const G1 = chalk.hex('#d4a574'); // name
|
|
34
|
+
const G2 = chalk.hex('#a8885c'); // location + weather
|
|
35
|
+
const G3 = chalk.hex('#7a6544'); // closing
|
|
36
36
|
async function typewrite(text, style, delay = 30) {
|
|
37
37
|
for (const ch of text) {
|
|
38
38
|
process.stdout.write(style(ch));
|
|
@@ -49,7 +49,6 @@ async function fetchWeather(city) {
|
|
|
49
49
|
const [temp, cond] = raw.split('|');
|
|
50
50
|
if (!temp || !cond)
|
|
51
51
|
return null;
|
|
52
|
-
// "+72°F" → "72°", "Sunny" → "sunny"
|
|
53
52
|
const deg = temp.replace(/[+\s]/g, '').replace(/°[CF]/, '°');
|
|
54
53
|
const sky = cond.trim().toLowerCase();
|
|
55
54
|
return `${deg} and ${sky}`;
|
|
@@ -58,42 +57,108 @@ async function fetchWeather(city) {
|
|
|
58
57
|
return null;
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
|
-
function
|
|
60
|
+
function timeGreeting(h) {
|
|
62
61
|
if (h < 5)
|
|
63
|
-
return "
|
|
62
|
+
return "Don't stay up too late.";
|
|
64
63
|
if (h < 12)
|
|
65
|
-
return '
|
|
64
|
+
return 'Hope you have an incredible morning.';
|
|
66
65
|
if (h < 17)
|
|
67
|
-
return "
|
|
66
|
+
return "Hope you're having a wonderful afternoon.";
|
|
68
67
|
if (h < 21)
|
|
69
|
-
return "
|
|
70
|
-
return "
|
|
68
|
+
return "Hope you're having a beautiful evening.";
|
|
69
|
+
return "Don't stay up too late.";
|
|
70
|
+
}
|
|
71
|
+
function weatherRemark(weather) {
|
|
72
|
+
const w = weather.toLowerCase();
|
|
73
|
+
if (w.includes('sunny') || w.includes('clear'))
|
|
74
|
+
return `${weather} out there.`;
|
|
75
|
+
if (w.includes('rain') || w.includes('drizzle'))
|
|
76
|
+
return `${weather} — good day to stay sharp.`;
|
|
77
|
+
if (w.includes('cloud') || w.includes('overcast'))
|
|
78
|
+
return `${weather}.`;
|
|
79
|
+
if (w.includes('snow'))
|
|
80
|
+
return `${weather}. Stay warm.`;
|
|
81
|
+
return `${weather}.`;
|
|
82
|
+
}
|
|
83
|
+
// ─── Geometric animation ───
|
|
84
|
+
function renderScanField(cols, rows) {
|
|
85
|
+
const cy = Math.floor(rows / 2);
|
|
86
|
+
const shades = [
|
|
87
|
+
chalk.hex('#1a1b26'),
|
|
88
|
+
chalk.hex('#1a1b26'),
|
|
89
|
+
chalk.hex('#292e42'),
|
|
90
|
+
chalk.hex('#292e42'),
|
|
91
|
+
chalk.hex('#3b4261'),
|
|
92
|
+
];
|
|
93
|
+
const lines = [];
|
|
94
|
+
for (let y = 0; y < rows; y++) {
|
|
95
|
+
const d = Math.abs(y - cy) / Math.max(cy, 1);
|
|
96
|
+
const brightness = 1 - d;
|
|
97
|
+
const segW = Math.max(0, Math.floor(cols * brightness * 0.85));
|
|
98
|
+
const pad = Math.floor((cols - segW) / 2);
|
|
99
|
+
if (segW < 4) {
|
|
100
|
+
lines.push(' '.repeat(cols));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const si = Math.min(Math.floor(brightness * shades.length), shades.length - 1);
|
|
104
|
+
const shade = shades[si];
|
|
105
|
+
// Thin lines with periodic breaks — creates a lens/field shape
|
|
106
|
+
let seg = '';
|
|
107
|
+
for (let x = 0; x < segW; x++) {
|
|
108
|
+
if (x === 0 || x === segW - 1)
|
|
109
|
+
seg += shade('·');
|
|
110
|
+
else if (x % 12 === 0)
|
|
111
|
+
seg += shade('·');
|
|
112
|
+
else
|
|
113
|
+
seg += shade('─');
|
|
114
|
+
}
|
|
115
|
+
lines.push(' '.repeat(pad) + seg + ' '.repeat(Math.max(0, cols - pad - segW)));
|
|
116
|
+
}
|
|
117
|
+
return lines;
|
|
71
118
|
}
|
|
72
119
|
export async function renderIntro(name) {
|
|
73
120
|
const firstName = name?.split(' ')[0] || name;
|
|
74
121
|
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
75
122
|
const city = tz.split('/').pop()?.replace(/_/g, ' ') || '';
|
|
76
|
-
// Fire weather fetch
|
|
123
|
+
// Fire weather fetch while animation runs
|
|
77
124
|
const weatherP = city ? fetchWeather(city) : Promise.resolve(null);
|
|
125
|
+
const cols = process.stdout.columns || 80;
|
|
126
|
+
const rows = process.stdout.rows || 24;
|
|
127
|
+
// Push old content out of scrollback
|
|
128
|
+
process.stdout.write('\n'.repeat(rows * 2));
|
|
129
|
+
process.stdout.write('\x1Bc');
|
|
130
|
+
process.stdout.write('\x1B[?25l');
|
|
131
|
+
// === Phase 1: Geometric scan field ===
|
|
132
|
+
const field = renderScanField(cols, rows);
|
|
133
|
+
for (let y = 0; y < field.length; y++) {
|
|
134
|
+
process.stdout.write(`\x1B[${y + 1};1H${field[y]}`);
|
|
135
|
+
await _sleep(12);
|
|
136
|
+
}
|
|
137
|
+
await _sleep(350);
|
|
138
|
+
// === Phase 2: Greeting ===
|
|
78
139
|
process.stdout.write('\x1Bc');
|
|
79
140
|
process.stdout.write('\n');
|
|
80
|
-
//
|
|
141
|
+
// "Hey Molly."
|
|
81
142
|
const hey = firstName ? `Hey ${firstName}.` : 'Hey.';
|
|
82
143
|
process.stdout.write(' ');
|
|
83
|
-
await typewrite(hey, G1,
|
|
84
|
-
process.stdout.write('\n');
|
|
85
|
-
await _sleep(300);
|
|
86
|
-
// Line 2: "Los Angeles, 68° and sunny."
|
|
87
|
-
const weather = await weatherP;
|
|
88
|
-
const line2 = weather ? `${city}, ${weather}.` : `${city}.`;
|
|
89
|
-
process.stdout.write(' ');
|
|
90
|
-
await typewrite(line2, G2, 25);
|
|
144
|
+
await typewrite(hey, G1, 35);
|
|
91
145
|
process.stdout.write('\n');
|
|
92
146
|
await _sleep(250);
|
|
93
|
-
//
|
|
147
|
+
// "I see you're in Los Angeles. 72° and sunny out there."
|
|
148
|
+
const weather = await weatherP;
|
|
149
|
+
const locLine = weather
|
|
150
|
+
? `I see you're in ${city}. ${weatherRemark(weather)}`
|
|
151
|
+
: city ? `I see you're in ${city}.` : '';
|
|
152
|
+
if (locLine) {
|
|
153
|
+
process.stdout.write(' ');
|
|
154
|
+
await typewrite(locLine, G2, 20);
|
|
155
|
+
process.stdout.write('\n');
|
|
156
|
+
await _sleep(200);
|
|
157
|
+
}
|
|
158
|
+
// "Hope you're having an incredible morning."
|
|
94
159
|
const h = new Date().getHours();
|
|
95
160
|
process.stdout.write(' ');
|
|
96
|
-
await typewrite(
|
|
161
|
+
await typewrite(timeGreeting(h), G3, 18);
|
|
97
162
|
process.stdout.write('\n\n');
|
|
98
163
|
if (USE_INK)
|
|
99
164
|
ink.initInk();
|