Skip to content

Commit 52a8e8b

Browse files
committed
feat(inquirerer): add Constructive logo animation demo
- Add demo-constructive.ts with animated logo reveal - Uses spinner while loading, then reveals logo line by line - Includes color wave animation effect - Add dev:constructive npm script
1 parent 0a99a25 commit 52a8e8b

2 files changed

Lines changed: 245 additions & 0 deletions

File tree

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Demo: Constructive Logo Animation
4+
*
5+
* Run with: pnpm dev:constructive
6+
* Or: npx ts-node dev/demo-constructive.ts
7+
*/
8+
9+
import { createSpinner, UIEngine, Key } from '../src/ui';
10+
import { cyan, green, yellow, dim, white, magenta, blue } from 'yanse';
11+
12+
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
13+
14+
// Constructive logo ASCII art
15+
const CONSTRUCTIVE_LOGO = `
16+
.=====:
17+
.=== .==-
18+
.==- .==-.
19+
:==: .-==.
20+
-==. -==.
21+
.-==-==. .-===
22+
.-==. :==: .=======
23+
.=== .==- .==========
24+
.==- .==-. :=============
25+
:==: .===================
26+
====. -===================
27+
=: ===. =======================
28+
=: :==: .==========================
29+
=: .==- :=============================
30+
=: .==================================
31+
=: ===============================:
32+
=: ============================.
33+
=: =========================.
34+
=: ======================
35+
.==. ==================-
36+
:==: .===. ===============:
37+
-==. === ============:
38+
.-==. -==: =========.
39+
.===. :==:======.
40+
:==. -===
41+
:=:===. :=====
42+
:= .===. .-========
43+
:= .===: .============
44+
:= ===: :===============
45+
:= :================= .===:
46+
:= ================= .==-. .==-
47+
:= ================= :==- .===
48+
:= ================= :==: .-==.
49+
:= =================-==. .-==.
50+
:==: ==================: .===
51+
:= :==- ================= :==: .======
52+
:= .==-. ================= .==-. :=========
53+
:= .===. ================= .===. :============
54+
:= -=================== ===.================
55+
:= ================= -==================
56+
:= ================= .-=====================
57+
:= ================= .=========================
58+
:= ================= .============================
59+
:= ================================================
60+
-==. ===============================================.
61+
:==: =============. =============================.
62+
:==: ==========. ==========================.
63+
.==-. ======:. ======================-.
64+
.=====: ===================:
65+
.===. ================:
66+
-==. =============.
67+
:==: ==========.
68+
.==- =======
69+
.====-`;
70+
71+
const LOGO_LINES = CONSTRUCTIVE_LOGO.split('\n').filter(line => line.length > 0);
72+
73+
interface AnimationState {
74+
phase: 'loading' | 'revealing' | 'complete' | 'color-wave';
75+
frame: number;
76+
revealLine: number;
77+
colorOffset: number;
78+
}
79+
80+
function colorizeChar(char: string, index: number, lineIndex: number, colorOffset: number): string {
81+
if (char === ' ' || char === '') return char;
82+
83+
// Create a wave effect based on position and offset
84+
const wave = Math.sin((index + lineIndex + colorOffset) * 0.15);
85+
86+
if (wave > 0.5) {
87+
return cyan(char);
88+
} else if (wave > 0) {
89+
return blue(char);
90+
} else if (wave > -0.5) {
91+
return magenta(char);
92+
} else {
93+
return green(char);
94+
}
95+
}
96+
97+
function renderLogoWithColorWave(lines: string[], colorOffset: number): string[] {
98+
return lines.map((line, lineIndex) => {
99+
return line.split('').map((char, charIndex) =>
100+
colorizeChar(char, charIndex, lineIndex, colorOffset)
101+
).join('');
102+
});
103+
}
104+
105+
async function main() {
106+
console.log('\n');
107+
108+
// Phase 1: Loading spinner
109+
const spinner = createSpinner('Initializing Constructive...');
110+
spinner.start();
111+
await sleep(1500);
112+
spinner.text('Loading components...');
113+
await sleep(1000);
114+
spinner.text('Building interface...');
115+
await sleep(1000);
116+
spinner.succeed('Ready!');
117+
118+
await sleep(500);
119+
console.log('\n');
120+
121+
// Phase 2: Reveal animation using UIEngine
122+
const engine = new UIEngine();
123+
124+
await engine.run<AnimationState, void>({
125+
initialState: {
126+
phase: 'revealing',
127+
frame: 0,
128+
revealLine: 0,
129+
colorOffset: 0,
130+
},
131+
hideCursor: true,
132+
tickInterval: 30,
133+
134+
render: (state) => {
135+
const lines: string[] = [];
136+
137+
if (state.phase === 'revealing') {
138+
// Reveal lines one by one with a gradient effect
139+
for (let i = 0; i < state.revealLine && i < LOGO_LINES.length; i++) {
140+
const distanceFromBottom = state.revealLine - i;
141+
if (distanceFromBottom <= 3) {
142+
// Fade in effect for recently revealed lines
143+
lines.push(dim(LOGO_LINES[i]));
144+
} else {
145+
lines.push(cyan(LOGO_LINES[i]));
146+
}
147+
}
148+
// Pad remaining lines
149+
for (let i = state.revealLine; i < LOGO_LINES.length; i++) {
150+
lines.push('');
151+
}
152+
} else if (state.phase === 'color-wave') {
153+
// Color wave animation
154+
lines.push(...renderLogoWithColorWave(LOGO_LINES, state.colorOffset));
155+
} else {
156+
// Complete - static colored logo
157+
lines.push(...LOGO_LINES.map(line => cyan(line)));
158+
}
159+
160+
// Add title and info
161+
lines.push('');
162+
lines.push(white(' C O N S T R U C T I V E'));
163+
lines.push(dim(' Database-first development platform'));
164+
lines.push('');
165+
166+
if (state.phase === 'complete') {
167+
lines.push(dim(' Press any key to exit...'));
168+
} else if (state.phase === 'color-wave') {
169+
lines.push(dim(' Press SPACE to stop animation'));
170+
}
171+
172+
return lines;
173+
},
174+
175+
onEvent: (event, state) => {
176+
if (event.type === 'tick') {
177+
if (state.phase === 'revealing') {
178+
// Reveal 2 lines per tick for faster animation
179+
const newRevealLine = Math.min(state.revealLine + 2, LOGO_LINES.length);
180+
181+
if (newRevealLine >= LOGO_LINES.length) {
182+
// Move to color wave phase
183+
return {
184+
state: {
185+
...state,
186+
phase: 'color-wave',
187+
revealLine: LOGO_LINES.length,
188+
colorOffset: 0,
189+
}
190+
};
191+
}
192+
193+
return {
194+
state: {
195+
...state,
196+
revealLine: newRevealLine,
197+
frame: state.frame + 1,
198+
}
199+
};
200+
} else if (state.phase === 'color-wave') {
201+
// Animate color wave
202+
return {
203+
state: {
204+
...state,
205+
colorOffset: state.colorOffset + 1,
206+
frame: state.frame + 1,
207+
}
208+
};
209+
}
210+
211+
return { state };
212+
}
213+
214+
if (event.type === 'key') {
215+
if (state.phase === 'color-wave' && event.key === Key.SPACE) {
216+
return {
217+
state: { ...state, phase: 'complete' }
218+
};
219+
}
220+
221+
if (state.phase === 'complete') {
222+
return { state, done: true };
223+
}
224+
}
225+
226+
if (event.type === 'char') {
227+
if (state.phase === 'complete') {
228+
return { state, done: true };
229+
}
230+
}
231+
232+
return { state };
233+
},
234+
});
235+
236+
engine.destroy();
237+
238+
console.log('\n');
239+
console.log(green(' Thanks for using Constructive!'));
240+
console.log(dim(' https://github.com/constructive-io/constructive'));
241+
console.log('\n');
242+
}
243+
244+
main().catch(console.error);

packages/inquirerer/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"dev:chat": "ts-node dev/demo-chat",
3030
"dev:upgrade": "ts-node dev/demo-upgrade",
3131
"dev:prompts": "ts-node dev/demo-prompts-engine",
32+
"dev:constructive": "ts-node dev/demo-constructive",
3233
"test": "jest",
3334
"test:watch": "jest --watch"
3435
},

0 commit comments

Comments
 (0)