From 52a8e8be0c2364632ff95a0d6df41922a0309424 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sat, 27 Dec 2025 20:13:45 +0000 Subject: [PATCH 1/2] 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 --- packages/inquirerer/dev/demo-constructive.ts | 244 +++++++++++++++++++ packages/inquirerer/package.json | 1 + 2 files changed, 245 insertions(+) create mode 100644 packages/inquirerer/dev/demo-constructive.ts diff --git a/packages/inquirerer/dev/demo-constructive.ts b/packages/inquirerer/dev/demo-constructive.ts new file mode 100644 index 0000000..5c4c297 --- /dev/null +++ b/packages/inquirerer/dev/demo-constructive.ts @@ -0,0 +1,244 @@ +#!/usr/bin/env node +/** + * Demo: Constructive Logo Animation + * + * Run with: pnpm dev:constructive + * Or: npx ts-node dev/demo-constructive.ts + */ + +import { createSpinner, UIEngine, Key } from '../src/ui'; +import { cyan, green, yellow, dim, white, magenta, blue } from 'yanse'; + +const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +// Constructive logo ASCII art +const CONSTRUCTIVE_LOGO = ` + .=====: + .=== .==- + .==- .==-. + :==: .-==. + -==. -==. + .-==-==. .-=== + .-==. :==: .======= + .=== .==- .========== + .==- .==-. :============= + :==: .=================== + ====. -=================== + =: ===. ======================= + =: :==: .========================== + =: .==- :============================= + =: .================================== + =: ===============================: + =: ============================. + =: =========================. + =: ====================== + .==. ==================- + :==: .===. ===============: + -==. === ============: + .-==. -==: =========. + .===. :==:======. + :==. -=== + :=:===. :===== + := .===. .-======== + := .===: .============ + := ===: :=============== + := :================= .===: + := ================= .==-. .==- + := ================= :==- .=== + := ================= :==: .-==. + := =================-==. .-==. + :==: ==================: .=== + := :==- ================= :==: .====== + := .==-. ================= .==-. :========= + := .===. ================= .===. :============ + := -=================== ===.================ + := ================= -================== + := ================= .-===================== + := ================= .========================= + := ================= .============================ + := ================================================ + -==. ===============================================. + :==: =============. =============================. + :==: ==========. ==========================. + .==-. ======:. ======================-. + .=====: ===================: + .===. ================: + -==. =============. + :==: ==========. + .==- ======= + .====-`; + +const LOGO_LINES = CONSTRUCTIVE_LOGO.split('\n').filter(line => line.length > 0); + +interface AnimationState { + phase: 'loading' | 'revealing' | 'complete' | 'color-wave'; + frame: number; + revealLine: number; + colorOffset: number; +} + +function colorizeChar(char: string, index: number, lineIndex: number, colorOffset: number): string { + if (char === ' ' || char === '') return char; + + // Create a wave effect based on position and offset + const wave = Math.sin((index + lineIndex + colorOffset) * 0.15); + + if (wave > 0.5) { + return cyan(char); + } else if (wave > 0) { + return blue(char); + } else if (wave > -0.5) { + return magenta(char); + } else { + return green(char); + } +} + +function renderLogoWithColorWave(lines: string[], colorOffset: number): string[] { + return lines.map((line, lineIndex) => { + return line.split('').map((char, charIndex) => + colorizeChar(char, charIndex, lineIndex, colorOffset) + ).join(''); + }); +} + +async function main() { + console.log('\n'); + + // Phase 1: Loading spinner + const spinner = createSpinner('Initializing Constructive...'); + spinner.start(); + await sleep(1500); + spinner.text('Loading components...'); + await sleep(1000); + spinner.text('Building interface...'); + await sleep(1000); + spinner.succeed('Ready!'); + + await sleep(500); + console.log('\n'); + + // Phase 2: Reveal animation using UIEngine + const engine = new UIEngine(); + + await engine.run({ + initialState: { + phase: 'revealing', + frame: 0, + revealLine: 0, + colorOffset: 0, + }, + hideCursor: true, + tickInterval: 30, + + render: (state) => { + const lines: string[] = []; + + if (state.phase === 'revealing') { + // Reveal lines one by one with a gradient effect + for (let i = 0; i < state.revealLine && i < LOGO_LINES.length; i++) { + const distanceFromBottom = state.revealLine - i; + if (distanceFromBottom <= 3) { + // Fade in effect for recently revealed lines + lines.push(dim(LOGO_LINES[i])); + } else { + lines.push(cyan(LOGO_LINES[i])); + } + } + // Pad remaining lines + for (let i = state.revealLine; i < LOGO_LINES.length; i++) { + lines.push(''); + } + } else if (state.phase === 'color-wave') { + // Color wave animation + lines.push(...renderLogoWithColorWave(LOGO_LINES, state.colorOffset)); + } else { + // Complete - static colored logo + lines.push(...LOGO_LINES.map(line => cyan(line))); + } + + // Add title and info + lines.push(''); + lines.push(white(' C O N S T R U C T I V E')); + lines.push(dim(' Database-first development platform')); + lines.push(''); + + if (state.phase === 'complete') { + lines.push(dim(' Press any key to exit...')); + } else if (state.phase === 'color-wave') { + lines.push(dim(' Press SPACE to stop animation')); + } + + return lines; + }, + + onEvent: (event, state) => { + if (event.type === 'tick') { + if (state.phase === 'revealing') { + // Reveal 2 lines per tick for faster animation + const newRevealLine = Math.min(state.revealLine + 2, LOGO_LINES.length); + + if (newRevealLine >= LOGO_LINES.length) { + // Move to color wave phase + return { + state: { + ...state, + phase: 'color-wave', + revealLine: LOGO_LINES.length, + colorOffset: 0, + } + }; + } + + return { + state: { + ...state, + revealLine: newRevealLine, + frame: state.frame + 1, + } + }; + } else if (state.phase === 'color-wave') { + // Animate color wave + return { + state: { + ...state, + colorOffset: state.colorOffset + 1, + frame: state.frame + 1, + } + }; + } + + return { state }; + } + + if (event.type === 'key') { + if (state.phase === 'color-wave' && event.key === Key.SPACE) { + return { + state: { ...state, phase: 'complete' } + }; + } + + if (state.phase === 'complete') { + return { state, done: true }; + } + } + + if (event.type === 'char') { + if (state.phase === 'complete') { + return { state, done: true }; + } + } + + return { state }; + }, + }); + + engine.destroy(); + + console.log('\n'); + console.log(green(' Thanks for using Constructive!')); + console.log(dim(' https://github.com/constructive-io/constructive')); + console.log('\n'); +} + +main().catch(console.error); diff --git a/packages/inquirerer/package.json b/packages/inquirerer/package.json index ec81dcd..d25cb02 100644 --- a/packages/inquirerer/package.json +++ b/packages/inquirerer/package.json @@ -29,6 +29,7 @@ "dev:chat": "ts-node dev/demo-chat", "dev:upgrade": "ts-node dev/demo-upgrade", "dev:prompts": "ts-node dev/demo-prompts-engine", + "dev:constructive": "ts-node dev/demo-constructive", "test": "jest", "test:watch": "jest --watch" }, From 808cff96a1c95dab9471fb19cde11cf6be10c1fb Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sat, 27 Dec 2025 12:35:41 -0800 Subject: [PATCH 2/2] sized --- packages/inquirerer/dev/demo-constructive.ts | 106 ++++++++----------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/packages/inquirerer/dev/demo-constructive.ts b/packages/inquirerer/dev/demo-constructive.ts index 5c4c297..ca3bb00 100644 --- a/packages/inquirerer/dev/demo-constructive.ts +++ b/packages/inquirerer/dev/demo-constructive.ts @@ -13,60 +13,48 @@ const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); // Constructive logo ASCII art const CONSTRUCTIVE_LOGO = ` - .=====: - .=== .==- - .==- .==-. - :==: .-==. - -==. -==. - .-==-==. .-=== - .-==. :==: .======= - .=== .==- .========== - .==- .==-. :============= - :==: .=================== - ====. -=================== - =: ===. ======================= - =: :==: .========================== - =: .==- :============================= - =: .================================== - =: ===============================: - =: ============================. - =: =========================. - =: ====================== - .==. ==================- - :==: .===. ===============: - -==. === ============: - .-==. -==: =========. - .===. :==:======. - :==. -=== - :=:===. :===== - := .===. .-======== - := .===: .============ - := ===: :=============== - := :================= .===: - := ================= .==-. .==- - := ================= :==- .=== - := ================= :==: .-==. - := =================-==. .-==. - :==: ==================: .=== - := :==- ================= :==: .====== - := .==-. ================= .==-. :========= - := .===. ================= .===. :============ - := -=================== ===.================ - := ================= -================== - := ================= .-===================== - := ================= .========================= - := ================= .============================ - := ================================================ - -==. ===============================================. - :==: =============. =============================. - :==: ==========. ==========================. - .==-. ======:. ======================-. - .=====: ===================: - .===. ================: - -==. =============. - :==: ==========. - .==- ======= - .====-`; + .==- + :=: .--. + -=: ==. + -=: -=. + -=:=: .=== + ==. :=- :====== + .=- .== :========= + :=: .---============ + =-=: -=============== + = -=- =================== + = :=: .====================== + = .========================== + = :======================: + = :===================: + = :================. + -=- :============= + .== .=- :=========- + .=- .-=. :======- + :=: -=-===: + ==- === + = :=- .====== + = .=-. :========= + = =============== + = ============= :=:.==. + = ============= -=: -=. + = ============= -=. -=: + = ============== :=- + =.-=. =============.=- :==== + = -=. ============= .--. -======= + = -=: ============= ==. -========== + = :============= .============== + = ============= .-================ + = ============= .==================== + = =============:======================= + :=: ====================================: + :=- =========. :=====================. + .=- ======. :================== + .-===- :==============- + -=. :===========: + -=. :========: + -=: :=====: + :===.`; const LOGO_LINES = CONSTRUCTIVE_LOGO.split('\n').filter(line => line.length > 0); @@ -159,14 +147,14 @@ async function main() { // Add title and info lines.push(''); - lines.push(white(' C O N S T R U C T I V E')); - lines.push(dim(' Database-first development platform')); + lines.push(white(' C O N S T R U C T I V E')); + lines.push(dim(' Database-first development platform')); lines.push(''); - + if (state.phase === 'complete') { - lines.push(dim(' Press any key to exit...')); + lines.push(dim(' Press any key to exit...')); } else if (state.phase === 'color-wave') { - lines.push(dim(' Press SPACE to stop animation')); + lines.push(dim(' Press SPACE to stop animation')); } return lines;