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.
Files changed (2) hide show
  1. package/dist/tui.js +89 -24
  2. 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
- // ─── Typewriter intro ───
29
+ // ─── Intro ───
30
30
  import chalk from 'chalk';
31
31
  const _sleep = (ms) => new Promise(r => setTimeout(r, ms));
32
- // Three-tier gold — fades like candlelight
33
- const G1 = chalk.hex('#d4a574'); // warm amber (name)
34
- const G2 = chalk.hex('#a8885c'); // muted gold (city + weather)
35
- const G3 = chalk.hex('#7a6544'); // whisper (closing)
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 closingLine(h) {
60
+ function timeGreeting(h) {
62
61
  if (h < 5)
63
- return "don't stay up too late.";
62
+ return "Don't stay up too late.";
64
63
  if (h < 12)
65
- return 'hope you have a beautiful day.';
64
+ return 'Hope you have an incredible morning.';
66
65
  if (h < 17)
67
- return "hope you're having a lovely afternoon.";
66
+ return "Hope you're having a wonderful afternoon.";
68
67
  if (h < 21)
69
- return "hope you're having a wonderful evening.";
70
- return "don't stay up too late.";
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 immediately runs while we type the name
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
- // Line 1: "Hey Molly."
141
+ // "Hey Molly."
81
142
  const hey = firstName ? `Hey ${firstName}.` : 'Hey.';
82
143
  process.stdout.write(' ');
83
- await typewrite(hey, G1, 40);
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
- // Line 3: "Hope you're having a wonderful evening."
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(closingLine(h), G3, 22);
161
+ await typewrite(timeGreeting(h), G3, 18);
97
162
  process.stdout.write('\n\n');
98
163
  if (USE_INK)
99
164
  ink.initInk();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "life-pulse",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "macOS life diagnostic — reads local data sources, generates actionable insights",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {