@subimpact/e 0.99.5 → 0.99.7
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/{chunk-YGYY5CGE.js → chunk-JKK652B2.js} +20 -20
- package/dist/bundle/chunks/{chunk-SS3AAGL7.js → chunk-VVPSHZFU.js} +1 -1
- package/dist/bundle/chunks/{chunk-34ZJK2EZ.js → chunk-ZDC7MWVF.js} +1 -1
- package/dist/bundle/chunks/easter-egg-3d-567GSTG6.js +2 -0
- package/dist/bundle/chunks/{virtual-modules-GWKJPH7F.js → virtual-modules-EKUHB2H5.js} +1 -1
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bug-report.js +1 -1
- package/dist/core/bug-report.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +6 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/bug-report.js +1 -1
- package/dist/modes/interactive/bug-report.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/{pi-logo.d.ts → e-logo.d.ts} +2 -2
- package/dist/modes/interactive/components/e-logo.d.ts.map +1 -0
- package/dist/modes/interactive/components/{pi-logo.js → e-logo.js} +2 -2
- package/dist/modes/interactive/components/e-logo.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} +126 -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 +23 -0
- package/dist/modes/interactive/components/easter-egg-3d.lazy.js.map +1 -0
- package/dist/modes/interactive/components/first-time-setup.js +1 -1
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.js +1 -1
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -5
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/package-manager-cli.js +3 -3
- package/dist/package-manager-cli.js.map +1 -1
- package/docs/cli.md +1 -1
- package/docs/settings.md +2 -2
- package/docs/usage.md +1 -1
- package/package.json +1 -1
- package/dist/bundle/chunks/pi-logo-animation-5NR3P2W2.js +0 -2
- 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
- package/dist/modes/interactive/components/pi-logo.d.ts.map +0 -1
- package/dist/modes/interactive/components/pi-logo.js.map +0 -1
|
@@ -1,23 +1,55 @@
|
|
|
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 E_LOGO_PIXELS = ["c..c", "cccc", "bbbc", "b..b"];
|
|
33
|
+
const E_LOGO_COLORS = { c: CORAL, b: BLUE };
|
|
34
|
+
function eLogoModel(origin) {
|
|
35
|
+
return createModel(4, 4, (column, row) => E_LOGO_COLORS[E_LOGO_PIXELS[row][column]], {
|
|
36
|
+
cameraDistance: 10,
|
|
37
|
+
widthShare: 0.35,
|
|
38
|
+
puzzleMoves: (random) => (random < 0.4 ? 2 : 1),
|
|
39
|
+
origin,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function arminModel(color) {
|
|
43
|
+
return createModel(ARMIN_WIDTH, ARMIN_HEIGHT, (column, row) => (isArminPixel(column, row) ? color : undefined), {
|
|
44
|
+
// Far enough that the perspective stays mild for a figure about 36 blocks tall.
|
|
45
|
+
cameraDistance: 80,
|
|
46
|
+
widthShare: 0.45,
|
|
47
|
+
puzzleMoves: (random, blockCount) => Math.round(blockCount * (0.03 + random * 0.04)),
|
|
48
|
+
origin: undefined,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// The sliding puzzle: after the model spun for a while, blocks slide into free neighboring cells, a few at a time.
|
|
52
|
+
// Each cycle shuffles, flies every block back home, and holds the model briefly.
|
|
21
53
|
const PUZZLE_START = FLY_START + FLY_DURATION + 3;
|
|
22
54
|
const PUZZLE_STEP = 0.3;
|
|
23
55
|
const PUZZLE_STEPS = 12;
|
|
@@ -37,18 +69,19 @@ const PUZZLE_MOVES = [
|
|
|
37
69
|
[0, 0, -1],
|
|
38
70
|
];
|
|
39
71
|
/** Block positions after each step of one shuffle cycle, starting at home. Deterministic per cycle. */
|
|
40
|
-
function shuffleSteps(cycle) {
|
|
41
|
-
|
|
72
|
+
function shuffleSteps(model, cycle) {
|
|
73
|
+
const { columns, rows } = model;
|
|
74
|
+
let positions = model.blocks.map((block) => block.home);
|
|
42
75
|
const steps = [positions];
|
|
43
76
|
const lastMoved = new Set();
|
|
44
77
|
let random = cycle * 7_919 + 1;
|
|
45
78
|
const next = () => hash(random++);
|
|
46
|
-
const key = ([x, y, z]) => (z + 1) *
|
|
79
|
+
const key = ([x, y, z]) => ((z + 1) * rows + y) * columns + x;
|
|
47
80
|
for (let step = 0; step < PUZZLE_STEPS; step++) {
|
|
48
81
|
const occupied = new Set(positions.map(key));
|
|
49
82
|
const nextPositions = [...positions];
|
|
50
83
|
const moved = new Set();
|
|
51
|
-
const moveCount = next()
|
|
84
|
+
const moveCount = model.puzzleMoves(next());
|
|
52
85
|
for (let move = 0; move < moveCount; move++) {
|
|
53
86
|
const candidates = [];
|
|
54
87
|
for (let block = 0; block < positions.length; block++) {
|
|
@@ -57,7 +90,7 @@ function shuffleSteps(cycle) {
|
|
|
57
90
|
const [x, y, z] = positions[block];
|
|
58
91
|
for (const [dx, dy, dz] of PUZZLE_MOVES) {
|
|
59
92
|
const target = [x + dx, y + dy, z + dz];
|
|
60
|
-
if (target[0] < 0 || target[0]
|
|
93
|
+
if (target[0] < 0 || target[0] >= columns || target[1] < 0 || target[1] >= rows)
|
|
61
94
|
continue;
|
|
62
95
|
if (target[2] < -1 || target[2] > 1 || occupied.has(key(target)))
|
|
63
96
|
continue;
|
|
@@ -335,11 +368,11 @@ function spinAngle(time) {
|
|
|
335
368
|
return phase - SPIN_LINGER * Math.sin(phase);
|
|
336
369
|
}
|
|
337
370
|
/**
|
|
338
|
-
* Renders the
|
|
371
|
+
* Renders the model's blocks into braille cells. Only faces that point at the camera and are not covered by a
|
|
339
372
|
* touching block are drawn. Each face is rasterized over its projected bounds by intersecting each dot's ray
|
|
340
373
|
* with the face's plane, with a depth buffer resolving overlaps. Buffers are reused between frames.
|
|
341
374
|
*/
|
|
342
|
-
class
|
|
375
|
+
class BlockRaster {
|
|
343
376
|
/** Braille dot bits per cell. */
|
|
344
377
|
bits = new Uint8Array(0);
|
|
345
378
|
/** Lit dots per cell. */
|
|
@@ -355,11 +388,15 @@ class LogoRaster {
|
|
|
355
388
|
/** Ray parameter of the nearest hit per dot; smaller is nearer. */
|
|
356
389
|
depth = new Float32Array(0);
|
|
357
390
|
/** Face index + 1 of the nearest hit per dot, 0 for none. */
|
|
358
|
-
faceIds = new
|
|
391
|
+
faceIds = new Uint16Array(0);
|
|
359
392
|
/** Cells written by the previous frame, cleared before the next one. */
|
|
360
393
|
dirty;
|
|
361
394
|
/** Cells with a halo from the previous frame, cleared before the next one. */
|
|
362
395
|
haloDirty;
|
|
396
|
+
cameraDistance;
|
|
397
|
+
constructor(cameraDistance) {
|
|
398
|
+
this.cameraDistance = cameraDistance;
|
|
399
|
+
}
|
|
363
400
|
render(width, height, pose, boxes, background, haloStrength) {
|
|
364
401
|
const dotWidth = width * 2;
|
|
365
402
|
const dotHeight = height * 4;
|
|
@@ -373,7 +410,7 @@ class LogoRaster {
|
|
|
373
410
|
this.haloRgb = new Float32Array(width * height * 3);
|
|
374
411
|
this.haloDirty = undefined;
|
|
375
412
|
this.depth = new Float32Array(dotWidth * dotHeight).fill(Infinity);
|
|
376
|
-
this.faceIds = new
|
|
413
|
+
this.faceIds = new Uint16Array(dotWidth * dotHeight);
|
|
377
414
|
this.dirty = undefined;
|
|
378
415
|
}
|
|
379
416
|
else if (this.dirty) {
|
|
@@ -395,8 +432,9 @@ class LogoRaster {
|
|
|
395
432
|
}
|
|
396
433
|
const m = rotation(pose.yaw, pose.pitch, pose.roll);
|
|
397
434
|
const { centerX, centerY, scale } = pose;
|
|
398
|
-
|
|
399
|
-
|
|
435
|
+
const cameraDistance = this.cameraDistance;
|
|
436
|
+
// The camera sits at (0, 0, cameraDistance) in camera space; object space is the transpose rotation.
|
|
437
|
+
const origin = [m[6] * cameraDistance, m[7] * cameraDistance, m[8] * cameraDistance];
|
|
400
438
|
const light = isLight(background);
|
|
401
439
|
const faces = this.visibleFaces(m, origin, pose, boxes, dotWidth, dotHeight, light);
|
|
402
440
|
if (faces.length === 0)
|
|
@@ -430,9 +468,9 @@ class LogoRaster {
|
|
|
430
468
|
const sx = (face.minX + 0.5 - centerX) / scale;
|
|
431
469
|
for (let dotY = face.minY; dotY <= face.maxY; dotY++) {
|
|
432
470
|
const sy = (dotY + 0.5 - centerY) / scale;
|
|
433
|
-
let directionA = m[a] * sx + m[3 + a] * sy - m[6 + a] *
|
|
434
|
-
let directionU = m[u] * sx + m[3 + u] * sy - m[6 + u] *
|
|
435
|
-
let directionV = m[v] * sx + m[3 + v] * sy - m[6 + v] *
|
|
471
|
+
let directionA = m[a] * sx + m[3 + a] * sy - m[6 + a] * cameraDistance;
|
|
472
|
+
let directionU = m[u] * sx + m[3 + u] * sy - m[6 + u] * cameraDistance;
|
|
473
|
+
let directionV = m[v] * sx + m[3 + v] * sy - m[6 + v] * cameraDistance;
|
|
436
474
|
let index = dotY * dotWidth + face.minX;
|
|
437
475
|
for (let dotX = face.minX; dotX <= face.maxX; dotX++, index++) {
|
|
438
476
|
const t = (face.plane - originA) / directionA;
|
|
@@ -466,7 +504,7 @@ class LogoRaster {
|
|
|
466
504
|
continue;
|
|
467
505
|
const face = faces[id - 1];
|
|
468
506
|
// Points farther from the camera fade slightly toward the background for depth.
|
|
469
|
-
const fog = clamp01(0.15 -
|
|
507
|
+
const fog = clamp01(0.15 - cameraDistance * (1 - depth[index]) * 0.12) * (light ? 0.5 : 1);
|
|
470
508
|
faceIds[index] = 0;
|
|
471
509
|
depth[index] = Infinity;
|
|
472
510
|
const cellX = dotX >> 1;
|
|
@@ -586,6 +624,7 @@ class LogoRaster {
|
|
|
586
624
|
}
|
|
587
625
|
visibleFaces(m, origin, pose, boxes, dotWidth, dotHeight, lightBackground) {
|
|
588
626
|
const faces = [];
|
|
627
|
+
const cameraDistance = this.cameraDistance;
|
|
589
628
|
for (const box of boxes) {
|
|
590
629
|
for (let a = 0; a < 3; a++) {
|
|
591
630
|
const u = (a + 1) % 3;
|
|
@@ -617,7 +656,7 @@ class LogoRaster {
|
|
|
617
656
|
const x = m[0] * corner[0] + m[1] * corner[1] + m[2] * corner[2];
|
|
618
657
|
const y = m[3] * corner[0] + m[4] * corner[1] + m[5] * corner[2];
|
|
619
658
|
const z = m[6] * corner[0] + m[7] * corner[1] + m[8] * corner[2];
|
|
620
|
-
const perspective = (pose.scale *
|
|
659
|
+
const perspective = (pose.scale * cameraDistance) / (cameraDistance - z);
|
|
621
660
|
const screenX = pose.centerX + x * perspective;
|
|
622
661
|
const screenY = pose.centerY + y * perspective;
|
|
623
662
|
minX = Math.min(minX, screenX);
|
|
@@ -672,7 +711,7 @@ let playing = false;
|
|
|
672
711
|
* Show the animation as a fullscreen overlay until it is dismissed. The overlay takes focus and mouse input and
|
|
673
712
|
* returns focus when hidden, so the rest of the UI keeps running underneath untouched.
|
|
674
713
|
*/
|
|
675
|
-
export async function
|
|
714
|
+
export async function playEasterEgg3d(tui, screen, egg) {
|
|
676
715
|
if (playing)
|
|
677
716
|
return;
|
|
678
717
|
playing = true;
|
|
@@ -688,15 +727,18 @@ export async function playPiLogoAnimation(tui, options) {
|
|
|
688
727
|
playing = false;
|
|
689
728
|
return;
|
|
690
729
|
}
|
|
691
|
-
const
|
|
730
|
+
const model = egg.kind === "armin" ? arminModel(toRgb(theme.colors.accent)) : eLogoModel({ column: egg.column, row: egg.row });
|
|
731
|
+
const animation = new EasterEgg3dAnimation(tui, screen, model, colors, () => {
|
|
692
732
|
playing = false;
|
|
693
733
|
overlay.hide();
|
|
694
734
|
});
|
|
695
735
|
const overlay = tui.showOverlay(animation, { anchor: "top-left", width: "100%", maxHeight: "100%" });
|
|
696
736
|
}
|
|
697
|
-
export class
|
|
737
|
+
export class EasterEgg3dAnimation {
|
|
698
738
|
tui;
|
|
699
|
-
|
|
739
|
+
/** The screen to dissolve, as rendered lines. */
|
|
740
|
+
screen;
|
|
741
|
+
model;
|
|
700
742
|
foreground;
|
|
701
743
|
background;
|
|
702
744
|
onDone;
|
|
@@ -711,10 +753,12 @@ export class PiLogoAnimation {
|
|
|
711
753
|
stars = [];
|
|
712
754
|
cells = [];
|
|
713
755
|
ansiCache = new Map();
|
|
714
|
-
|
|
715
|
-
constructor(tui,
|
|
756
|
+
raster;
|
|
757
|
+
constructor(tui, screen, model, colors, onDone) {
|
|
716
758
|
this.tui = tui;
|
|
717
|
-
this.
|
|
759
|
+
this.screen = screen;
|
|
760
|
+
this.model = model;
|
|
761
|
+
this.raster = new BlockRaster(model.cameraDistance);
|
|
718
762
|
this.foreground = colors.foreground;
|
|
719
763
|
this.background = colors.background;
|
|
720
764
|
this.onDone = onDone;
|
|
@@ -799,19 +843,20 @@ export class PiLogoAnimation {
|
|
|
799
843
|
starAlpha = this.starAlpha(time);
|
|
800
844
|
offsets = this.blockOffsets(time);
|
|
801
845
|
}
|
|
802
|
-
const
|
|
846
|
+
const { columns, rows } = this.model;
|
|
847
|
+
const boxes = this.model.blocks.map((block, index) => {
|
|
803
848
|
const [dx, dy, dz] = offsets[index];
|
|
804
|
-
const x = block.home[0] - 2 + dx;
|
|
805
|
-
const y = block.home[1] - 2 + dy;
|
|
849
|
+
const x = block.home[0] - columns / 2 + dx;
|
|
850
|
+
const y = block.home[1] - rows / 2 + dy;
|
|
806
851
|
return { min: [x, y, dz - DEPTH / 2], max: [x + 1, y + 1, dz + DEPTH / 2], color: block.color };
|
|
807
852
|
});
|
|
808
|
-
const
|
|
809
|
-
|
|
853
|
+
const raster = this.raster;
|
|
854
|
+
raster.render(width, height, pose, boxes, background, isLight(background) ? LIGHT_HALO_STRENGTH : 0);
|
|
810
855
|
const halo = (index, base) => {
|
|
811
|
-
const amount =
|
|
856
|
+
const amount = raster.haloAmount[index];
|
|
812
857
|
if (amount <= 0)
|
|
813
858
|
return base;
|
|
814
|
-
const color =
|
|
859
|
+
const color = raster.haloRgb;
|
|
815
860
|
return mix(base ?? background, [color[index * 3], color[index * 3 + 1], color[index * 3 + 2]], amount);
|
|
816
861
|
};
|
|
817
862
|
const backgroundFade = smooth(dissolveTime / BACKGROUND_FADE);
|
|
@@ -865,11 +910,11 @@ export class PiLogoAnimation {
|
|
|
865
910
|
emit(hint.text[offset], offset < hint.keyLength ? hint.keyColor : hint.color, cellBg);
|
|
866
911
|
continue;
|
|
867
912
|
}
|
|
868
|
-
const dots =
|
|
913
|
+
const dots = raster.bits[index];
|
|
869
914
|
if (dots) {
|
|
870
915
|
// Quantized so neighboring cells on one face usually share a color and its escape sequence.
|
|
871
|
-
const step = LOGO_COLOR_STEP *
|
|
872
|
-
const rgb =
|
|
916
|
+
const step = LOGO_COLOR_STEP * raster.counts[index];
|
|
917
|
+
const rgb = raster.rgb;
|
|
873
918
|
const color = [
|
|
874
919
|
Math.round(rgb[index * 3] / step) * LOGO_COLOR_STEP,
|
|
875
920
|
Math.round(rgb[index * 3 + 1] / step) * LOGO_COLOR_STEP,
|
|
@@ -884,7 +929,7 @@ export class PiLogoAnimation {
|
|
|
884
929
|
continue;
|
|
885
930
|
}
|
|
886
931
|
const dust = (dissolveTime - cell.delay) / DUST_DURATION;
|
|
887
|
-
if (dust < 0 && cell.width === 2 && !
|
|
932
|
+
if (dust < 0 && cell.width === 2 && !raster.bits[index + 1]) {
|
|
888
933
|
emit(cell.text, mix(cell.fg, background, textFade), cellBg);
|
|
889
934
|
column++;
|
|
890
935
|
continue;
|
|
@@ -929,18 +974,19 @@ export class PiLogoAnimation {
|
|
|
929
974
|
this.timer = undefined;
|
|
930
975
|
this.onDone();
|
|
931
976
|
}
|
|
932
|
-
/** Each block's displacement from its place in the
|
|
977
|
+
/** Each block's displacement from its place in the model at `time`, in grid units. */
|
|
933
978
|
blockOffsets(time) {
|
|
934
|
-
const
|
|
979
|
+
const blocks = this.model.blocks;
|
|
980
|
+
const home = () => blocks.map(() => [0, 0, 0]);
|
|
935
981
|
if (time < PUZZLE_START)
|
|
936
982
|
return home();
|
|
937
983
|
const cycle = Math.floor((time - PUZZLE_START) / PUZZLE_CYCLE);
|
|
938
984
|
const local = time - PUZZLE_START - cycle * PUZZLE_CYCLE;
|
|
939
985
|
if (this.shuffle?.cycle !== cycle)
|
|
940
|
-
this.shuffle = { cycle, steps: shuffleSteps(cycle) };
|
|
986
|
+
this.shuffle = { cycle, steps: shuffleSteps(this.model, cycle) };
|
|
941
987
|
const steps = this.shuffle.steps;
|
|
942
988
|
const offset = (position, index) => {
|
|
943
|
-
const block =
|
|
989
|
+
const block = blocks[index].home;
|
|
944
990
|
return [position[0] - block[0], position[1] - block[1], position[2] - block[2]];
|
|
945
991
|
};
|
|
946
992
|
const shuffleEnd = PUZZLE_STEP * PUZZLE_STEPS;
|
|
@@ -975,14 +1021,16 @@ export class PiLogoAnimation {
|
|
|
975
1021
|
return smooth((time - FLY_START - FLY_DURATION) / HINT_FADE);
|
|
976
1022
|
}
|
|
977
1023
|
pose(width, height, progress, time) {
|
|
978
|
-
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
const
|
|
983
|
-
const
|
|
1024
|
+
const { columns, rows, cameraDistance, radius, widthShare, origin } = this.model;
|
|
1025
|
+
const reach = radius * (cameraDistance / (cameraDistance - radius));
|
|
1026
|
+
// Lifting off, the front face must cover exactly the half-block cells (2x2 dots per pixel) despite the
|
|
1027
|
+
// perspective.
|
|
1028
|
+
const startScale = origin ? (2 * (cameraDistance - DEPTH / 2)) / cameraDistance : START_SCALE;
|
|
1029
|
+
const endScale = Math.max(startScale, Math.min(width * 2 * widthShare, (height * 4 - 8) * 0.48) / reach);
|
|
984
1030
|
const endX = width;
|
|
985
1031
|
const endY = height * 2 - 2;
|
|
1032
|
+
const startX = origin ? origin.column * 2 + columns : endX;
|
|
1033
|
+
const startY = origin ? origin.row * 4 + rows : endY;
|
|
986
1034
|
return {
|
|
987
1035
|
centerX: startX + (endX - startX) * progress,
|
|
988
1036
|
centerY: startY + (endY - startY) * progress,
|
|
@@ -1028,10 +1076,12 @@ export class PiLogoAnimation {
|
|
|
1028
1076
|
return stars;
|
|
1029
1077
|
}
|
|
1030
1078
|
prepareCells(width, foreground) {
|
|
1031
|
-
const cells = parseScreen(this.
|
|
1032
|
-
const centerX = this.options.logoColumn + 2;
|
|
1033
|
-
const centerY = this.options.logoRow + 1;
|
|
1079
|
+
const cells = parseScreen(this.screen, width, foreground, this.background);
|
|
1034
1080
|
const height = Math.max(1, this.tui.terminal.rows);
|
|
1081
|
+
const { columns, rows, origin } = this.model;
|
|
1082
|
+
// The dust spreads out from where the model starts.
|
|
1083
|
+
const centerX = origin ? origin.column + columns / 2 : width / 2;
|
|
1084
|
+
const centerY = origin ? origin.row + rows / 4 : height / 2;
|
|
1035
1085
|
const farthest = Math.hypot(Math.max(centerX, width - centerX), Math.max(centerY, height - centerY) * 2);
|
|
1036
1086
|
for (let row = 0; row < cells.length; row++) {
|
|
1037
1087
|
const line = cells[row];
|
|
@@ -1051,18 +1101,20 @@ export class PiLogoAnimation {
|
|
|
1051
1101
|
cell.ink = glyphInk(owner.text, seed);
|
|
1052
1102
|
}
|
|
1053
1103
|
}
|
|
1054
|
-
// The 3D
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
cell
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1104
|
+
// The 3D model replaces its half-block rendering on screen.
|
|
1105
|
+
if (origin) {
|
|
1106
|
+
for (let row = origin.row; row < origin.row + Math.ceil(rows / 2); row++) {
|
|
1107
|
+
const line = cells[row];
|
|
1108
|
+
if (!line)
|
|
1109
|
+
continue;
|
|
1110
|
+
for (let column = origin.column; column < origin.column + columns; column++) {
|
|
1111
|
+
const cell = line[column];
|
|
1112
|
+
if (cell) {
|
|
1113
|
+
cell.text = " ";
|
|
1114
|
+
cell.width = 1;
|
|
1115
|
+
cell.ink = 0;
|
|
1116
|
+
cell.bg = undefined;
|
|
1117
|
+
}
|
|
1066
1118
|
}
|
|
1067
1119
|
}
|
|
1068
1120
|
}
|
|
@@ -1083,4 +1135,4 @@ export class PiLogoAnimation {
|
|
|
1083
1135
|
return value;
|
|
1084
1136
|
}
|
|
1085
1137
|
}
|
|
1086
|
-
//# sourceMappingURL=
|
|
1138
|
+
//# sourceMappingURL=easter-egg-3d.js.map
|