cc-face 0.1.10
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 +102 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +142 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/config.d.ts +24 -0
- package/dist/src/config.js +32 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/face.d.ts +59 -0
- package/dist/src/face.js +493 -0
- package/dist/src/face.js.map +1 -0
- package/dist/src/frames.d.ts +1 -0
- package/dist/src/frames.js +6 -0
- package/dist/src/frames.js.map +1 -0
- package/dist/src/generator.d.ts +16 -0
- package/dist/src/generator.js +122 -0
- package/dist/src/generator.js.map +1 -0
- package/dist/src/ipc.d.ts +34 -0
- package/dist/src/ipc.js +203 -0
- package/dist/src/ipc.js.map +1 -0
- package/dist/src/loader.d.ts +12 -0
- package/dist/src/loader.js +63 -0
- package/dist/src/loader.js.map +1 -0
- package/dist/src/main.d.ts +2 -0
- package/dist/src/main.js +210 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/patterns.d.ts +6 -0
- package/dist/src/patterns.js +14 -0
- package/dist/src/patterns.js.map +1 -0
- package/dist/src/pty.d.ts +17 -0
- package/dist/src/pty.js +84 -0
- package/dist/src/pty.js.map +1 -0
- package/dist/src/scroll.d.ts +36 -0
- package/dist/src/scroll.js +56 -0
- package/dist/src/scroll.js.map +1 -0
- package/dist/src/state.d.ts +36 -0
- package/dist/src/state.js +164 -0
- package/dist/src/state.js.map +1 -0
- package/dist/src/theme.d.ts +15 -0
- package/dist/src/theme.js +51 -0
- package/dist/src/theme.js.map +1 -0
- package/dist/src/types.d.ts +60 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +8 -0
- package/dist/src/utils.js +13 -0
- package/dist/src/utils.js.map +1 -0
- package/faces/idle/config.json +7 -0
- package/faces/idle/img/1.jpeg +0 -0
- package/faces/idle/img/10.jpeg +0 -0
- package/faces/idle/img/11.jpeg +0 -0
- package/faces/idle/img/12.jpeg +0 -0
- package/faces/idle/img/13.jpeg +0 -0
- package/faces/idle/img/14.jpeg +0 -0
- package/faces/idle/img/15.jpeg +0 -0
- package/faces/idle/img/16.jpeg +0 -0
- package/faces/idle/img/17.jpeg +0 -0
- package/faces/idle/img/18.jpeg +0 -0
- package/faces/idle/img/19.jpeg +0 -0
- package/faces/idle/img/2.jpeg +0 -0
- package/faces/idle/img/20.jpeg +0 -0
- package/faces/idle/img/21.jpeg +0 -0
- package/faces/idle/img/22.jpeg +0 -0
- package/faces/idle/img/23.jpeg +0 -0
- package/faces/idle/img/24.jpeg +0 -0
- package/faces/idle/img/25.jpeg +0 -0
- package/faces/idle/img/26.jpeg +0 -0
- package/faces/idle/img/27.jpeg +0 -0
- package/faces/idle/img/28.jpeg +0 -0
- package/faces/idle/img/29.jpeg +0 -0
- package/faces/idle/img/3.jpeg +0 -0
- package/faces/idle/img/30.jpeg +0 -0
- package/faces/idle/img/4.jpeg +0 -0
- package/faces/idle/img/5.jpeg +0 -0
- package/faces/idle/img/6.jpeg +0 -0
- package/faces/idle/img/7.jpeg +0 -0
- package/faces/idle/img/8.jpeg +0 -0
- package/faces/idle/img/9.jpeg +0 -0
- package/faces/listening/config.json +5 -0
- package/faces/listening/img/1.jpeg +0 -0
- package/faces/listening/img/10.jpeg +0 -0
- package/faces/listening/img/11.jpeg +0 -0
- package/faces/listening/img/12.jpeg +0 -0
- package/faces/listening/img/13.jpeg +0 -0
- package/faces/listening/img/14.jpeg +0 -0
- package/faces/listening/img/15.jpeg +0 -0
- package/faces/listening/img/16.jpeg +0 -0
- package/faces/listening/img/17.jpeg +0 -0
- package/faces/listening/img/18.jpeg +0 -0
- package/faces/listening/img/19.jpeg +0 -0
- package/faces/listening/img/2.jpeg +0 -0
- package/faces/listening/img/20.jpeg +0 -0
- package/faces/listening/img/21.jpeg +0 -0
- package/faces/listening/img/22.jpeg +0 -0
- package/faces/listening/img/23.jpeg +0 -0
- package/faces/listening/img/24.jpeg +0 -0
- package/faces/listening/img/25.jpeg +0 -0
- package/faces/listening/img/26.jpeg +0 -0
- package/faces/listening/img/27.jpeg +0 -0
- package/faces/listening/img/3.jpeg +0 -0
- package/faces/listening/img/4.jpeg +0 -0
- package/faces/listening/img/5.jpeg +0 -0
- package/faces/listening/img/6.jpeg +0 -0
- package/faces/listening/img/7.jpeg +0 -0
- package/faces/listening/img/8.jpeg +0 -0
- package/faces/listening/img/9.jpeg +0 -0
- package/faces/thinking/config.json +5 -0
- package/faces/thinking/img/1.jpeg +0 -0
- package/faces/thinking/img/10.jpeg +0 -0
- package/faces/thinking/img/11.jpeg +0 -0
- package/faces/thinking/img/12.jpeg +0 -0
- package/faces/thinking/img/13.jpeg +0 -0
- package/faces/thinking/img/14.jpeg +0 -0
- package/faces/thinking/img/15.jpeg +0 -0
- package/faces/thinking/img/16.jpeg +0 -0
- package/faces/thinking/img/17.jpeg +0 -0
- package/faces/thinking/img/18.jpeg +0 -0
- package/faces/thinking/img/19.jpeg +0 -0
- package/faces/thinking/img/2.jpeg +0 -0
- package/faces/thinking/img/20.jpeg +0 -0
- package/faces/thinking/img/3.jpeg +0 -0
- package/faces/thinking/img/4.jpeg +0 -0
- package/faces/thinking/img/5.jpeg +0 -0
- package/faces/thinking/img/6.jpeg +0 -0
- package/faces/thinking/img/7.jpeg +0 -0
- package/faces/thinking/img/8.jpeg +0 -0
- package/faces/thinking/img/9.jpeg +0 -0
- package/faces/typing/config.json +5 -0
- package/faces/typing/img/1.jpeg +0 -0
- package/faces/typing/img/10.jpeg +0 -0
- package/faces/typing/img/11.jpeg +0 -0
- package/faces/typing/img/12.jpeg +0 -0
- package/faces/typing/img/13.jpeg +0 -0
- package/faces/typing/img/14.jpeg +0 -0
- package/faces/typing/img/15.jpeg +0 -0
- package/faces/typing/img/16.jpeg +0 -0
- package/faces/typing/img/17.jpeg +0 -0
- package/faces/typing/img/18.jpeg +0 -0
- package/faces/typing/img/19.jpeg +0 -0
- package/faces/typing/img/2.jpeg +0 -0
- package/faces/typing/img/20.jpeg +0 -0
- package/faces/typing/img/21.jpeg +0 -0
- package/faces/typing/img/22.jpeg +0 -0
- package/faces/typing/img/23.jpeg +0 -0
- package/faces/typing/img/24.jpeg +0 -0
- package/faces/typing/img/25.jpeg +0 -0
- package/faces/typing/img/26.jpeg +0 -0
- package/faces/typing/img/27.jpeg +0 -0
- package/faces/typing/img/28.jpeg +0 -0
- package/faces/typing/img/29.jpeg +0 -0
- package/faces/typing/img/3.jpeg +0 -0
- package/faces/typing/img/30.jpeg +0 -0
- package/faces/typing/img/31.jpeg +0 -0
- package/faces/typing/img/32.jpeg +0 -0
- package/faces/typing/img/4.jpeg +0 -0
- package/faces/typing/img/5.jpeg +0 -0
- package/faces/typing/img/6.jpeg +0 -0
- package/faces/typing/img/7.jpeg +0 -0
- package/faces/typing/img/8.jpeg +0 -0
- package/faces/typing/img/9.jpeg +0 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# cc-face: Animated ASCII anime girl for Claude Code
|
|
2
|
+
|
|
3
|
+
An expressive ASCII face that reacts to Claude Code in real-time. It monitors Claude's activity and changes expression based on what Claude is doing — idle, listening, thinking, or typing.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g cc-face
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js >= 18 and [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Run Claude Code in one terminal, and render the face in another.
|
|
16
|
+
|
|
17
|
+
**Terminal 1** — launch Claude with the face server:
|
|
18
|
+
```bash
|
|
19
|
+
cc-face
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Terminal 2** — open the face renderer:
|
|
23
|
+
```bash
|
|
24
|
+
cc-face -face
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The face automatically detects Claude's state:
|
|
28
|
+
|
|
29
|
+
| Expression | Trigger |
|
|
30
|
+
|---|---|
|
|
31
|
+
| **Idle** | Claude is not active (relaxed blinking animation) |
|
|
32
|
+
| **Listening** | You're typing a prompt |
|
|
33
|
+
| **Thinking** | Claude is reasoning (spinner/thinking indicator detected) |
|
|
34
|
+
| **Typing** | Claude is generating output |
|
|
35
|
+
|
|
36
|
+
### Options
|
|
37
|
+
|
|
38
|
+
| Flag | Description |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `--face <path>` | Load a custom face definition |
|
|
41
|
+
| `-face, -f` | Run only the face renderer |
|
|
42
|
+
| `--theme dark\|light\|auto` | Color theme (default: `auto`) |
|
|
43
|
+
| `--no-face` | Plain passthrough, no face server |
|
|
44
|
+
| `--debug` | Print diagnostics before launching |
|
|
45
|
+
| `-h, --help` | Show help |
|
|
46
|
+
| `-v, --version` | Show version |
|
|
47
|
+
|
|
48
|
+
### Environment variables
|
|
49
|
+
|
|
50
|
+
| Variable | Description |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `CLAUDE_PATH` | Override the path to the Claude binary |
|
|
53
|
+
|
|
54
|
+
## How it works
|
|
55
|
+
|
|
56
|
+
cc-face runs as two processes connected via a Unix domain socket:
|
|
57
|
+
|
|
58
|
+
1. **Wrapper** (`cc-face`) — spawns Claude Code in a PTY, monitors the output stream for state changes (spinner characters, text output, etc.), and broadcasts state updates over IPC.
|
|
59
|
+
2. **Renderer** (`cc-face -face`) — connects to the wrapper, receives state updates, and renders the appropriate animated ASCII frames with smooth per-character transitions.
|
|
60
|
+
|
|
61
|
+
Each expression has 26-27 hand-drawn ASCII frames that loop with configurable timing. Transitions between expressions use a sigmoid-distributed per-character flip effect.
|
|
62
|
+
|
|
63
|
+
## Custom faces
|
|
64
|
+
|
|
65
|
+
Export a `FaceDefinition` from a TypeScript file:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { FaceDefinition } from 'cc-face/src/types';
|
|
69
|
+
|
|
70
|
+
const myFace: FaceDefinition = {
|
|
71
|
+
name: 'robot',
|
|
72
|
+
width: 16,
|
|
73
|
+
height: 5,
|
|
74
|
+
expressions: {
|
|
75
|
+
idle: { name: 'idle', frames: [{ art: [/* ... */] }] },
|
|
76
|
+
typing: { /* ... */ },
|
|
77
|
+
thinking: { /* ... */ },
|
|
78
|
+
listening: { /* ... */ },
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default myFace;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cc-face --face ./my-face.ts
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Local development
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm install
|
|
93
|
+
npm run build
|
|
94
|
+
npm run dev # run wrapper (tsx bin/cli.ts)
|
|
95
|
+
npm run dev -- -face # run face renderer
|
|
96
|
+
npm test # run tests once
|
|
97
|
+
npm run test:watch # run tests in watch mode
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run } from '../src/main.js';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
// ── Argument parsing ────────────────────────────────────────────────
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const options = {
|
|
7
|
+
theme: 'auto',
|
|
8
|
+
noFace: false,
|
|
9
|
+
displayOnly: false,
|
|
10
|
+
debug: false,
|
|
11
|
+
help: false,
|
|
12
|
+
version: false,
|
|
13
|
+
};
|
|
14
|
+
const args = argv.slice(2); // skip node and script path
|
|
15
|
+
for (let i = 0; i < args.length; i++) {
|
|
16
|
+
const arg = args[i];
|
|
17
|
+
if (arg === '--help' || arg === '-h') {
|
|
18
|
+
options.help = true;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (arg === '--version' || arg === '-v') {
|
|
22
|
+
options.version = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (arg === '--no-face') {
|
|
26
|
+
options.noFace = true;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (arg === '-display' || arg === '-f') {
|
|
30
|
+
options.displayOnly = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (arg === '--debug') {
|
|
34
|
+
options.debug = true;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (arg === '--sock') {
|
|
38
|
+
i++;
|
|
39
|
+
if (i >= args.length) {
|
|
40
|
+
console.error('Error: --sock requires a socket path argument.');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
options.socketPath = args[i];
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg.startsWith('--sock=')) {
|
|
47
|
+
options.socketPath = arg.slice('--sock='.length);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (arg === '--face') {
|
|
51
|
+
i++;
|
|
52
|
+
if (i >= args.length) {
|
|
53
|
+
console.error('Error: --face requires a path argument.');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
options.facePath = args[i];
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (arg.startsWith('--face=')) {
|
|
60
|
+
options.facePath = arg.slice('--face='.length);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (arg === '--theme') {
|
|
64
|
+
i++;
|
|
65
|
+
if (i >= args.length) {
|
|
66
|
+
console.error('Error: --theme requires a value (dark, light, or auto).');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const value = args[i];
|
|
70
|
+
if (value !== 'dark' && value !== 'light' && value !== 'auto') {
|
|
71
|
+
console.error(`Error: invalid theme "${value}". Must be dark, light, or auto.`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
options.theme = value;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (arg.startsWith('--theme=')) {
|
|
78
|
+
const value = arg.slice('--theme='.length);
|
|
79
|
+
if (value !== 'dark' && value !== 'light' && value !== 'auto') {
|
|
80
|
+
console.error(`Error: invalid theme "${value}". Must be dark, light, or auto.`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
options.theme = value;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
console.error(`Error: unknown option "${arg}".`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
return options;
|
|
90
|
+
}
|
|
91
|
+
// ── Help text ───────────────────────────────────────────────────────
|
|
92
|
+
const HELP_TEXT = `\
|
|
93
|
+
cc-face — Animated ASCII face for Claude Code
|
|
94
|
+
|
|
95
|
+
Usage: cc-face [options]
|
|
96
|
+
|
|
97
|
+
Options:
|
|
98
|
+
--face <path> Load a custom face definition
|
|
99
|
+
-display, -f Run only the face renderer (connect to running wrapper)
|
|
100
|
+
--sock <path> Socket path to connect to (used with -display)
|
|
101
|
+
--theme dark|light|auto Color theme (default: auto)
|
|
102
|
+
--no-face Run Claude without the face overlay
|
|
103
|
+
--debug Print diagnostic info before launching
|
|
104
|
+
-h, --help Show this help
|
|
105
|
+
-v, --version Show version`;
|
|
106
|
+
// ── Main ────────────────────────────────────────────────────────────
|
|
107
|
+
const options = parseArgs(process.argv);
|
|
108
|
+
if (options.help) {
|
|
109
|
+
console.log(HELP_TEXT);
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
if (options.version) {
|
|
113
|
+
const require = createRequire(import.meta.url);
|
|
114
|
+
const pkg = require('../package.json');
|
|
115
|
+
console.log(pkg.version);
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
async function main() {
|
|
119
|
+
if (options.debug) {
|
|
120
|
+
const { findClaude, resolveSymlink } = await import('../src/pty.js');
|
|
121
|
+
try {
|
|
122
|
+
const claudePath = findClaude();
|
|
123
|
+
const target = resolveSymlink(claudePath);
|
|
124
|
+
console.error(`[debug] claude path: ${claudePath}${target ? ` -> ${target} (symlink)` : ''}`);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.error(`[debug] claude path: NOT FOUND (${err instanceof Error ? err.message : err})`);
|
|
128
|
+
}
|
|
129
|
+
const cols = process.stdout.columns ?? '?';
|
|
130
|
+
const rows = process.stdout.rows ?? '?';
|
|
131
|
+
console.error(`[debug] terminal: ${cols}x${rows}`);
|
|
132
|
+
console.error(`[debug] node: ${process.version}, platform: ${process.platform} ${process.arch}`);
|
|
133
|
+
console.error(`[debug] cwd: ${process.cwd()}`);
|
|
134
|
+
}
|
|
135
|
+
await run(options);
|
|
136
|
+
}
|
|
137
|
+
main().catch((err) => {
|
|
138
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
139
|
+
console.error(`cc-face: ${message}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const config: {
|
|
2
|
+
/** Minimum ms between normal animation frames (~6 fps). */
|
|
3
|
+
minRenderIntervalMs: number;
|
|
4
|
+
/** Total duration of the per-character flip transition (ms). */
|
|
5
|
+
transitionDurationMs: number;
|
|
6
|
+
/** Render interval during a transition (~30 fps). */
|
|
7
|
+
transitionTickMs: number;
|
|
8
|
+
/** Logistic steepness — higher = sharper sigmoid S-curve. */
|
|
9
|
+
sigmoidSteepness: number;
|
|
10
|
+
/** No PTY activity for this long → idle. */
|
|
11
|
+
idleTimeoutMs: number;
|
|
12
|
+
/** Debounce window before committing a state change. */
|
|
13
|
+
debounceMs: number;
|
|
14
|
+
/** How often accumulated PTY data is processed (ms). */
|
|
15
|
+
feedSampleIntervalMs: number;
|
|
16
|
+
/** Minimum printable chars in a PTY chunk to trigger 'typing'. */
|
|
17
|
+
minPrintableLen: number;
|
|
18
|
+
/** After a thinking pattern, suppress typing transitions for this long. */
|
|
19
|
+
thinkingCooldownMs: number;
|
|
20
|
+
/** Inactivity timeout before leaving 'listening' state. */
|
|
21
|
+
listeningTimeoutMs: number;
|
|
22
|
+
/** Delay before retrying a failed IPC connection (ms). */
|
|
23
|
+
ipcRetryMs: number;
|
|
24
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// ── Tunable constants ───────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// All timing, rendering, and state-detection knobs in one place.
|
|
4
|
+
export const config = {
|
|
5
|
+
// ── Rendering ───────────────────────────────────────────────────
|
|
6
|
+
/** Minimum ms between normal animation frames (~6 fps). */
|
|
7
|
+
minRenderIntervalMs: 166,
|
|
8
|
+
// ── Transitions ─────────────────────────────────────────────────
|
|
9
|
+
/** Total duration of the per-character flip transition (ms). */
|
|
10
|
+
transitionDurationMs: 80,
|
|
11
|
+
/** Render interval during a transition (~30 fps). */
|
|
12
|
+
transitionTickMs: 33,
|
|
13
|
+
/** Logistic steepness — higher = sharper sigmoid S-curve. */
|
|
14
|
+
sigmoidSteepness: 7,
|
|
15
|
+
// ── State detection ─────────────────────────────────────────────
|
|
16
|
+
/** No PTY activity for this long → idle. */
|
|
17
|
+
idleTimeoutMs: 500,
|
|
18
|
+
/** Debounce window before committing a state change. */
|
|
19
|
+
debounceMs: 100,
|
|
20
|
+
/** How often accumulated PTY data is processed (ms). */
|
|
21
|
+
feedSampleIntervalMs: 50,
|
|
22
|
+
/** Minimum printable chars in a PTY chunk to trigger 'typing'. */
|
|
23
|
+
minPrintableLen: 3,
|
|
24
|
+
/** After a thinking pattern, suppress typing transitions for this long. */
|
|
25
|
+
thinkingCooldownMs: 400,
|
|
26
|
+
/** Inactivity timeout before leaving 'listening' state. */
|
|
27
|
+
listeningTimeoutMs: 1000,
|
|
28
|
+
// ── IPC ─────────────────────────────────────────────────────────
|
|
29
|
+
/** Delay before retrying a failed IPC connection (ms). */
|
|
30
|
+
ipcRetryMs: 1000,
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,iEAAiE;AAEjE,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,mEAAmE;IACnE,2DAA2D;IAC3D,mBAAmB,EAAE,GAAG;IAExB,mEAAmE;IACnE,gEAAgE;IAChE,oBAAoB,EAAE,EAAE;IACxB,qDAAqD;IACrD,gBAAgB,EAAE,EAAE;IACpB,6DAA6D;IAC7D,gBAAgB,EAAE,CAAC;IAEnB,mEAAmE;IACnE,4CAA4C;IAC5C,aAAa,EAAE,GAAG;IAClB,wDAAwD;IACxD,UAAU,EAAE,GAAG;IACf,wDAAwD;IACxD,oBAAoB,EAAE,EAAE;IACxB,kEAAkE;IAClE,eAAe,EAAE,CAAC;IAClB,2EAA2E;IAC3E,kBAAkB,EAAE,GAAG;IACvB,2DAA2D;IAC3D,kBAAkB,EAAE,IAAI;IAExB,mEAAmE;IACnE,0DAA0D;IAC1D,UAAU,EAAE,IAAI;CACjB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { FaceDefinition, FaceState, ColorSpan, ThemeColors } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render a single art row with ANSI color spans applied.
|
|
4
|
+
* Accepts pre-sorted spans for this specific row only.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderRow(art: string, rowSpans: ColorSpan[], theme: ThemeColors): string;
|
|
7
|
+
export declare class FaceRenderer {
|
|
8
|
+
private face;
|
|
9
|
+
private theme;
|
|
10
|
+
private currentState;
|
|
11
|
+
private currentFrameIndex;
|
|
12
|
+
private animationTimer;
|
|
13
|
+
private cycleStartTime;
|
|
14
|
+
private animCycleDuration;
|
|
15
|
+
private animForwardDuration;
|
|
16
|
+
private animFrameDuration;
|
|
17
|
+
private animFrameCount;
|
|
18
|
+
private animHasReverse;
|
|
19
|
+
private animGapMin;
|
|
20
|
+
private animGapMax;
|
|
21
|
+
private animTickMs;
|
|
22
|
+
private stdoutDraining;
|
|
23
|
+
private hasRenderedOnce;
|
|
24
|
+
private lastRenderedState;
|
|
25
|
+
private lastRenderedFrame;
|
|
26
|
+
private frameCache;
|
|
27
|
+
private clearScreenBuf;
|
|
28
|
+
private cachedCols;
|
|
29
|
+
private cachedRows;
|
|
30
|
+
private transitioning;
|
|
31
|
+
private transitionTimer;
|
|
32
|
+
private transitionStartTime;
|
|
33
|
+
private transitionFlipTimes;
|
|
34
|
+
private transitionOldArt;
|
|
35
|
+
private transitionNewArt;
|
|
36
|
+
private transitionOldRoles;
|
|
37
|
+
private transitionNewRoles;
|
|
38
|
+
private transitionNewState;
|
|
39
|
+
constructor(face: FaceDefinition, theme: ThemeColors);
|
|
40
|
+
private rebuildFrameCache;
|
|
41
|
+
setState(state: FaceState): void;
|
|
42
|
+
invalidateCache(): void;
|
|
43
|
+
showMessage(msg: string): void;
|
|
44
|
+
destroy(): void;
|
|
45
|
+
private buildRoleGrid;
|
|
46
|
+
private generateFlipTimes;
|
|
47
|
+
private beginTransition;
|
|
48
|
+
private scheduleTransitionTick;
|
|
49
|
+
private transitionTick;
|
|
50
|
+
private finishTransition;
|
|
51
|
+
private stopTransition;
|
|
52
|
+
private renderTransitionFrame;
|
|
53
|
+
private startAnimation;
|
|
54
|
+
private startNewCycle;
|
|
55
|
+
private scheduleNextTick;
|
|
56
|
+
private animationTick;
|
|
57
|
+
private stopAnimation;
|
|
58
|
+
private renderNow;
|
|
59
|
+
}
|