drexler 0.2.18 → 0.2.20
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/package.json +1 -1
- package/src/ui/MascotIntro.tsx +1 -1
- package/src/ui/PetPanel.tsx +120 -28
package/package.json
CHANGED
package/src/ui/MascotIntro.tsx
CHANGED
|
@@ -171,7 +171,7 @@ const RIGHT_COLUMN_PAD_RIGHT = 1;
|
|
|
171
171
|
const LEFT_PANEL_MIN_COPY = 24;
|
|
172
172
|
const PET_STATS_MIN_WIDTH = 24;
|
|
173
173
|
const PET_STATS_MAX_WIDTH = 58;
|
|
174
|
-
const PET_SPLIT_DIVIDER_HEIGHT =
|
|
174
|
+
const PET_SPLIT_DIVIDER_HEIGHT = 17;
|
|
175
175
|
const PET_SPLIT_DIVIDER_ROWS: number[] = Array.from(
|
|
176
176
|
{ length: PET_SPLIT_DIVIDER_HEIGHT },
|
|
177
177
|
(_, i) => i,
|
package/src/ui/PetPanel.tsx
CHANGED
|
@@ -18,14 +18,15 @@ export type Environment = "office" | "home" | "outdoors";
|
|
|
18
18
|
|
|
19
19
|
const PANEL_BORDER_COLUMNS = 2;
|
|
20
20
|
const PANEL_PADDING_COLUMNS = 2;
|
|
21
|
-
const SCENE_ROWS =
|
|
21
|
+
const SCENE_ROWS = 16;
|
|
22
22
|
const R_WALL = 0;
|
|
23
23
|
const R_WINDOW_TOP = 1;
|
|
24
|
-
const R_WINDOW_BOTTOM =
|
|
25
|
-
const R_ACTIVITY =
|
|
26
|
-
const R_MASCOT_START =
|
|
24
|
+
const R_WINDOW_BOTTOM = 4;
|
|
25
|
+
const R_ACTIVITY = 5;
|
|
26
|
+
const R_MASCOT_START = 6;
|
|
27
27
|
const R_DESK_SURFACE = R_MASCOT_START + BRIEFCASE_FINAL.length;
|
|
28
28
|
const R_DESK_FRONT = R_DESK_SURFACE + 1;
|
|
29
|
+
const R_FLOOR = R_DESK_FRONT + 1;
|
|
29
30
|
|
|
30
31
|
export const PET_SCENE_WIDTH = 52;
|
|
31
32
|
|
|
@@ -73,23 +74,33 @@ function sceneBoxBottom(width: number): string {
|
|
|
73
74
|
return `╰${"─".repeat(safeWidth - 2)}╯`;
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
function
|
|
77
|
+
function placeBoxLines(
|
|
77
78
|
rows: string[],
|
|
78
79
|
row: number,
|
|
79
80
|
x: number,
|
|
80
81
|
width: number,
|
|
81
82
|
title: string,
|
|
82
|
-
body: string,
|
|
83
|
+
body: readonly string[],
|
|
83
84
|
): void {
|
|
84
85
|
rows[row] = place(rows[row] ?? "", sceneBoxTop(title, width), x);
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
for (let i = 0; i < body.length; i++) {
|
|
87
|
+
rows[row + i + 1] = place(
|
|
88
|
+
rows[row + i + 1] ?? "",
|
|
89
|
+
sceneBoxBody(body[i] ?? "", width),
|
|
90
|
+
x,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
rows[row + body.length + 1] = place(
|
|
94
|
+
rows[row + body.length + 1] ?? "",
|
|
95
|
+
sceneBoxBottom(width),
|
|
96
|
+
x,
|
|
97
|
+
);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
function cupForEnergy(energy: number): string {
|
|
90
|
-
if (energy > 60) return "
|
|
91
|
-
if (energy > 30) return "
|
|
92
|
-
return "
|
|
101
|
+
if (energy > 60) return "[c~]";
|
|
102
|
+
if (energy > 30) return "[c-]";
|
|
103
|
+
return "[c_]";
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
function progressTicker(frame: number): string {
|
|
@@ -199,16 +210,25 @@ function drawOfficeBackground(rows: string[], width: number, frame: number, stat
|
|
|
199
210
|
const windowWidth = Math.min(22, Math.max(16, Math.floor(width * 0.36)));
|
|
200
211
|
const boardWidth = Math.min(28, Math.max(20, width - windowWidth - 6));
|
|
201
212
|
const boardX = Math.max(windowWidth + 4, width - boardWidth - 2);
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
213
|
+
const cloud = frame % 6 < 3 ? "(~~)" : " (~~)";
|
|
214
|
+
const sun = frame % 12 < 6 ? "\\o/" : "-o-";
|
|
215
|
+
const tape = frame % 8 < 4 ? "▁▃▅▇" : "▂▄▆█";
|
|
216
|
+
const cursor = frame % 4 < 2 ? ">" : "*";
|
|
217
|
+
|
|
218
|
+
placeBoxLines(rows, R_WINDOW_TOP, 1, windowWidth, "Window", [
|
|
219
|
+
`${sun} ${cloud}`,
|
|
220
|
+
"║║ ║║ skyline",
|
|
221
|
+
]);
|
|
222
|
+
placeBoxLines(
|
|
206
223
|
rows,
|
|
207
224
|
R_WINDOW_TOP,
|
|
208
225
|
boardX,
|
|
209
226
|
Math.min(boardWidth, width - boardX),
|
|
210
227
|
"Deal Board",
|
|
211
|
-
|
|
228
|
+
[
|
|
229
|
+
`DL:${dealPct} fees:${Math.round(stats.happiness)}%`,
|
|
230
|
+
`PIPE ${tape} ${cursor}`,
|
|
231
|
+
],
|
|
212
232
|
);
|
|
213
233
|
|
|
214
234
|
rows[R_ACTIVITY] = centerText(
|
|
@@ -217,6 +237,28 @@ function drawOfficeBackground(rows: string[], width: number, frame: number, stat
|
|
|
217
237
|
);
|
|
218
238
|
}
|
|
219
239
|
|
|
240
|
+
function drawOfficeFurniture(rows: string[], width: number, frame: number): void {
|
|
241
|
+
const lampX = 2;
|
|
242
|
+
const fileX = Math.max(1, width - 10);
|
|
243
|
+
const lampLight = frame % 8 < 4 ? "\\|/" : " | ";
|
|
244
|
+
const plantLeaves = frame % 6 < 3 ? "\\|/" : "v|v";
|
|
245
|
+
|
|
246
|
+
rows[R_MASCOT_START] = place(rows[R_MASCOT_START], ` ${lampLight} `, lampX);
|
|
247
|
+
rows[R_MASCOT_START + 1] = place(rows[R_MASCOT_START + 1], " /_\\ ", lampX);
|
|
248
|
+
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], " /___\\", lampX);
|
|
249
|
+
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], " │ ", lampX);
|
|
250
|
+
rows[R_MASCOT_START + 4] = place(rows[R_MASCOT_START + 4], " ╭IN╮ ", lampX);
|
|
251
|
+
rows[R_MASCOT_START + 5] = place(rows[R_MASCOT_START + 5], " ╰──╯ ", lampX);
|
|
252
|
+
|
|
253
|
+
rows[R_MASCOT_START] = place(rows[R_MASCOT_START], ` ${plantLeaves} `, fileX);
|
|
254
|
+
rows[R_MASCOT_START + 1] = place(rows[R_MASCOT_START + 1], " \\|/ ", fileX);
|
|
255
|
+
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], " ╰┬╯ ", fileX);
|
|
256
|
+
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], "╭FILE╮", fileX - 1);
|
|
257
|
+
rows[R_MASCOT_START + 4] = place(rows[R_MASCOT_START + 4], "│▤▤▤│", fileX - 1);
|
|
258
|
+
rows[R_MASCOT_START + 5] = place(rows[R_MASCOT_START + 5], "│▤▤▤│", fileX - 1);
|
|
259
|
+
rows[R_MASCOT_START + 6] = place(rows[R_MASCOT_START + 6], "╰────╯", fileX - 1);
|
|
260
|
+
}
|
|
261
|
+
|
|
220
262
|
function drawActivityAccents(
|
|
221
263
|
rows: string[],
|
|
222
264
|
width: number,
|
|
@@ -231,34 +273,37 @@ function drawActivityAccents(
|
|
|
231
273
|
|
|
232
274
|
const mascotRight = mascotX + MASCOT_WIDTH;
|
|
233
275
|
const leftAccentX = Math.max(1, mascotX - 10);
|
|
234
|
-
const
|
|
276
|
+
const fileX = Math.max(1, width - 10);
|
|
277
|
+
const rightAccentX = Math.min(fileX - 5, mascotRight + 2);
|
|
235
278
|
|
|
236
279
|
switch (activity) {
|
|
237
280
|
case "eating":
|
|
238
|
-
rows[
|
|
281
|
+
rows[R_MASCOT_START + 5] = place(
|
|
282
|
+
rows[R_MASCOT_START + 5],
|
|
283
|
+
"[$] memo",
|
|
284
|
+
Math.max(1, Math.min(fileX - 8, rightAccentX)),
|
|
285
|
+
);
|
|
239
286
|
break;
|
|
240
287
|
case "playing":
|
|
241
288
|
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], "*", leftAccentX);
|
|
242
|
-
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], "*", rightAccentX + 6);
|
|
289
|
+
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], "*", Math.min(fileX - 2, rightAccentX + 6));
|
|
243
290
|
break;
|
|
244
291
|
case "working":
|
|
245
292
|
rows[R_MASCOT_START + 1] = place(rows[R_MASCOT_START + 1], "$", leftAccentX);
|
|
246
|
-
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], "$", rightAccentX + 6);
|
|
293
|
+
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], "$", Math.min(fileX - 2, rightAccentX + 6));
|
|
247
294
|
break;
|
|
248
295
|
case "sleeping":
|
|
249
296
|
rows[R_MASCOT_START] = place(rows[R_MASCOT_START], "z z Z", rightAccentX);
|
|
250
297
|
break;
|
|
251
298
|
case "praised":
|
|
252
299
|
rows[R_MASCOT_START + 1] = place(rows[R_MASCOT_START + 1], "* *", leftAccentX);
|
|
253
|
-
rows[R_MASCOT_START + 1] = place(rows[R_MASCOT_START + 1], "* *", rightAccentX + 4);
|
|
300
|
+
rows[R_MASCOT_START + 1] = place(rows[R_MASCOT_START + 1], "* *", Math.min(fileX - 4, rightAccentX + 4));
|
|
254
301
|
break;
|
|
255
302
|
case "vibing":
|
|
256
303
|
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], "~ ~", leftAccentX);
|
|
257
|
-
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], "~ ~", rightAccentX + 4);
|
|
304
|
+
rows[R_MASCOT_START + 3] = place(rows[R_MASCOT_START + 3], "~ ~", Math.min(fileX - 4, rightAccentX + 4));
|
|
258
305
|
break;
|
|
259
306
|
default:
|
|
260
|
-
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], "[IN]", 2);
|
|
261
|
-
rows[R_MASCOT_START + 2] = place(rows[R_MASCOT_START + 2], "[OUT]", Math.max(2, width - 8));
|
|
262
307
|
break;
|
|
263
308
|
}
|
|
264
309
|
}
|
|
@@ -276,12 +321,52 @@ function drawMascot(rows: string[], width: number, activity: PetActivity, frame:
|
|
|
276
321
|
return mascotX;
|
|
277
322
|
}
|
|
278
323
|
|
|
324
|
+
function drawDesktopObjects(
|
|
325
|
+
rows: string[],
|
|
326
|
+
width: number,
|
|
327
|
+
activity: PetActivity,
|
|
328
|
+
frame: number,
|
|
329
|
+
stats: PetStats,
|
|
330
|
+
): void {
|
|
331
|
+
const mascotX = Math.max(0, Math.floor((width - MASCOT_WIDTH) / 2));
|
|
332
|
+
const mascotRight = mascotX + MASCOT_WIDTH;
|
|
333
|
+
const fileX = Math.max(1, width - 10);
|
|
334
|
+
const laptopX = Math.max(8, mascotX - 10);
|
|
335
|
+
const papersX = Math.min(width - 5, mascotX + MASCOT_WIDTH + 1);
|
|
336
|
+
const coffeeX = fileX - 13;
|
|
337
|
+
const cursor = frame % 2 === 0 ? "_" : " ";
|
|
338
|
+
const screen =
|
|
339
|
+
activity === "working"
|
|
340
|
+
? `$>${cursor} DL`
|
|
341
|
+
: activity === "sleeping"
|
|
342
|
+
? "zzz..."
|
|
343
|
+
: "DREX";
|
|
344
|
+
const steam = stats.energy > 30
|
|
345
|
+
? frame % 4 < 2 ? " ((" : " ))"
|
|
346
|
+
: " ";
|
|
347
|
+
const paperFace = frame % 6 < 3 ? "////" : "\\\\\\\\";
|
|
348
|
+
|
|
349
|
+
rows[R_MASCOT_START + 4] = place(rows[R_MASCOT_START + 4], "╭laptop─╮", laptopX);
|
|
350
|
+
rows[R_MASCOT_START + 5] = place(
|
|
351
|
+
rows[R_MASCOT_START + 5],
|
|
352
|
+
`│${padDisplayText(screen, 7)}│`,
|
|
353
|
+
laptopX,
|
|
354
|
+
);
|
|
355
|
+
rows[R_MASCOT_START + 6] = place(rows[R_MASCOT_START + 6], "╰─┬──┬─╯", laptopX);
|
|
356
|
+
rows[R_MASCOT_START + 6] = place(rows[R_MASCOT_START + 6], paperFace, papersX);
|
|
357
|
+
if (coffeeX > mascotRight + 1) {
|
|
358
|
+
rows[R_MASCOT_START + 4] = place(rows[R_MASCOT_START + 4], steam, coffeeX + 1);
|
|
359
|
+
rows[R_MASCOT_START + 5] = place(rows[R_MASCOT_START + 5], `coffee ${cupForEnergy(stats.energy)}`, coffeeX);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
279
363
|
function drawDesk(rows: string[], width: number, stats: PetStats): void {
|
|
280
364
|
const deskX = width > PET_SCENE_WIDTH ? 2 : 1;
|
|
281
365
|
const deskWidth = Math.max(4, width - deskX * 2);
|
|
282
366
|
const deskInner = Math.max(1, deskWidth - 2);
|
|
283
|
-
const surface = `
|
|
284
|
-
const
|
|
367
|
+
const surface = `papers [///] coffee ${cupForEnergy(stats.energy)} covenants OK`;
|
|
368
|
+
const centerLabel = `DREXLER DEAL DESK pipeline ${Math.round(stats.deals)}%`;
|
|
369
|
+
const front = `[IN] ${centerLabel} [OUT]`;
|
|
285
370
|
|
|
286
371
|
rows[R_DESK_SURFACE] = place(
|
|
287
372
|
rows[R_DESK_SURFACE],
|
|
@@ -290,7 +375,12 @@ function drawDesk(rows: string[], width: number, stats: PetStats): void {
|
|
|
290
375
|
);
|
|
291
376
|
rows[R_DESK_FRONT] = place(
|
|
292
377
|
rows[R_DESK_FRONT],
|
|
293
|
-
|
|
378
|
+
`│${padDisplayText(front, deskInner)}│`,
|
|
379
|
+
deskX,
|
|
380
|
+
);
|
|
381
|
+
rows[R_FLOOR] = place(
|
|
382
|
+
rows[R_FLOOR],
|
|
383
|
+
`╰${"─".repeat(Math.max(0, deskInner))}╯`,
|
|
294
384
|
deskX,
|
|
295
385
|
);
|
|
296
386
|
}
|
|
@@ -305,8 +395,10 @@ function buildScene(
|
|
|
305
395
|
const rows: string[] = Array.from({ length: SCENE_ROWS }, () => blankRow(sceneWidth));
|
|
306
396
|
|
|
307
397
|
drawOfficeBackground(rows, sceneWidth, frame, stats);
|
|
308
|
-
|
|
398
|
+
drawOfficeFurniture(rows, sceneWidth, frame);
|
|
309
399
|
const mascotX = drawMascot(rows, sceneWidth, activity, frame);
|
|
400
|
+
drawDesktopObjects(rows, sceneWidth, activity, frame, stats);
|
|
401
|
+
drawDesk(rows, sceneWidth, stats);
|
|
310
402
|
drawActivityAccents(rows, sceneWidth, activity, frame, mascotX);
|
|
311
403
|
return rows.map((row) => overlayFitted(blankRow(sceneWidth), row, 0, sceneWidth));
|
|
312
404
|
}
|