@astralyn/pi 1.0.0 → 1.0.1
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/CHANGELOG.md +19 -0
- package/dist/bundle/chunks/{anthropic-messages-CG2BSDQS.js → anthropic-messages-YET4T7BO.js} +3 -3
- package/dist/bundle/chunks/azure-openai-responses-SBLL5YN3.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
- package/dist/bundle/chunks/{chunk-SGLYRVQL.js → chunk-4TT2QGFL.js} +1 -1
- package/dist/bundle/chunks/{chunk-HESRDUKO.js → chunk-H2N2THAO.js} +72 -52
- package/dist/bundle/chunks/{chunk-PFZKRUMO.js → chunk-IZ3S3GDX.js} +1 -1
- package/dist/bundle/chunks/{chunk-6UFFVA7M.js → chunk-NY3CWK44.js} +1 -1
- package/dist/bundle/chunks/chunk-SVJ7OGEB.js +2 -0
- package/dist/bundle/chunks/chunk-XDYM2567.js +20 -0
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-YB7XPPP4.js → cloudflare-workers-ai-system-one-QI46LUZ6.js} +1 -1
- package/dist/bundle/chunks/codemode-worker.js +24 -3
- package/dist/bundle/chunks/{google-generative-ai-V5ZM5MCL.js → google-generative-ai-YTZCSHQN.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-22THOFP5.js → google-vertex-OTFZJJXQ.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-WHSCJJWP.js → mistral-conversations-ELH4V4TY.js} +1 -1
- package/dist/bundle/chunks/node-USQQ7C6M.js +16 -0
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-N7GDPBPP.js → openai-codex-responses-OLVTU4UA.js} +1 -1
- package/dist/bundle/chunks/openai-completions-53M2KJ67.js +7 -0
- package/dist/bundle/chunks/openai-responses-4ABDEL4Z.js +3 -0
- package/dist/bundle/chunks/{virtual-modules-4RQ2L6W4.js → virtual-modules-YFKU7JZF.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +4 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts +3 -3
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +3 -3
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +9 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/mcp-servers.d.ts +6 -0
- package/dist/core/mcp-servers.d.ts.map +1 -1
- package/dist/core/mcp-servers.js +11 -0
- package/dist/core/mcp-servers.js.map +1 -1
- package/dist/core/model-config.d.ts +36 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +14 -2
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-composer.d.ts +2 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +13 -0
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/tools/renderers/index.d.ts +2 -2
- package/dist/core/tools/renderers/index.d.ts.map +1 -1
- package/dist/core/tools/renderers/index.js.map +1 -1
- package/dist/extensions/mcp/cli.d.ts.map +1 -1
- package/dist/extensions/mcp/cli.js +3 -0
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/config.d.ts +15 -3
- package/dist/extensions/mcp/config.d.ts.map +1 -1
- package/dist/extensions/mcp/config.js +46 -10
- package/dist/extensions/mcp/config.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts +4 -1
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +80 -45
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +4 -1
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +54 -10
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +1 -0
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +3 -1
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +19 -13
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/extensions/mcp/ui.d.ts.map +1 -1
- package/dist/extensions/mcp/ui.js +8 -4
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts +3 -0
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +7 -5
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/auth-url.d.ts +14 -0
- package/dist/modes/interactive/components/auth-url.d.ts.map +1 -0
- package/dist/modes/interactive/components/auth-url.js +34 -0
- package/dist/modes/interactive/components/auth-url.js.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.d.ts +104 -0
- package/dist/modes/interactive/components/easter-egg-3d.d.ts.map +1 -0
- package/dist/modes/interactive/components/{pi-logo-animation.js → easter-egg-3d.js} +121 -74
- package/dist/modes/interactive/components/easter-egg-3d.js.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts +6 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.d.ts.map +1 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.js +24 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +2 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +9 -5
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +15 -17
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tool-view/tool-execution.d.ts +4 -19
- package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/tool-view/tool-execution.js +23 -67
- package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
- package/dist/utils/image-convert.d.ts +12 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +45 -6
- package/dist/utils/image-convert.js.map +1 -1
- package/docs/codemode.md +1 -1
- package/docs/extensions.md +4 -0
- package/docs/keybindings.md +1 -1
- package/docs/mcp.md +23 -1
- package/docs/models.md +30 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +58 -58
- package/package.json +11 -11
- package/dist/bundle/chunks/azure-openai-responses-PBA4QKCM.js +0 -2
- package/dist/bundle/chunks/chunk-PJVFYVHE.js +0 -42
- package/dist/bundle/chunks/chunk-Z2RKSI3O.js +0 -2
- package/dist/bundle/chunks/node-CXWYTK2I.js +0 -16
- package/dist/bundle/chunks/openai-completions-RGGQK5UW.js +0 -7
- package/dist/bundle/chunks/openai-responses-3ZLD5JYI.js +0 -3
- package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
- package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
- package/dist/modes/interactive/components/daxnuts.js +0 -138
- package/dist/modes/interactive/components/daxnuts.js.map +0 -1
- package/dist/modes/interactive/components/pi-logo-animation.d.ts +0 -68
- package/dist/modes/interactive/components/pi-logo-animation.d.ts.map +0 -1
- package/dist/modes/interactive/components/pi-logo-animation.js.map +0 -1
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts +0 -7
- package/dist/modes/interactive/components/pi-logo-animation.lazy.d.ts.map +0 -1
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js +0 -12
- package/dist/modes/interactive/components/pi-logo-animation.lazy.js.map +0 -1
|
@@ -1,23 +1,56 @@
|
|
|
1
1
|
import { backgroundAnsi, colorToRgb, foregroundAnsi, getKeybindings, indexedColor, rgbColor, visibleWidth, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { theme } from "../theme/theme.js";
|
|
3
|
+
import { ARMIN_HEIGHT, ARMIN_WIDTH, isArminPixel } from "./armin.js";
|
|
3
4
|
import { formatKeyText } from "./keybinding-hints.js";
|
|
4
|
-
const CORAL = [228, 138, 122];
|
|
5
|
-
const BLUE = [79, 142, 179];
|
|
6
|
-
const YELLOW = [234, 182, 93];
|
|
7
5
|
const DEPTH = 0.7;
|
|
8
|
-
const CAMERA_DISTANCE = 10;
|
|
9
6
|
const FLY_START = 0.1;
|
|
10
7
|
const FLY_DURATION = 1.3;
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
/** Braille dots per pixel when a model without an origin appears, growing from a speck at the center. */
|
|
9
|
+
const START_SCALE = 0.1;
|
|
10
|
+
function createModel(columns, rows, pixel, options) {
|
|
11
|
+
const blocks = [];
|
|
12
|
+
for (let row = 0; row < rows; row++) {
|
|
13
|
+
for (let column = 0; column < columns; column++) {
|
|
14
|
+
const color = pixel(column, row);
|
|
15
|
+
if (color)
|
|
16
|
+
blocks.push({ home: [column, row, 0], color });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
columns,
|
|
21
|
+
rows,
|
|
22
|
+
blocks,
|
|
23
|
+
cameraDistance: options.cameraDistance,
|
|
24
|
+
radius: Math.hypot(columns / 2, rows / 2, 1 + DEPTH / 2),
|
|
25
|
+
widthShare: options.widthShare,
|
|
26
|
+
puzzleMoves: (random) => options.puzzleMoves(random, blocks.length),
|
|
27
|
+
origin: options.origin,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const CORAL = [228, 138, 122];
|
|
31
|
+
const BLUE = [79, 142, 179];
|
|
32
|
+
const YELLOW = [234, 182, 93];
|
|
33
|
+
const PI_LOGO_PIXELS = ["ccc.", "b.c.", "bb.y", "b..y"];
|
|
34
|
+
const PI_LOGO_COLORS = { c: CORAL, b: BLUE, y: YELLOW };
|
|
35
|
+
function piLogoModel(origin) {
|
|
36
|
+
return createModel(4, 4, (column, row) => PI_LOGO_COLORS[PI_LOGO_PIXELS[row][column]], {
|
|
37
|
+
cameraDistance: 10,
|
|
38
|
+
widthShare: 0.35,
|
|
39
|
+
puzzleMoves: (random) => (random < 0.4 ? 2 : 1),
|
|
40
|
+
origin,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function arminModel(color) {
|
|
44
|
+
return createModel(ARMIN_WIDTH, ARMIN_HEIGHT, (column, row) => (isArminPixel(column, row) ? color : undefined), {
|
|
45
|
+
// Far enough that the perspective stays mild for a figure about 36 blocks tall.
|
|
46
|
+
cameraDistance: 80,
|
|
47
|
+
widthShare: 0.45,
|
|
48
|
+
puzzleMoves: (random, blockCount) => Math.round(blockCount * (0.03 + random * 0.04)),
|
|
49
|
+
origin: undefined,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// The sliding puzzle: after the model spun for a while, blocks slide into free neighboring cells, a few at a time.
|
|
53
|
+
// Each cycle shuffles, flies every block back home, and holds the model briefly.
|
|
21
54
|
const PUZZLE_START = FLY_START + FLY_DURATION + 3;
|
|
22
55
|
const PUZZLE_STEP = 0.3;
|
|
23
56
|
const PUZZLE_STEPS = 12;
|
|
@@ -37,18 +70,19 @@ const PUZZLE_MOVES = [
|
|
|
37
70
|
[0, 0, -1],
|
|
38
71
|
];
|
|
39
72
|
/** Block positions after each step of one shuffle cycle, starting at home. Deterministic per cycle. */
|
|
40
|
-
function shuffleSteps(cycle) {
|
|
41
|
-
|
|
73
|
+
function shuffleSteps(model, cycle) {
|
|
74
|
+
const { columns, rows } = model;
|
|
75
|
+
let positions = model.blocks.map((block) => block.home);
|
|
42
76
|
const steps = [positions];
|
|
43
77
|
const lastMoved = new Set();
|
|
44
78
|
let random = cycle * 7_919 + 1;
|
|
45
79
|
const next = () => hash(random++);
|
|
46
|
-
const key = ([x, y, z]) => (z + 1) *
|
|
80
|
+
const key = ([x, y, z]) => ((z + 1) * rows + y) * columns + x;
|
|
47
81
|
for (let step = 0; step < PUZZLE_STEPS; step++) {
|
|
48
82
|
const occupied = new Set(positions.map(key));
|
|
49
83
|
const nextPositions = [...positions];
|
|
50
84
|
const moved = new Set();
|
|
51
|
-
const moveCount = next()
|
|
85
|
+
const moveCount = model.puzzleMoves(next());
|
|
52
86
|
for (let move = 0; move < moveCount; move++) {
|
|
53
87
|
const candidates = [];
|
|
54
88
|
for (let block = 0; block < positions.length; block++) {
|
|
@@ -57,7 +91,7 @@ function shuffleSteps(cycle) {
|
|
|
57
91
|
const [x, y, z] = positions[block];
|
|
58
92
|
for (const [dx, dy, dz] of PUZZLE_MOVES) {
|
|
59
93
|
const target = [x + dx, y + dy, z + dz];
|
|
60
|
-
if (target[0] < 0 || target[0]
|
|
94
|
+
if (target[0] < 0 || target[0] >= columns || target[1] < 0 || target[1] >= rows)
|
|
61
95
|
continue;
|
|
62
96
|
if (target[2] < -1 || target[2] > 1 || occupied.has(key(target)))
|
|
63
97
|
continue;
|
|
@@ -335,12 +369,12 @@ function spinAngle(time) {
|
|
|
335
369
|
return phase - SPIN_LINGER * Math.sin(phase);
|
|
336
370
|
}
|
|
337
371
|
/**
|
|
338
|
-
* Renders the
|
|
372
|
+
* Renders the model's blocks into braille cells. Only faces that point at the camera and are not covered by a
|
|
339
373
|
* touching block are drawn. Each face is rasterized over its projected bounds by intersecting each dot's ray
|
|
340
374
|
* with the face's plane, with a depth buffer resolving overlaps. Buffers are reused between frames.
|
|
341
375
|
*/
|
|
342
|
-
class
|
|
343
|
-
constructor() {
|
|
376
|
+
class BlockRaster {
|
|
377
|
+
constructor(cameraDistance) {
|
|
344
378
|
/** Braille dot bits per cell. */
|
|
345
379
|
this.bits = new Uint8Array(0);
|
|
346
380
|
/** Lit dots per cell. */
|
|
@@ -356,7 +390,8 @@ class LogoRaster {
|
|
|
356
390
|
/** Ray parameter of the nearest hit per dot; smaller is nearer. */
|
|
357
391
|
this.depth = new Float32Array(0);
|
|
358
392
|
/** Face index + 1 of the nearest hit per dot, 0 for none. */
|
|
359
|
-
this.faceIds = new
|
|
393
|
+
this.faceIds = new Uint16Array(0);
|
|
394
|
+
this.cameraDistance = cameraDistance;
|
|
360
395
|
}
|
|
361
396
|
render(width, height, pose, boxes, background, haloStrength) {
|
|
362
397
|
const dotWidth = width * 2;
|
|
@@ -371,7 +406,7 @@ class LogoRaster {
|
|
|
371
406
|
this.haloRgb = new Float32Array(width * height * 3);
|
|
372
407
|
this.haloDirty = undefined;
|
|
373
408
|
this.depth = new Float32Array(dotWidth * dotHeight).fill(Infinity);
|
|
374
|
-
this.faceIds = new
|
|
409
|
+
this.faceIds = new Uint16Array(dotWidth * dotHeight);
|
|
375
410
|
this.dirty = undefined;
|
|
376
411
|
}
|
|
377
412
|
else if (this.dirty) {
|
|
@@ -393,8 +428,9 @@ class LogoRaster {
|
|
|
393
428
|
}
|
|
394
429
|
const m = rotation(pose.yaw, pose.pitch, pose.roll);
|
|
395
430
|
const { centerX, centerY, scale } = pose;
|
|
396
|
-
|
|
397
|
-
|
|
431
|
+
const cameraDistance = this.cameraDistance;
|
|
432
|
+
// The camera sits at (0, 0, cameraDistance) in camera space; object space is the transpose rotation.
|
|
433
|
+
const origin = [m[6] * cameraDistance, m[7] * cameraDistance, m[8] * cameraDistance];
|
|
398
434
|
const light = isLight(background);
|
|
399
435
|
const faces = this.visibleFaces(m, origin, pose, boxes, dotWidth, dotHeight, light);
|
|
400
436
|
if (faces.length === 0)
|
|
@@ -428,9 +464,9 @@ class LogoRaster {
|
|
|
428
464
|
const sx = (face.minX + 0.5 - centerX) / scale;
|
|
429
465
|
for (let dotY = face.minY; dotY <= face.maxY; dotY++) {
|
|
430
466
|
const sy = (dotY + 0.5 - centerY) / scale;
|
|
431
|
-
let directionA = m[a] * sx + m[3 + a] * sy - m[6 + a] *
|
|
432
|
-
let directionU = m[u] * sx + m[3 + u] * sy - m[6 + u] *
|
|
433
|
-
let directionV = m[v] * sx + m[3 + v] * sy - m[6 + v] *
|
|
467
|
+
let directionA = m[a] * sx + m[3 + a] * sy - m[6 + a] * cameraDistance;
|
|
468
|
+
let directionU = m[u] * sx + m[3 + u] * sy - m[6 + u] * cameraDistance;
|
|
469
|
+
let directionV = m[v] * sx + m[3 + v] * sy - m[6 + v] * cameraDistance;
|
|
434
470
|
let index = dotY * dotWidth + face.minX;
|
|
435
471
|
for (let dotX = face.minX; dotX <= face.maxX; dotX++, index++) {
|
|
436
472
|
const t = (face.plane - originA) / directionA;
|
|
@@ -464,7 +500,7 @@ class LogoRaster {
|
|
|
464
500
|
continue;
|
|
465
501
|
const face = faces[id - 1];
|
|
466
502
|
// Points farther from the camera fade slightly toward the background for depth.
|
|
467
|
-
const fog = clamp01(0.15 -
|
|
503
|
+
const fog = clamp01(0.15 - cameraDistance * (1 - depth[index]) * 0.12) * (light ? 0.5 : 1);
|
|
468
504
|
faceIds[index] = 0;
|
|
469
505
|
depth[index] = Infinity;
|
|
470
506
|
const cellX = dotX >> 1;
|
|
@@ -584,6 +620,7 @@ class LogoRaster {
|
|
|
584
620
|
}
|
|
585
621
|
visibleFaces(m, origin, pose, boxes, dotWidth, dotHeight, lightBackground) {
|
|
586
622
|
const faces = [];
|
|
623
|
+
const cameraDistance = this.cameraDistance;
|
|
587
624
|
for (const box of boxes) {
|
|
588
625
|
for (let a = 0; a < 3; a++) {
|
|
589
626
|
const u = (a + 1) % 3;
|
|
@@ -615,7 +652,7 @@ class LogoRaster {
|
|
|
615
652
|
const x = m[0] * corner[0] + m[1] * corner[1] + m[2] * corner[2];
|
|
616
653
|
const y = m[3] * corner[0] + m[4] * corner[1] + m[5] * corner[2];
|
|
617
654
|
const z = m[6] * corner[0] + m[7] * corner[1] + m[8] * corner[2];
|
|
618
|
-
const perspective = (pose.scale *
|
|
655
|
+
const perspective = (pose.scale * cameraDistance) / (cameraDistance - z);
|
|
619
656
|
const screenX = pose.centerX + x * perspective;
|
|
620
657
|
const screenY = pose.centerY + y * perspective;
|
|
621
658
|
minX = Math.min(minX, screenX);
|
|
@@ -670,7 +707,7 @@ let playing = false;
|
|
|
670
707
|
* Show the animation as a fullscreen overlay until it is dismissed. The overlay takes focus and mouse input and
|
|
671
708
|
* returns focus when hidden, so the rest of the UI keeps running underneath untouched.
|
|
672
709
|
*/
|
|
673
|
-
export async function
|
|
710
|
+
export async function playEasterEgg3d(tui, screen, egg) {
|
|
674
711
|
if (playing)
|
|
675
712
|
return;
|
|
676
713
|
playing = true;
|
|
@@ -686,14 +723,15 @@ export async function playPiLogoAnimation(tui, options) {
|
|
|
686
723
|
playing = false;
|
|
687
724
|
return;
|
|
688
725
|
}
|
|
689
|
-
const
|
|
726
|
+
const model = egg.kind === "armin" ? arminModel(toRgb(theme.colors.accent)) : piLogoModel({ column: egg.column, row: egg.row });
|
|
727
|
+
const animation = new EasterEgg3dAnimation(tui, screen, model, colors, () => {
|
|
690
728
|
playing = false;
|
|
691
729
|
overlay.hide();
|
|
692
730
|
});
|
|
693
731
|
const overlay = tui.showOverlay(animation, { anchor: "top-left", width: "100%", maxHeight: "100%" });
|
|
694
732
|
}
|
|
695
|
-
export class
|
|
696
|
-
constructor(tui,
|
|
733
|
+
export class EasterEgg3dAnimation {
|
|
734
|
+
constructor(tui, screen, model, colors, onDone) {
|
|
697
735
|
this.startTime = performance.now();
|
|
698
736
|
this.lastRender = performance.now();
|
|
699
737
|
this.screenWidth = -1;
|
|
@@ -702,9 +740,10 @@ export class PiLogoAnimation {
|
|
|
702
740
|
this.stars = [];
|
|
703
741
|
this.cells = [];
|
|
704
742
|
this.ansiCache = new Map();
|
|
705
|
-
this.logo = new LogoRaster();
|
|
706
743
|
this.tui = tui;
|
|
707
|
-
this.
|
|
744
|
+
this.screen = screen;
|
|
745
|
+
this.model = model;
|
|
746
|
+
this.raster = new BlockRaster(model.cameraDistance);
|
|
708
747
|
this.foreground = colors.foreground;
|
|
709
748
|
this.background = colors.background;
|
|
710
749
|
this.onDone = onDone;
|
|
@@ -789,19 +828,20 @@ export class PiLogoAnimation {
|
|
|
789
828
|
starAlpha = this.starAlpha(time);
|
|
790
829
|
offsets = this.blockOffsets(time);
|
|
791
830
|
}
|
|
792
|
-
const
|
|
831
|
+
const { columns, rows } = this.model;
|
|
832
|
+
const boxes = this.model.blocks.map((block, index) => {
|
|
793
833
|
const [dx, dy, dz] = offsets[index];
|
|
794
|
-
const x = block.home[0] - 2 + dx;
|
|
795
|
-
const y = block.home[1] - 2 + dy;
|
|
834
|
+
const x = block.home[0] - columns / 2 + dx;
|
|
835
|
+
const y = block.home[1] - rows / 2 + dy;
|
|
796
836
|
return { min: [x, y, dz - DEPTH / 2], max: [x + 1, y + 1, dz + DEPTH / 2], color: block.color };
|
|
797
837
|
});
|
|
798
|
-
const
|
|
799
|
-
|
|
838
|
+
const raster = this.raster;
|
|
839
|
+
raster.render(width, height, pose, boxes, background, isLight(background) ? LIGHT_HALO_STRENGTH : 0);
|
|
800
840
|
const halo = (index, base) => {
|
|
801
|
-
const amount =
|
|
841
|
+
const amount = raster.haloAmount[index];
|
|
802
842
|
if (amount <= 0)
|
|
803
843
|
return base;
|
|
804
|
-
const color =
|
|
844
|
+
const color = raster.haloRgb;
|
|
805
845
|
return mix(base ?? background, [color[index * 3], color[index * 3 + 1], color[index * 3 + 2]], amount);
|
|
806
846
|
};
|
|
807
847
|
const backgroundFade = smooth(dissolveTime / BACKGROUND_FADE);
|
|
@@ -855,11 +895,11 @@ export class PiLogoAnimation {
|
|
|
855
895
|
emit(hint.text[offset], offset < hint.keyLength ? hint.keyColor : hint.color, cellBg);
|
|
856
896
|
continue;
|
|
857
897
|
}
|
|
858
|
-
const dots =
|
|
898
|
+
const dots = raster.bits[index];
|
|
859
899
|
if (dots) {
|
|
860
900
|
// Quantized so neighboring cells on one face usually share a color and its escape sequence.
|
|
861
|
-
const step = LOGO_COLOR_STEP *
|
|
862
|
-
const rgb =
|
|
901
|
+
const step = LOGO_COLOR_STEP * raster.counts[index];
|
|
902
|
+
const rgb = raster.rgb;
|
|
863
903
|
const color = [
|
|
864
904
|
Math.round(rgb[index * 3] / step) * LOGO_COLOR_STEP,
|
|
865
905
|
Math.round(rgb[index * 3 + 1] / step) * LOGO_COLOR_STEP,
|
|
@@ -874,7 +914,7 @@ export class PiLogoAnimation {
|
|
|
874
914
|
continue;
|
|
875
915
|
}
|
|
876
916
|
const dust = (dissolveTime - cell.delay) / DUST_DURATION;
|
|
877
|
-
if (dust < 0 && cell.width === 2 && !
|
|
917
|
+
if (dust < 0 && cell.width === 2 && !raster.bits[index + 1]) {
|
|
878
918
|
emit(cell.text, mix(cell.fg, background, textFade), cellBg);
|
|
879
919
|
column++;
|
|
880
920
|
continue;
|
|
@@ -919,18 +959,19 @@ export class PiLogoAnimation {
|
|
|
919
959
|
this.timer = undefined;
|
|
920
960
|
this.onDone();
|
|
921
961
|
}
|
|
922
|
-
/** Each block's displacement from its place in the
|
|
962
|
+
/** Each block's displacement from its place in the model at `time`, in grid units. */
|
|
923
963
|
blockOffsets(time) {
|
|
924
|
-
const
|
|
964
|
+
const blocks = this.model.blocks;
|
|
965
|
+
const home = () => blocks.map(() => [0, 0, 0]);
|
|
925
966
|
if (time < PUZZLE_START)
|
|
926
967
|
return home();
|
|
927
968
|
const cycle = Math.floor((time - PUZZLE_START) / PUZZLE_CYCLE);
|
|
928
969
|
const local = time - PUZZLE_START - cycle * PUZZLE_CYCLE;
|
|
929
970
|
if (this.shuffle?.cycle !== cycle)
|
|
930
|
-
this.shuffle = { cycle, steps: shuffleSteps(cycle) };
|
|
971
|
+
this.shuffle = { cycle, steps: shuffleSteps(this.model, cycle) };
|
|
931
972
|
const steps = this.shuffle.steps;
|
|
932
973
|
const offset = (position, index) => {
|
|
933
|
-
const block =
|
|
974
|
+
const block = blocks[index].home;
|
|
934
975
|
return [position[0] - block[0], position[1] - block[1], position[2] - block[2]];
|
|
935
976
|
};
|
|
936
977
|
const shuffleEnd = PUZZLE_STEP * PUZZLE_STEPS;
|
|
@@ -965,14 +1006,16 @@ export class PiLogoAnimation {
|
|
|
965
1006
|
return smooth((time - FLY_START - FLY_DURATION) / HINT_FADE);
|
|
966
1007
|
}
|
|
967
1008
|
pose(width, height, progress, time) {
|
|
968
|
-
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
const
|
|
973
|
-
const
|
|
1009
|
+
const { columns, rows, cameraDistance, radius, widthShare, origin } = this.model;
|
|
1010
|
+
const reach = radius * (cameraDistance / (cameraDistance - radius));
|
|
1011
|
+
// Lifting off, the front face must cover exactly the half-block cells (2x2 dots per pixel) despite the
|
|
1012
|
+
// perspective.
|
|
1013
|
+
const startScale = origin ? (2 * (cameraDistance - DEPTH / 2)) / cameraDistance : START_SCALE;
|
|
1014
|
+
const endScale = Math.max(startScale, Math.min(width * 2 * widthShare, (height * 4 - 8) * 0.48) / reach);
|
|
974
1015
|
const endX = width;
|
|
975
1016
|
const endY = height * 2 - 2;
|
|
1017
|
+
const startX = origin ? origin.column * 2 + columns : endX;
|
|
1018
|
+
const startY = origin ? origin.row * 4 + rows : endY;
|
|
976
1019
|
return {
|
|
977
1020
|
centerX: startX + (endX - startX) * progress,
|
|
978
1021
|
centerY: startY + (endY - startY) * progress,
|
|
@@ -1018,10 +1061,12 @@ export class PiLogoAnimation {
|
|
|
1018
1061
|
return stars;
|
|
1019
1062
|
}
|
|
1020
1063
|
prepareCells(width, foreground) {
|
|
1021
|
-
const cells = parseScreen(this.
|
|
1022
|
-
const centerX = this.options.logoColumn + 2;
|
|
1023
|
-
const centerY = this.options.logoRow + 1;
|
|
1064
|
+
const cells = parseScreen(this.screen, width, foreground, this.background);
|
|
1024
1065
|
const height = Math.max(1, this.tui.terminal.rows);
|
|
1066
|
+
const { columns, rows, origin } = this.model;
|
|
1067
|
+
// The dust spreads out from where the model starts.
|
|
1068
|
+
const centerX = origin ? origin.column + columns / 2 : width / 2;
|
|
1069
|
+
const centerY = origin ? origin.row + rows / 4 : height / 2;
|
|
1025
1070
|
const farthest = Math.hypot(Math.max(centerX, width - centerX), Math.max(centerY, height - centerY) * 2);
|
|
1026
1071
|
for (let row = 0; row < cells.length; row++) {
|
|
1027
1072
|
const line = cells[row];
|
|
@@ -1041,18 +1086,20 @@ export class PiLogoAnimation {
|
|
|
1041
1086
|
cell.ink = glyphInk(owner.text, seed);
|
|
1042
1087
|
}
|
|
1043
1088
|
}
|
|
1044
|
-
// The 3D
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
cell
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1089
|
+
// The 3D model replaces its half-block rendering on screen.
|
|
1090
|
+
if (origin) {
|
|
1091
|
+
for (let row = origin.row; row < origin.row + Math.ceil(rows / 2); row++) {
|
|
1092
|
+
const line = cells[row];
|
|
1093
|
+
if (!line)
|
|
1094
|
+
continue;
|
|
1095
|
+
for (let column = origin.column; column < origin.column + columns; column++) {
|
|
1096
|
+
const cell = line[column];
|
|
1097
|
+
if (cell) {
|
|
1098
|
+
cell.text = " ";
|
|
1099
|
+
cell.width = 1;
|
|
1100
|
+
cell.ink = 0;
|
|
1101
|
+
cell.bg = undefined;
|
|
1102
|
+
}
|
|
1056
1103
|
}
|
|
1057
1104
|
}
|
|
1058
1105
|
}
|
|
@@ -1073,4 +1120,4 @@ export class PiLogoAnimation {
|
|
|
1073
1120
|
return value;
|
|
1074
1121
|
}
|
|
1075
1122
|
}
|
|
1076
|
-
//# sourceMappingURL=
|
|
1123
|
+
//# sourceMappingURL=easter-egg-3d.js.map
|