@figliolia/chalk-animation 1.0.1 → 1.0.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/README.md +1 -1
- package/dist/cjs/Animation.d.ts +8 -12
- package/dist/cjs/Animation.js +25 -36
- package/dist/cjs/ChalkAnimation.d.ts +18 -7
- package/dist/cjs/ChalkAnimation.js +26 -21
- package/dist/cjs/Decor.d.ts +5 -0
- package/dist/cjs/Decor.js +18 -0
- package/dist/cjs/Effects.d.ts +2 -2
- package/dist/cjs/Effects.js +28 -3
- package/dist/cjs/FrameRate.d.ts +11 -0
- package/dist/cjs/FrameRate.js +26 -0
- package/dist/cjs/InstanceTracker.d.ts +1 -0
- package/dist/cjs/InstanceTracker.js +4 -2
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/types.d.ts +5 -0
- package/dist/mjs/Animation.d.ts +8 -12
- package/dist/mjs/Animation.js +20 -33
- package/dist/mjs/ChalkAnimation.d.ts +18 -7
- package/dist/mjs/ChalkAnimation.js +24 -21
- package/dist/mjs/Decor.d.ts +5 -0
- package/dist/mjs/Decor.js +14 -0
- package/dist/mjs/Effects.d.ts +2 -2
- package/dist/mjs/Effects.js +27 -2
- package/dist/mjs/FrameRate.d.ts +11 -0
- package/dist/mjs/FrameRate.js +24 -0
- package/dist/mjs/InstanceTracker.d.ts +1 -0
- package/dist/mjs/InstanceTracker.js +2 -2
- package/dist/mjs/index.d.ts +1 -0
- package/dist/mjs/types.d.ts +5 -0
- package/package.json +1 -1
- package/src/Animation.ts +20 -34
- package/src/ChalkAnimation.ts +25 -26
- package/src/Decor.ts +24 -0
- package/src/Effects.ts +14 -6
- package/src/FrameRate.ts +28 -0
- package/src/InstanceTracker.ts +5 -3
- package/src/__tests__/ChalkAnimation.test.ts +108 -0
- package/src/index.ts +1 -0
- package/src/types.ts +14 -0
- package/dist/cjs/animateString.d.ts +0 -2
- package/dist/cjs/animateString.js +0 -18
- package/dist/mjs/animateString.d.ts +0 -2
- package/dist/mjs/animateString.js +0 -14
- package/src/animateString.ts +0 -15
package/README.md
CHANGED
package/dist/cjs/Animation.d.ts
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import type { AnimationFN } from "./types";
|
|
2
|
-
import {
|
|
3
|
-
export declare class Animation extends
|
|
4
|
-
effect: any;
|
|
2
|
+
import { FrameRate } from "./FrameRate";
|
|
3
|
+
export declare class Animation extends FrameRate {
|
|
5
4
|
lines: number;
|
|
6
|
-
speed: number;
|
|
7
|
-
delay: number;
|
|
8
5
|
text: string[];
|
|
9
6
|
stopped: boolean;
|
|
10
|
-
currentFrame: number;
|
|
11
7
|
initialized: boolean;
|
|
12
|
-
|
|
8
|
+
effect: AnimationFN;
|
|
9
|
+
static readonly LINE_BREAKS: RegExp;
|
|
13
10
|
constructor(effect: AnimationFN, str: string, delay?: number, speed?: number);
|
|
14
11
|
render(): void;
|
|
15
|
-
|
|
16
|
-
replace(str: string)
|
|
17
|
-
stop()
|
|
18
|
-
start()
|
|
19
|
-
private clearFrames;
|
|
12
|
+
nextFrame(): string;
|
|
13
|
+
readonly replace: (str: string) => this;
|
|
14
|
+
readonly stop: () => this;
|
|
15
|
+
readonly start: () => this;
|
|
20
16
|
}
|
package/dist/cjs/Animation.js
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Animation = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const FrameRate_1 = require("./FrameRate");
|
|
5
|
+
const Decor_1 = require("./Decor");
|
|
6
|
+
class Animation extends FrameRate_1.FrameRate {
|
|
6
7
|
constructor(effect, str, delay = 0, speed = 0) {
|
|
7
|
-
super();
|
|
8
|
+
super(delay, speed);
|
|
8
9
|
this.stopped = false;
|
|
9
|
-
this.currentFrame = 0;
|
|
10
10
|
this.initialized = false;
|
|
11
|
-
this.
|
|
11
|
+
this.replace = Decor_1.Decor.chainable(this, (str) => {
|
|
12
|
+
this.text = str.split(Animation.LINE_BREAKS);
|
|
13
|
+
this.lines = this.text.length;
|
|
14
|
+
});
|
|
15
|
+
this.stop = Decor_1.Decor.chainable(this, () => {
|
|
16
|
+
this.clearFrames();
|
|
17
|
+
this.stopped = true;
|
|
18
|
+
});
|
|
19
|
+
this.start = Decor_1.Decor.chainable(this, () => {
|
|
20
|
+
this.clearFrames();
|
|
21
|
+
this.stopped = false;
|
|
22
|
+
this.render();
|
|
23
|
+
});
|
|
12
24
|
this.effect = effect;
|
|
13
|
-
this.
|
|
14
|
-
this.delay = delay;
|
|
15
|
-
this.text = str.split(/\r\n|\r|\n/);
|
|
25
|
+
this.text = str.split(Animation.LINE_BREAKS);
|
|
16
26
|
this.lines = this.text.length;
|
|
17
27
|
}
|
|
18
28
|
render() {
|
|
@@ -20,41 +30,20 @@ class Animation extends InstanceTracker_1.InstanceTracker {
|
|
|
20
30
|
Animation.LOG("\n".repeat(this.lines - 1));
|
|
21
31
|
this.initialized = true;
|
|
22
32
|
}
|
|
23
|
-
Animation.LOG(this.
|
|
24
|
-
this.
|
|
33
|
+
Animation.LOG(this.nextFrame());
|
|
34
|
+
this.schedule(() => {
|
|
25
35
|
if (!this.stopped) {
|
|
26
36
|
this.render();
|
|
27
37
|
}
|
|
28
|
-
}
|
|
38
|
+
});
|
|
29
39
|
}
|
|
30
|
-
|
|
31
|
-
this.
|
|
40
|
+
nextFrame() {
|
|
41
|
+
this.increment();
|
|
32
42
|
return ("\u001B[" +
|
|
33
43
|
`${this.lines}` +
|
|
34
44
|
"F\u001B[G\u001B[2K" +
|
|
35
|
-
this.text.map(
|
|
36
|
-
}
|
|
37
|
-
replace(str) {
|
|
38
|
-
this.text = str.split(/\r\n|\r|\n/);
|
|
39
|
-
this.lines = this.text.length;
|
|
40
|
-
return this;
|
|
41
|
-
}
|
|
42
|
-
stop() {
|
|
43
|
-
this.clearFrames();
|
|
44
|
-
this.stopped = true;
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
start() {
|
|
48
|
-
this.clearFrames();
|
|
49
|
-
this.stopped = false;
|
|
50
|
-
this.render();
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
clearFrames() {
|
|
54
|
-
if (this.controller) {
|
|
55
|
-
clearTimeout(this.controller);
|
|
56
|
-
this.controller = null;
|
|
57
|
-
}
|
|
45
|
+
this.text.map(str => this.effect(str, this.current)).join("\n"));
|
|
58
46
|
}
|
|
59
47
|
}
|
|
60
48
|
exports.Animation = Animation;
|
|
49
|
+
Animation.LINE_BREAKS = /\r\n|\r|\n/;
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { Animation } from "./Animation";
|
|
2
|
+
/**
|
|
3
|
+
* Chalk Animation
|
|
4
|
+
*
|
|
5
|
+
* Console animations for your CLI tools
|
|
6
|
+
*
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const animation = ChalkAnimation.rainbow("hello!");
|
|
9
|
+
* animation.stop();
|
|
10
|
+
* animation.start();
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
2
13
|
export declare class ChalkAnimation {
|
|
3
|
-
static
|
|
4
|
-
static
|
|
5
|
-
static
|
|
6
|
-
static
|
|
7
|
-
static
|
|
8
|
-
static karaoke(str: string, speed?: number)
|
|
9
|
-
static
|
|
14
|
+
static readonly neon: (str: string, speed?: number) => Animation;
|
|
15
|
+
static readonly radar: (str: string, speed?: number) => Animation;
|
|
16
|
+
static readonly pulse: (str: string, speed?: number) => Animation;
|
|
17
|
+
static readonly glitch: (str: string, speed?: number) => Animation;
|
|
18
|
+
static readonly rainbow: (str: string, speed?: number) => Animation;
|
|
19
|
+
static readonly karaoke: (str: string, speed?: number) => Animation;
|
|
20
|
+
private static configure;
|
|
10
21
|
}
|
|
@@ -1,30 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var _a;
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.ChalkAnimation = void 0;
|
|
4
5
|
const Effects_1 = require("./Effects");
|
|
5
6
|
const Animation_1 = require("./Animation");
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Chalk Animation
|
|
9
|
+
*
|
|
10
|
+
* Console animations for your CLI tools
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const animation = ChalkAnimation.rainbow("hello!");
|
|
14
|
+
* animation.stop();
|
|
15
|
+
* animation.start();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
7
18
|
class ChalkAnimation {
|
|
8
|
-
static
|
|
9
|
-
return (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return (0, animateString_1.animateString)(Effects_1.Effects.glitch, str, 55, speed);
|
|
16
|
-
}
|
|
17
|
-
static radar(str, speed = 1) {
|
|
18
|
-
return (0, animateString_1.animateString)(Effects_1.Effects.radar, str, 50, speed);
|
|
19
|
-
}
|
|
20
|
-
static neon(str, speed = 1) {
|
|
21
|
-
return (0, animateString_1.animateString)(Effects_1.Effects.neon, str, 500, speed);
|
|
22
|
-
}
|
|
23
|
-
static karaoke(str, speed = 1) {
|
|
24
|
-
return (0, animateString_1.animateString)(Effects_1.Effects.karaoke, str, 50, speed);
|
|
25
|
-
}
|
|
26
|
-
static clearAllAnimations() {
|
|
27
|
-
return Animation_1.Animation.clearAll();
|
|
19
|
+
static configure(effect, delay) {
|
|
20
|
+
return (str, speed = 1) => {
|
|
21
|
+
if (!speed || speed <= 0) {
|
|
22
|
+
throw new Error("Expected `speed` to be an number greater than 0");
|
|
23
|
+
}
|
|
24
|
+
return new Animation_1.Animation(Effects_1.Effects[effect], str, delay, speed).start();
|
|
25
|
+
};
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
exports.ChalkAnimation = ChalkAnimation;
|
|
29
|
+
_a = ChalkAnimation;
|
|
30
|
+
ChalkAnimation.neon = _a.configure("neon", 500);
|
|
31
|
+
ChalkAnimation.radar = _a.configure("radar", 50);
|
|
32
|
+
ChalkAnimation.pulse = _a.configure("pulse", 16);
|
|
33
|
+
ChalkAnimation.glitch = _a.configure("glitch", 55);
|
|
34
|
+
ChalkAnimation.rainbow = _a.configure("rainbow", 15);
|
|
35
|
+
ChalkAnimation.karaoke = _a.configure("karaoke", 50);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { MethodKeys, MethodLike } from "./types";
|
|
2
|
+
export declare class Decor {
|
|
3
|
+
static bound<T, K extends MethodKeys<T>>(target: T, _propertyKey: K, descriptor: TypedPropertyDescriptor<MethodLike>): void;
|
|
4
|
+
static chainable<I, F extends (...args: any[]) => any>(instance: I, func: F): (...params: Parameters<F>) => I;
|
|
5
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Decor = void 0;
|
|
4
|
+
class Decor {
|
|
5
|
+
static bound(target, _propertyKey, descriptor) {
|
|
6
|
+
const operation = descriptor.value;
|
|
7
|
+
if (operation) {
|
|
8
|
+
descriptor.value = operation.bind(target);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
static chainable(instance, func) {
|
|
12
|
+
return (...params) => {
|
|
13
|
+
func(...params);
|
|
14
|
+
return instance;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.Decor = Decor;
|
package/dist/cjs/Effects.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare class Effects {
|
|
2
|
-
static longHsv: {
|
|
2
|
+
static readonly longHsv: {
|
|
3
3
|
interpolation: string;
|
|
4
4
|
hsvSpin: string;
|
|
5
5
|
};
|
|
6
|
-
static glitchChars
|
|
6
|
+
static readonly glitchChars = "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
7
7
|
static rainbow(str: string, frame: number): string;
|
|
8
8
|
static pulse(str: string, frame: number): string;
|
|
9
9
|
static glitch(str: string, frame: number): string;
|
package/dist/cjs/Effects.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
2
8
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
9
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
10
|
};
|
|
@@ -6,12 +12,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
12
|
exports.Effects = void 0;
|
|
7
13
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
14
|
const gradient_string_1 = __importDefault(require("gradient-string"));
|
|
15
|
+
const Decor_1 = require("./Decor");
|
|
9
16
|
class Effects {
|
|
10
17
|
static rainbow(str, frame) {
|
|
11
18
|
const hue = 5 * frame;
|
|
12
19
|
const leftColor = { h: hue % 360, s: 1, v: 1 };
|
|
13
20
|
const rightColor = { h: (hue + 1) % 360, s: 1, v: 1 };
|
|
14
|
-
return (0, gradient_string_1.default)(leftColor, rightColor)(str,
|
|
21
|
+
return (0, gradient_string_1.default)(leftColor, rightColor)(str, this.longHsv);
|
|
15
22
|
}
|
|
16
23
|
static pulse(str, frame) {
|
|
17
24
|
frame = (frame % 120) + 1;
|
|
@@ -56,7 +63,7 @@ class Effects {
|
|
|
56
63
|
i += skip;
|
|
57
64
|
if (str[i]) {
|
|
58
65
|
if (str[i] !== "\n" && str[i] !== "\r" && Math.random() > 0.995) {
|
|
59
|
-
chunks.push(
|
|
66
|
+
chunks.push(this.glitchChars[Math.floor(Math.random() * this.glitchChars.length)]);
|
|
60
67
|
}
|
|
61
68
|
else if (Math.random() > 0.005) {
|
|
62
69
|
chunks.push(str[i]);
|
|
@@ -104,6 +111,24 @@ class Effects {
|
|
|
104
111
|
chalk_1.default.white(str.substr(chars)));
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
|
-
exports.Effects = Effects;
|
|
108
114
|
Effects.longHsv = { interpolation: "hsv", hsvSpin: "long" };
|
|
109
115
|
Effects.glitchChars = "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
116
|
+
__decorate([
|
|
117
|
+
Decor_1.Decor.bound
|
|
118
|
+
], Effects, "rainbow", null);
|
|
119
|
+
__decorate([
|
|
120
|
+
Decor_1.Decor.bound
|
|
121
|
+
], Effects, "pulse", null);
|
|
122
|
+
__decorate([
|
|
123
|
+
Decor_1.Decor.bound
|
|
124
|
+
], Effects, "glitch", null);
|
|
125
|
+
__decorate([
|
|
126
|
+
Decor_1.Decor.bound
|
|
127
|
+
], Effects, "radar", null);
|
|
128
|
+
__decorate([
|
|
129
|
+
Decor_1.Decor.bound
|
|
130
|
+
], Effects, "neon", null);
|
|
131
|
+
__decorate([
|
|
132
|
+
Decor_1.Decor.bound
|
|
133
|
+
], Effects, "karaoke", null);
|
|
134
|
+
exports.Effects = Effects;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InstanceTracker } from "./InstanceTracker";
|
|
2
|
+
export declare class FrameRate extends InstanceTracker {
|
|
3
|
+
current: number;
|
|
4
|
+
speed: number;
|
|
5
|
+
delay: number;
|
|
6
|
+
controller: ReturnType<typeof setTimeout> | null;
|
|
7
|
+
constructor(delay: number, speed: number);
|
|
8
|
+
schedule<F extends () => any>(func: F): void;
|
|
9
|
+
increment(): void;
|
|
10
|
+
clearFrames(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FrameRate = void 0;
|
|
4
|
+
const InstanceTracker_1 = require("./InstanceTracker");
|
|
5
|
+
class FrameRate extends InstanceTracker_1.InstanceTracker {
|
|
6
|
+
constructor(delay, speed) {
|
|
7
|
+
super();
|
|
8
|
+
this.current = 0;
|
|
9
|
+
this.controller = null;
|
|
10
|
+
this.delay = delay;
|
|
11
|
+
this.speed = speed;
|
|
12
|
+
}
|
|
13
|
+
schedule(func) {
|
|
14
|
+
this.controller = setTimeout(func, this.delay / this.speed);
|
|
15
|
+
}
|
|
16
|
+
increment() {
|
|
17
|
+
this.current++;
|
|
18
|
+
}
|
|
19
|
+
clearFrames() {
|
|
20
|
+
if (this.controller) {
|
|
21
|
+
clearTimeout(this.controller);
|
|
22
|
+
this.controller = null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.FrameRate = FrameRate;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var _a;
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.InstanceTracker = void 0;
|
|
4
5
|
const event_emitter_1 = require("@figliolia/event-emitter");
|
|
@@ -19,12 +20,13 @@ class InstanceTracker {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
exports.InstanceTracker = InstanceTracker;
|
|
23
|
+
_a = InstanceTracker;
|
|
22
24
|
InstanceTracker.LOG = console.log;
|
|
23
25
|
InstanceTracker.IDs = new event_emitter_1.AutoIncrementingID();
|
|
24
26
|
InstanceTracker.bucket = new Map();
|
|
27
|
+
InstanceTracker.loggers = ["log", "warn", "info", "error"];
|
|
25
28
|
(() => {
|
|
26
|
-
|
|
27
|
-
methods.forEach((method) => {
|
|
29
|
+
_a.loggers.forEach(method => {
|
|
28
30
|
const original = console[method];
|
|
29
31
|
console[method] = function (...args) {
|
|
30
32
|
InstanceTracker.clearAll();
|
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/types.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
1
|
export type AnimationFN = (str: string, frame: number) => string;
|
|
2
|
+
export type AnimationName = "rainbow" | "pulse" | "glitch" | "radar" | "neon" | "karaoke";
|
|
3
|
+
export type MethodLike<T = any> = (...args: any[]) => T;
|
|
4
|
+
export type MethodKeys<T, R = any> = keyof {
|
|
5
|
+
[K in keyof T as Required<T>[K] extends MethodLike<R> ? K : never]: T[K];
|
|
6
|
+
};
|
package/dist/mjs/Animation.d.ts
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import type { AnimationFN } from "./types";
|
|
2
|
-
import {
|
|
3
|
-
export declare class Animation extends
|
|
4
|
-
effect: any;
|
|
2
|
+
import { FrameRate } from "./FrameRate";
|
|
3
|
+
export declare class Animation extends FrameRate {
|
|
5
4
|
lines: number;
|
|
6
|
-
speed: number;
|
|
7
|
-
delay: number;
|
|
8
5
|
text: string[];
|
|
9
6
|
stopped: boolean;
|
|
10
|
-
currentFrame: number;
|
|
11
7
|
initialized: boolean;
|
|
12
|
-
|
|
8
|
+
effect: AnimationFN;
|
|
9
|
+
static readonly LINE_BREAKS: RegExp;
|
|
13
10
|
constructor(effect: AnimationFN, str: string, delay?: number, speed?: number);
|
|
14
11
|
render(): void;
|
|
15
|
-
|
|
16
|
-
replace(str: string)
|
|
17
|
-
stop()
|
|
18
|
-
start()
|
|
19
|
-
private clearFrames;
|
|
12
|
+
nextFrame(): string;
|
|
13
|
+
readonly replace: (str: string) => this;
|
|
14
|
+
readonly stop: () => this;
|
|
15
|
+
readonly start: () => this;
|
|
20
16
|
}
|
package/dist/mjs/Animation.js
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { FrameRate } from "./FrameRate";
|
|
2
|
+
import { Decor } from "./Decor";
|
|
3
|
+
export class Animation extends FrameRate {
|
|
4
4
|
lines;
|
|
5
|
-
speed;
|
|
6
|
-
delay;
|
|
7
5
|
text;
|
|
8
6
|
stopped = false;
|
|
9
|
-
currentFrame = 0;
|
|
10
7
|
initialized = false;
|
|
11
|
-
|
|
8
|
+
effect;
|
|
9
|
+
static LINE_BREAKS = /\r\n|\r|\n/;
|
|
12
10
|
constructor(effect, str, delay = 0, speed = 0) {
|
|
13
|
-
super();
|
|
11
|
+
super(delay, speed);
|
|
14
12
|
this.effect = effect;
|
|
15
|
-
this.
|
|
16
|
-
this.delay = delay;
|
|
17
|
-
this.text = str.split(/\r\n|\r|\n/);
|
|
13
|
+
this.text = str.split(Animation.LINE_BREAKS);
|
|
18
14
|
this.lines = this.text.length;
|
|
19
15
|
}
|
|
20
16
|
render() {
|
|
@@ -22,40 +18,31 @@ export class Animation extends InstanceTracker {
|
|
|
22
18
|
Animation.LOG("\n".repeat(this.lines - 1));
|
|
23
19
|
this.initialized = true;
|
|
24
20
|
}
|
|
25
|
-
Animation.LOG(this.
|
|
26
|
-
this.
|
|
21
|
+
Animation.LOG(this.nextFrame());
|
|
22
|
+
this.schedule(() => {
|
|
27
23
|
if (!this.stopped) {
|
|
28
24
|
this.render();
|
|
29
25
|
}
|
|
30
|
-
}
|
|
26
|
+
});
|
|
31
27
|
}
|
|
32
|
-
|
|
33
|
-
this.
|
|
28
|
+
nextFrame() {
|
|
29
|
+
this.increment();
|
|
34
30
|
return ("\u001B[" +
|
|
35
31
|
`${this.lines}` +
|
|
36
32
|
"F\u001B[G\u001B[2K" +
|
|
37
|
-
this.text.map(
|
|
33
|
+
this.text.map(str => this.effect(str, this.current)).join("\n"));
|
|
38
34
|
}
|
|
39
|
-
replace(str) {
|
|
40
|
-
this.text = str.split(
|
|
35
|
+
replace = Decor.chainable(this, (str) => {
|
|
36
|
+
this.text = str.split(Animation.LINE_BREAKS);
|
|
41
37
|
this.lines = this.text.length;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
stop() {
|
|
38
|
+
});
|
|
39
|
+
stop = Decor.chainable(this, () => {
|
|
45
40
|
this.clearFrames();
|
|
46
41
|
this.stopped = true;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
start() {
|
|
42
|
+
});
|
|
43
|
+
start = Decor.chainable(this, () => {
|
|
50
44
|
this.clearFrames();
|
|
51
45
|
this.stopped = false;
|
|
52
46
|
this.render();
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
clearFrames() {
|
|
56
|
-
if (this.controller) {
|
|
57
|
-
clearTimeout(this.controller);
|
|
58
|
-
this.controller = null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
47
|
+
});
|
|
61
48
|
}
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { Animation } from "./Animation";
|
|
2
|
+
/**
|
|
3
|
+
* Chalk Animation
|
|
4
|
+
*
|
|
5
|
+
* Console animations for your CLI tools
|
|
6
|
+
*
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const animation = ChalkAnimation.rainbow("hello!");
|
|
9
|
+
* animation.stop();
|
|
10
|
+
* animation.start();
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
2
13
|
export declare class ChalkAnimation {
|
|
3
|
-
static
|
|
4
|
-
static
|
|
5
|
-
static
|
|
6
|
-
static
|
|
7
|
-
static
|
|
8
|
-
static karaoke(str: string, speed?: number)
|
|
9
|
-
static
|
|
14
|
+
static readonly neon: (str: string, speed?: number) => Animation;
|
|
15
|
+
static readonly radar: (str: string, speed?: number) => Animation;
|
|
16
|
+
static readonly pulse: (str: string, speed?: number) => Animation;
|
|
17
|
+
static readonly glitch: (str: string, speed?: number) => Animation;
|
|
18
|
+
static readonly rainbow: (str: string, speed?: number) => Animation;
|
|
19
|
+
static readonly karaoke: (str: string, speed?: number) => Animation;
|
|
20
|
+
private static configure;
|
|
10
21
|
}
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import { Effects } from "./Effects";
|
|
2
2
|
import { Animation } from "./Animation";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Chalk Animation
|
|
5
|
+
*
|
|
6
|
+
* Console animations for your CLI tools
|
|
7
|
+
*
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const animation = ChalkAnimation.rainbow("hello!");
|
|
10
|
+
* animation.stop();
|
|
11
|
+
* animation.start();
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
4
14
|
export class ChalkAnimation {
|
|
5
|
-
static
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
static
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
static
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return animateString(Effects.neon, str, 500, speed);
|
|
19
|
-
}
|
|
20
|
-
static karaoke(str, speed = 1) {
|
|
21
|
-
return animateString(Effects.karaoke, str, 50, speed);
|
|
22
|
-
}
|
|
23
|
-
static clearAllAnimations() {
|
|
24
|
-
return Animation.clearAll();
|
|
15
|
+
static neon = this.configure("neon", 500);
|
|
16
|
+
static radar = this.configure("radar", 50);
|
|
17
|
+
static pulse = this.configure("pulse", 16);
|
|
18
|
+
static glitch = this.configure("glitch", 55);
|
|
19
|
+
static rainbow = this.configure("rainbow", 15);
|
|
20
|
+
static karaoke = this.configure("karaoke", 50);
|
|
21
|
+
static configure(effect, delay) {
|
|
22
|
+
return (str, speed = 1) => {
|
|
23
|
+
if (!speed || speed <= 0) {
|
|
24
|
+
throw new Error("Expected `speed` to be an number greater than 0");
|
|
25
|
+
}
|
|
26
|
+
return new Animation(Effects[effect], str, delay, speed).start();
|
|
27
|
+
};
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { MethodKeys, MethodLike } from "./types";
|
|
2
|
+
export declare class Decor {
|
|
3
|
+
static bound<T, K extends MethodKeys<T>>(target: T, _propertyKey: K, descriptor: TypedPropertyDescriptor<MethodLike>): void;
|
|
4
|
+
static chainable<I, F extends (...args: any[]) => any>(instance: I, func: F): (...params: Parameters<F>) => I;
|
|
5
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class Decor {
|
|
2
|
+
static bound(target, _propertyKey, descriptor) {
|
|
3
|
+
const operation = descriptor.value;
|
|
4
|
+
if (operation) {
|
|
5
|
+
descriptor.value = operation.bind(target);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
static chainable(instance, func) {
|
|
9
|
+
return (...params) => {
|
|
10
|
+
func(...params);
|
|
11
|
+
return instance;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
package/dist/mjs/Effects.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare class Effects {
|
|
2
|
-
static longHsv: {
|
|
2
|
+
static readonly longHsv: {
|
|
3
3
|
interpolation: string;
|
|
4
4
|
hsvSpin: string;
|
|
5
5
|
};
|
|
6
|
-
static glitchChars
|
|
6
|
+
static readonly glitchChars = "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
7
7
|
static rainbow(str: string, frame: number): string;
|
|
8
8
|
static pulse(str: string, frame: number): string;
|
|
9
9
|
static glitch(str: string, frame: number): string;
|
package/dist/mjs/Effects.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
1
7
|
import chalk from "chalk";
|
|
2
8
|
import gradient from "gradient-string";
|
|
9
|
+
import { Decor } from "./Decor";
|
|
3
10
|
export class Effects {
|
|
4
11
|
static longHsv = { interpolation: "hsv", hsvSpin: "long" };
|
|
5
12
|
static glitchChars = "x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
@@ -7,7 +14,7 @@ export class Effects {
|
|
|
7
14
|
const hue = 5 * frame;
|
|
8
15
|
const leftColor = { h: hue % 360, s: 1, v: 1 };
|
|
9
16
|
const rightColor = { h: (hue + 1) % 360, s: 1, v: 1 };
|
|
10
|
-
return gradient(leftColor, rightColor)(str,
|
|
17
|
+
return gradient(leftColor, rightColor)(str, this.longHsv);
|
|
11
18
|
}
|
|
12
19
|
static pulse(str, frame) {
|
|
13
20
|
frame = (frame % 120) + 1;
|
|
@@ -52,7 +59,7 @@ export class Effects {
|
|
|
52
59
|
i += skip;
|
|
53
60
|
if (str[i]) {
|
|
54
61
|
if (str[i] !== "\n" && str[i] !== "\r" && Math.random() > 0.995) {
|
|
55
|
-
chunks.push(
|
|
62
|
+
chunks.push(this.glitchChars[Math.floor(Math.random() * this.glitchChars.length)]);
|
|
56
63
|
}
|
|
57
64
|
else if (Math.random() > 0.005) {
|
|
58
65
|
chunks.push(str[i]);
|
|
@@ -100,3 +107,21 @@ export class Effects {
|
|
|
100
107
|
chalk.white(str.substr(chars)));
|
|
101
108
|
}
|
|
102
109
|
}
|
|
110
|
+
__decorate([
|
|
111
|
+
Decor.bound
|
|
112
|
+
], Effects, "rainbow", null);
|
|
113
|
+
__decorate([
|
|
114
|
+
Decor.bound
|
|
115
|
+
], Effects, "pulse", null);
|
|
116
|
+
__decorate([
|
|
117
|
+
Decor.bound
|
|
118
|
+
], Effects, "glitch", null);
|
|
119
|
+
__decorate([
|
|
120
|
+
Decor.bound
|
|
121
|
+
], Effects, "radar", null);
|
|
122
|
+
__decorate([
|
|
123
|
+
Decor.bound
|
|
124
|
+
], Effects, "neon", null);
|
|
125
|
+
__decorate([
|
|
126
|
+
Decor.bound
|
|
127
|
+
], Effects, "karaoke", null);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InstanceTracker } from "./InstanceTracker";
|
|
2
|
+
export declare class FrameRate extends InstanceTracker {
|
|
3
|
+
current: number;
|
|
4
|
+
speed: number;
|
|
5
|
+
delay: number;
|
|
6
|
+
controller: ReturnType<typeof setTimeout> | null;
|
|
7
|
+
constructor(delay: number, speed: number);
|
|
8
|
+
schedule<F extends () => any>(func: F): void;
|
|
9
|
+
increment(): void;
|
|
10
|
+
clearFrames(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { InstanceTracker } from "./InstanceTracker";
|
|
2
|
+
export class FrameRate extends InstanceTracker {
|
|
3
|
+
current = 0;
|
|
4
|
+
speed;
|
|
5
|
+
delay;
|
|
6
|
+
controller = null;
|
|
7
|
+
constructor(delay, speed) {
|
|
8
|
+
super();
|
|
9
|
+
this.delay = delay;
|
|
10
|
+
this.speed = speed;
|
|
11
|
+
}
|
|
12
|
+
schedule(func) {
|
|
13
|
+
this.controller = setTimeout(func, this.delay / this.speed);
|
|
14
|
+
}
|
|
15
|
+
increment() {
|
|
16
|
+
this.current++;
|
|
17
|
+
}
|
|
18
|
+
clearFrames() {
|
|
19
|
+
if (this.controller) {
|
|
20
|
+
clearTimeout(this.controller);
|
|
21
|
+
this.controller = null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -4,14 +4,14 @@ export class InstanceTracker {
|
|
|
4
4
|
static LOG = console.log;
|
|
5
5
|
static IDs = new AutoIncrementingID();
|
|
6
6
|
static bucket = new Map();
|
|
7
|
+
static loggers = ["log", "warn", "info", "error"];
|
|
7
8
|
constructor() {
|
|
8
9
|
InstanceTracker.clearAll();
|
|
9
10
|
this.ID = InstanceTracker.IDs.get();
|
|
10
11
|
InstanceTracker.bucket.set(this.ID, this.instance);
|
|
11
12
|
}
|
|
12
13
|
static {
|
|
13
|
-
|
|
14
|
-
methods.forEach((method) => {
|
|
14
|
+
this.loggers.forEach(method => {
|
|
15
15
|
const original = console[method];
|
|
16
16
|
console[method] = function (...args) {
|
|
17
17
|
InstanceTracker.clearAll();
|
package/dist/mjs/index.d.ts
CHANGED
package/dist/mjs/types.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
1
|
export type AnimationFN = (str: string, frame: number) => string;
|
|
2
|
+
export type AnimationName = "rainbow" | "pulse" | "glitch" | "radar" | "neon" | "karaoke";
|
|
3
|
+
export type MethodLike<T = any> = (...args: any[]) => T;
|
|
4
|
+
export type MethodKeys<T, R = any> = keyof {
|
|
5
|
+
[K in keyof T as Required<T>[K] extends MethodLike<R> ? K : never]: T[K];
|
|
6
|
+
};
|
package/package.json
CHANGED
package/src/Animation.ts
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import type { AnimationFN } from "./types";
|
|
2
|
-
import {
|
|
2
|
+
import { FrameRate } from "./FrameRate";
|
|
3
|
+
import { Decor } from "./Decor";
|
|
3
4
|
|
|
4
|
-
export class Animation extends
|
|
5
|
-
effect: any;
|
|
5
|
+
export class Animation extends FrameRate {
|
|
6
6
|
lines: number;
|
|
7
|
-
speed: number;
|
|
8
|
-
delay: number;
|
|
9
7
|
text: string[];
|
|
10
8
|
stopped = false;
|
|
11
|
-
currentFrame = 0;
|
|
12
9
|
initialized = false;
|
|
13
|
-
|
|
10
|
+
effect: AnimationFN;
|
|
11
|
+
static readonly LINE_BREAKS = /\r\n|\r|\n/;
|
|
14
12
|
constructor(effect: AnimationFN, str: string, delay = 0, speed = 0) {
|
|
15
|
-
super();
|
|
13
|
+
super(delay, speed);
|
|
16
14
|
this.effect = effect;
|
|
17
|
-
this.
|
|
18
|
-
this.delay = delay;
|
|
19
|
-
this.text = str.split(/\r\n|\r|\n/);
|
|
15
|
+
this.text = str.split(Animation.LINE_BREAKS);
|
|
20
16
|
this.lines = this.text.length;
|
|
21
17
|
}
|
|
22
18
|
|
|
@@ -25,47 +21,37 @@ export class Animation extends InstanceTracker {
|
|
|
25
21
|
Animation.LOG("\n".repeat(this.lines - 1));
|
|
26
22
|
this.initialized = true;
|
|
27
23
|
}
|
|
28
|
-
Animation.LOG(this.
|
|
29
|
-
this.
|
|
24
|
+
Animation.LOG(this.nextFrame());
|
|
25
|
+
this.schedule(() => {
|
|
30
26
|
if (!this.stopped) {
|
|
31
27
|
this.render();
|
|
32
28
|
}
|
|
33
|
-
}
|
|
29
|
+
});
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
public
|
|
37
|
-
this.
|
|
32
|
+
public nextFrame() {
|
|
33
|
+
this.increment();
|
|
38
34
|
return (
|
|
39
35
|
"\u001B[" +
|
|
40
36
|
`${this.lines}` +
|
|
41
37
|
"F\u001B[G\u001B[2K" +
|
|
42
|
-
this.text.map(
|
|
38
|
+
this.text.map(str => this.effect(str, this.current)).join("\n")
|
|
43
39
|
);
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
public replace(str: string) {
|
|
47
|
-
this.text = str.split(
|
|
42
|
+
public readonly replace = Decor.chainable(this, (str: string) => {
|
|
43
|
+
this.text = str.split(Animation.LINE_BREAKS);
|
|
48
44
|
this.lines = this.text.length;
|
|
49
|
-
|
|
50
|
-
}
|
|
45
|
+
});
|
|
51
46
|
|
|
52
|
-
public stop() {
|
|
47
|
+
public readonly stop = Decor.chainable(this, () => {
|
|
53
48
|
this.clearFrames();
|
|
54
49
|
this.stopped = true;
|
|
55
|
-
|
|
56
|
-
}
|
|
50
|
+
});
|
|
57
51
|
|
|
58
|
-
public start() {
|
|
52
|
+
public readonly start = Decor.chainable(this, () => {
|
|
59
53
|
this.clearFrames();
|
|
60
54
|
this.stopped = false;
|
|
61
55
|
this.render();
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private clearFrames() {
|
|
66
|
-
if (this.controller) {
|
|
67
|
-
clearTimeout(this.controller);
|
|
68
|
-
this.controller = null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
56
|
+
});
|
|
71
57
|
}
|
package/src/ChalkAnimation.ts
CHANGED
|
@@ -1,33 +1,32 @@
|
|
|
1
1
|
import { Effects } from "./Effects";
|
|
2
2
|
import { Animation } from "./Animation";
|
|
3
|
-
import {
|
|
3
|
+
import type { AnimationName } from "./types";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Chalk Animation
|
|
7
|
+
*
|
|
8
|
+
* Console animations for your CLI tools
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const animation = ChalkAnimation.rainbow("hello!");
|
|
12
|
+
* animation.stop();
|
|
13
|
+
* animation.start();
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
5
16
|
export class ChalkAnimation {
|
|
6
|
-
public static
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
public static
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public static glitch(str: string, speed = 1) {
|
|
15
|
-
return animateString(Effects.glitch, str, 55, speed);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
public static radar(str: string, speed = 1) {
|
|
19
|
-
return animateString(Effects.radar, str, 50, speed);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public static neon(str: string, speed = 1) {
|
|
23
|
-
return animateString(Effects.neon, str, 500, speed);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public static karaoke(str: string, speed = 1) {
|
|
27
|
-
return animateString(Effects.karaoke, str, 50, speed);
|
|
28
|
-
}
|
|
17
|
+
public static readonly neon = this.configure("neon", 500);
|
|
18
|
+
public static readonly radar = this.configure("radar", 50);
|
|
19
|
+
public static readonly pulse = this.configure("pulse", 16);
|
|
20
|
+
public static readonly glitch = this.configure("glitch", 55);
|
|
21
|
+
public static readonly rainbow = this.configure("rainbow", 15);
|
|
22
|
+
public static readonly karaoke = this.configure("karaoke", 50);
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
return
|
|
24
|
+
private static configure(effect: AnimationName, delay: number) {
|
|
25
|
+
return (str: string, speed = 1) => {
|
|
26
|
+
if (!speed || speed <= 0) {
|
|
27
|
+
throw new Error("Expected `speed` to be an number greater than 0");
|
|
28
|
+
}
|
|
29
|
+
return new Animation(Effects[effect], str, delay, speed).start();
|
|
30
|
+
};
|
|
32
31
|
}
|
|
33
32
|
}
|
package/src/Decor.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MethodKeys, MethodLike } from "./types";
|
|
2
|
+
|
|
3
|
+
export class Decor {
|
|
4
|
+
public static bound<T, K extends MethodKeys<T>>(
|
|
5
|
+
target: T,
|
|
6
|
+
_propertyKey: K,
|
|
7
|
+
descriptor: TypedPropertyDescriptor<MethodLike>,
|
|
8
|
+
) {
|
|
9
|
+
const operation = descriptor.value;
|
|
10
|
+
if (operation) {
|
|
11
|
+
descriptor.value = operation.bind(target);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public static chainable<I, F extends (...args: any[]) => any>(
|
|
16
|
+
instance: I,
|
|
17
|
+
func: F,
|
|
18
|
+
) {
|
|
19
|
+
return (...params: Parameters<F>): I => {
|
|
20
|
+
func(...params);
|
|
21
|
+
return instance;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/Effects.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import gradient from "gradient-string";
|
|
3
|
+
import { Decor } from "./Decor";
|
|
3
4
|
|
|
4
5
|
export class Effects {
|
|
5
|
-
public static longHsv = { interpolation: "hsv", hsvSpin: "long" };
|
|
6
|
-
public static glitchChars =
|
|
6
|
+
public static readonly longHsv = { interpolation: "hsv", hsvSpin: "long" };
|
|
7
|
+
public static readonly glitchChars =
|
|
7
8
|
"x*0987654321[]0-~@#(____!!!!\\|?????....0000\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
9
|
+
|
|
10
|
+
@Decor.bound
|
|
8
11
|
public static rainbow(str: string, frame: number) {
|
|
9
12
|
const hue = 5 * frame;
|
|
10
13
|
const leftColor = { h: hue % 360, s: 1, v: 1 };
|
|
11
14
|
const rightColor = { h: (hue + 1) % 360, s: 1, v: 1 };
|
|
12
|
-
return gradient(leftColor, rightColor)(str,
|
|
15
|
+
return gradient(leftColor, rightColor)(str, this.longHsv);
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
@Decor.bound
|
|
15
19
|
public static pulse(str: string, frame: number) {
|
|
16
20
|
frame = (frame % 120) + 1;
|
|
17
21
|
const transition = 6;
|
|
@@ -48,6 +52,7 @@ export class Effects {
|
|
|
48
52
|
return g(str);
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
@Decor.bound
|
|
51
56
|
public static glitch(str: string, frame: number) {
|
|
52
57
|
if (
|
|
53
58
|
(frame % 2) + (frame % 3) + (frame % 11) + (frame % 29) + (frame % 37) >
|
|
@@ -66,9 +71,9 @@ export class Effects {
|
|
|
66
71
|
if (str[i]) {
|
|
67
72
|
if (str[i] !== "\n" && str[i] !== "\r" && Math.random() > 0.995) {
|
|
68
73
|
chunks.push(
|
|
69
|
-
|
|
70
|
-
Math.floor(Math.random() *
|
|
71
|
-
]
|
|
74
|
+
this.glitchChars[
|
|
75
|
+
Math.floor(Math.random() * this.glitchChars.length)
|
|
76
|
+
],
|
|
72
77
|
);
|
|
73
78
|
} else if (Math.random() > 0.005) {
|
|
74
79
|
chunks.push(str[i]);
|
|
@@ -86,6 +91,7 @@ export class Effects {
|
|
|
86
91
|
return result;
|
|
87
92
|
}
|
|
88
93
|
|
|
94
|
+
@Decor.bound
|
|
89
95
|
public static radar(str: string, frame: number) {
|
|
90
96
|
const depth = Math.floor(Math.min(str.length, str.length * 0.2));
|
|
91
97
|
const step = Math.floor(255 / depth);
|
|
@@ -106,6 +112,7 @@ export class Effects {
|
|
|
106
112
|
return chars.join("");
|
|
107
113
|
}
|
|
108
114
|
|
|
115
|
+
@Decor.bound
|
|
109
116
|
public static neon(str: string, frame: number) {
|
|
110
117
|
const color =
|
|
111
118
|
frame % 2 === 0
|
|
@@ -114,6 +121,7 @@ export class Effects {
|
|
|
114
121
|
return color(str);
|
|
115
122
|
}
|
|
116
123
|
|
|
124
|
+
@Decor.bound
|
|
117
125
|
public static karaoke(str: string, frame: number) {
|
|
118
126
|
const chars = (frame % (str.length + 20)) - 10;
|
|
119
127
|
if (chars < 0) {
|
package/src/FrameRate.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { InstanceTracker } from "./InstanceTracker";
|
|
2
|
+
|
|
3
|
+
export class FrameRate extends InstanceTracker {
|
|
4
|
+
current = 0;
|
|
5
|
+
speed: number;
|
|
6
|
+
delay: number;
|
|
7
|
+
controller: ReturnType<typeof setTimeout> | null = null;
|
|
8
|
+
constructor(delay: number, speed: number) {
|
|
9
|
+
super();
|
|
10
|
+
this.delay = delay;
|
|
11
|
+
this.speed = speed;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public schedule<F extends () => any>(func: F) {
|
|
15
|
+
this.controller = setTimeout(func, this.delay / this.speed);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public increment() {
|
|
19
|
+
this.current++;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public clearFrames() {
|
|
23
|
+
if (this.controller) {
|
|
24
|
+
clearTimeout(this.controller);
|
|
25
|
+
this.controller = null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/InstanceTracker.ts
CHANGED
|
@@ -6,6 +6,7 @@ export class InstanceTracker {
|
|
|
6
6
|
static readonly LOG = console.log;
|
|
7
7
|
static IDs = new AutoIncrementingID();
|
|
8
8
|
static bucket = new Map<string, Animation>();
|
|
9
|
+
static loggers = ["log", "warn", "info", "error"] as const;
|
|
9
10
|
constructor() {
|
|
10
11
|
InstanceTracker.clearAll();
|
|
11
12
|
this.ID = InstanceTracker.IDs.get();
|
|
@@ -13,10 +14,11 @@ export class InstanceTracker {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
static {
|
|
16
|
-
|
|
17
|
-
methods.forEach((method) => {
|
|
17
|
+
this.loggers.forEach(method => {
|
|
18
18
|
const original = console[method];
|
|
19
|
-
console[method] = function (
|
|
19
|
+
console[method] = function (
|
|
20
|
+
...args: Parameters<(typeof console)[typeof method]>
|
|
21
|
+
) {
|
|
20
22
|
InstanceTracker.clearAll();
|
|
21
23
|
return original.apply(console, args);
|
|
22
24
|
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ChalkAnimation } from "../ChalkAnimation";
|
|
2
|
+
import { Effects } from "../Effects";
|
|
3
|
+
import { InstanceTracker } from "../InstanceTracker";
|
|
4
|
+
|
|
5
|
+
const animations = [
|
|
6
|
+
"rainbow",
|
|
7
|
+
"pulse",
|
|
8
|
+
"glitch",
|
|
9
|
+
"radar",
|
|
10
|
+
"neon",
|
|
11
|
+
"karaoke",
|
|
12
|
+
] as const;
|
|
13
|
+
|
|
14
|
+
describe("Chalk Animation", () => {
|
|
15
|
+
afterAll(() => {
|
|
16
|
+
jest.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("Spawn", () => {
|
|
20
|
+
beforeAll(() => {
|
|
21
|
+
jest.spyOn(InstanceTracker, "LOG").mockImplementation(() => {});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
InstanceTracker.clearAll();
|
|
26
|
+
InstanceTracker.IDs.reset();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
animations.forEach(name => {
|
|
30
|
+
it(`ChalkAnimation.${name} - returns an initialized animation instance`, () => {
|
|
31
|
+
const animation = ChalkAnimation[name]("hello");
|
|
32
|
+
expect(animation.effect).toEqual(Effects[name]);
|
|
33
|
+
expect(typeof animation.ID).toEqual("string");
|
|
34
|
+
expect(animation.text).toEqual(["hello"]);
|
|
35
|
+
expect(animation.lines).toEqual(1);
|
|
36
|
+
expect(animation.speed).toEqual(1);
|
|
37
|
+
expect(animation.current).toEqual(1);
|
|
38
|
+
expect(animation.initialized).toEqual(true);
|
|
39
|
+
expect(animation.stopped).toEqual(false);
|
|
40
|
+
expect(animation.controller).not.toEqual(null);
|
|
41
|
+
expect(InstanceTracker.bucket.size).toEqual(1);
|
|
42
|
+
animation.stop();
|
|
43
|
+
expect(animation.stopped).toEqual(true);
|
|
44
|
+
expect(animation.controller).toEqual(null);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
InstanceTracker.loggers.forEach(method => {
|
|
48
|
+
it(`ChalkAnimation.${name} - subsequent console.${method} stop the animation`, () => {
|
|
49
|
+
const animation = ChalkAnimation[name]("hello");
|
|
50
|
+
expect(animation.stopped).toEqual(false);
|
|
51
|
+
console[method]("");
|
|
52
|
+
expect(animation.stopped).toEqual(true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it(`ChalkAnimation.${name} - can be stopped and restarted`, () => {
|
|
57
|
+
const animation = ChalkAnimation[name]("hello");
|
|
58
|
+
animation.stop();
|
|
59
|
+
expect(animation.stopped).toEqual(true);
|
|
60
|
+
animation.start();
|
|
61
|
+
expect(animation.current).toEqual(2);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it(`ChalkAnimation.${name} - can be manually rendered at a desired frame rate`, () => {
|
|
65
|
+
const animation = ChalkAnimation[name]("hello").stop();
|
|
66
|
+
expect(animation.current).toEqual(1);
|
|
67
|
+
animation.render();
|
|
68
|
+
expect(animation.current).toEqual(2);
|
|
69
|
+
animation.render();
|
|
70
|
+
expect(animation.current).toEqual(3);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it(`ChalkAnimation.${name} - text can be replaced`, () => {
|
|
74
|
+
if (name === "radar") {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const animation = ChalkAnimation[name]("Y Y Y").stop();
|
|
78
|
+
const f1 = animation.nextFrame();
|
|
79
|
+
animation.replace("Z Z Z");
|
|
80
|
+
const f2 = animation.nextFrame();
|
|
81
|
+
expect(f1.includes("Y")).toEqual(true);
|
|
82
|
+
expect(f1.includes("Z")).toEqual(false);
|
|
83
|
+
expect(f2.includes("Y")).toEqual(false);
|
|
84
|
+
expect(f2.includes("Z")).toEqual(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it(`ChalkAnimation.${name} - supports multiline strings`, () => {
|
|
88
|
+
const animation = ChalkAnimation[name](
|
|
89
|
+
"Lorem\nipsum\ndolor\nsit\namet",
|
|
90
|
+
).stop();
|
|
91
|
+
const frame = animation.nextFrame();
|
|
92
|
+
expect(animation.lines).toEqual(5);
|
|
93
|
+
expect(frame.split("\n")).toHaveLength(5);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it(`ChalkAnimation.${name} - supports 5K+ frames`, () => {
|
|
97
|
+
const animation = ChalkAnimation[name](
|
|
98
|
+
"Lorem\nipsum\ndolor\nsit\namet",
|
|
99
|
+
).stop();
|
|
100
|
+
for (let i = 0; i < 5000; i++) {
|
|
101
|
+
expect(() => {
|
|
102
|
+
animation.nextFrame();
|
|
103
|
+
}).not.toThrow();
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
1
|
export type AnimationFN = (str: string, frame: number) => string;
|
|
2
|
+
|
|
3
|
+
export type AnimationName =
|
|
4
|
+
| "rainbow"
|
|
5
|
+
| "pulse"
|
|
6
|
+
| "glitch"
|
|
7
|
+
| "radar"
|
|
8
|
+
| "neon"
|
|
9
|
+
| "karaoke";
|
|
10
|
+
|
|
11
|
+
export type MethodLike<T = any> = (...args: any[]) => T;
|
|
12
|
+
|
|
13
|
+
export type MethodKeys<T, R = any> = keyof {
|
|
14
|
+
[K in keyof T as Required<T>[K] extends MethodLike<R> ? K : never]: T[K];
|
|
15
|
+
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.animateString = void 0;
|
|
4
|
-
const Animation_1 = require("./Animation");
|
|
5
|
-
function animateString(effect, str, delay = 0, speed = 0) {
|
|
6
|
-
if (!speed || speed <= 0) {
|
|
7
|
-
throw new Error("Expected `speed` to be an number greater than 0");
|
|
8
|
-
}
|
|
9
|
-
const animation = new Animation_1.Animation(effect, str, delay, speed);
|
|
10
|
-
// setTimeout(() => {
|
|
11
|
-
// if (!animation.stopped) {
|
|
12
|
-
// animation.start();
|
|
13
|
-
// }
|
|
14
|
-
// }, delay / speed);
|
|
15
|
-
animation.start();
|
|
16
|
-
return animation;
|
|
17
|
-
}
|
|
18
|
-
exports.animateString = animateString;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Animation } from "./Animation";
|
|
2
|
-
export function animateString(effect, str, delay = 0, speed = 0) {
|
|
3
|
-
if (!speed || speed <= 0) {
|
|
4
|
-
throw new Error("Expected `speed` to be an number greater than 0");
|
|
5
|
-
}
|
|
6
|
-
const animation = new Animation(effect, str, delay, speed);
|
|
7
|
-
// setTimeout(() => {
|
|
8
|
-
// if (!animation.stopped) {
|
|
9
|
-
// animation.start();
|
|
10
|
-
// }
|
|
11
|
-
// }, delay / speed);
|
|
12
|
-
animation.start();
|
|
13
|
-
return animation;
|
|
14
|
-
}
|
package/src/animateString.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Animation } from "./Animation";
|
|
2
|
-
|
|
3
|
-
export function animateString(effect: any, str: string, delay = 0, speed = 0) {
|
|
4
|
-
if (!speed || speed <= 0) {
|
|
5
|
-
throw new Error("Expected `speed` to be an number greater than 0");
|
|
6
|
-
}
|
|
7
|
-
const animation = new Animation(effect, str, delay, speed);
|
|
8
|
-
// setTimeout(() => {
|
|
9
|
-
// if (!animation.stopped) {
|
|
10
|
-
// animation.start();
|
|
11
|
-
// }
|
|
12
|
-
// }, delay / speed);
|
|
13
|
-
animation.start();
|
|
14
|
-
return animation;
|
|
15
|
-
}
|