feat(ui): center avatar as hero, ~1/3 viewport height; tools grid below

- Avatar now centered in its own row above the tools grid (was crammed in column 1)
- KiraAvatar container: min-height 33vh, canvas up to 500px wide
- Tools reorganized into 4 columns below: Chat, Timer+Music, Notes+Noise, Clock+Pets+Wardrobe
- WelcomeScreen restored to full (not compact) for first-time users
This commit is contained in:
2026-06-05 09:03:32 -04:00
parent 92250a668b
commit baaa89756f
2 changed files with 36 additions and 30 deletions
+23 -18
View File
@@ -80,7 +80,7 @@ export default function App() {
if (!identified && !loadingPrefs) {
const savedId = localStorage.getItem('kira-user-id');
if (!savedId) {
return <WelcomeScreen onComplete={handleWelcome} isCompact />;
return <WelcomeScreen onComplete={handleWelcome} />;
}
// Has saved ID but not identified yet — show welcome with their name
return (
@@ -121,13 +121,9 @@ export default function App() {
<Toolbar currentScene={currentSceneId} onSceneChange={handleSceneChange} />
</div>
{/* Main grid */}
<div className="flex-1 overflow-y-auto px-4 py-4 scrollbar-thin">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 max-w-7xl mx-auto">
{/* Column 1: Kira + Clock */}
<div className="space-y-4">
<Clock />
{/* Hero: Avatar centered, ~1/3 of viewport */}
<div className="flex-none flex justify-center py-4 px-4">
<div className="w-full max-w-md">
<KiraAvatar
isSpeaking={isKiraSpeaking}
isListening={isRecording}
@@ -136,22 +132,18 @@ export default function App() {
onTalkToggle={handleTalkToggle}
/>
</div>
{/* Column 2: Timer + Music + Notes + WhiteNoise */}
<div className="space-y-4">
<Timer />
<MusicPlayer />
<Notes />
<WhiteNoise />
</div>
{/* Column 3: Chat + Text Input */}
{/* Tools grid below the avatar */}
<div className="flex-1 overflow-y-auto px-4 pb-4 scrollbar-thin">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 max-w-7xl mx-auto">
{/* Column 1: Chat + Text Input */}
<div className="space-y-4">
<ChatBubble messages={messages} isKiraSpeaking={isKiraSpeaking} userName={userName} livePartial={livePartial} />
{/* Text input fallback */}
<div className="glass-card p-3">
{/* Subtle greeting */}
<div className="text-[10px] text-kira-plum/30 mb-2">
hey {userName}
</div>
@@ -174,8 +166,21 @@ export default function App() {
</div>
</div>
{/* Column 4: Cats + Wardrobe */}
{/* Column 2: Timer + Music */}
<div className="space-y-4">
<Timer />
<MusicPlayer />
</div>
{/* Column 3: Notes + White Noise */}
<div className="space-y-4">
<Notes />
<WhiteNoise />
</div>
{/* Column 4: Cats + Wardrobe + Clock */}
<div className="space-y-4">
<Clock />
<PetZone />
<Wardrobe onOutfitChange={handleOutfitChange} onAccessoryChange={handleAccessoryChange} />
</div>
+5 -4
View File
@@ -55,8 +55,9 @@ export default function KiraAvatar(props: Props) {
// Cast needed due to pixi-live2d-display expecting older Ticker type
(Live2DModel as any).registerTicker(Ticker as any);
// Responsive sizing
const size = Math.min(container.clientWidth || 260, 260);
// Responsive sizing — fill the container, target ~1/3 viewport
const containerW = container.clientWidth || 400;
const size = Math.min(containerW, 500);
const app = new Application({
width: size,
height: size * 1.25,
@@ -198,12 +199,12 @@ export default function KiraAvatar(props: Props) {
}, [props.accessory, live2dReady]);
return (
<div className="glass-card p-4 flex flex-col items-center" style={{ minHeight: 360 }}>
<div className="glass-card p-6 flex flex-col items-center w-full" style={{ minHeight: '33vh' }}>
{/* Live2D canvas */}
<div
ref={canvasRef}
className={`relative w-full ${live2dReady ? 'block' : 'hidden'}`}
style={{ maxWidth: 260, height: 325 }}
style={{ maxWidth: 500, height: '30vh', minHeight: 250 }}
/>
{/* SVG fallback */}