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:
+23
-18
@@ -80,7 +80,7 @@ export default function App() {
|
|||||||
if (!identified && !loadingPrefs) {
|
if (!identified && !loadingPrefs) {
|
||||||
const savedId = localStorage.getItem('kira-user-id');
|
const savedId = localStorage.getItem('kira-user-id');
|
||||||
if (!savedId) {
|
if (!savedId) {
|
||||||
return <WelcomeScreen onComplete={handleWelcome} isCompact />;
|
return <WelcomeScreen onComplete={handleWelcome} />;
|
||||||
}
|
}
|
||||||
// Has saved ID but not identified yet — show welcome with their name
|
// Has saved ID but not identified yet — show welcome with their name
|
||||||
return (
|
return (
|
||||||
@@ -121,13 +121,9 @@ export default function App() {
|
|||||||
<Toolbar currentScene={currentSceneId} onSceneChange={handleSceneChange} />
|
<Toolbar currentScene={currentSceneId} onSceneChange={handleSceneChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main grid */}
|
{/* Hero: Avatar centered, ~1/3 of viewport */}
|
||||||
<div className="flex-1 overflow-y-auto px-4 py-4 scrollbar-thin">
|
<div className="flex-none flex justify-center py-4 px-4">
|
||||||
<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">
|
<div className="w-full max-w-md">
|
||||||
|
|
||||||
{/* Column 1: Kira + Clock */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Clock />
|
|
||||||
<KiraAvatar
|
<KiraAvatar
|
||||||
isSpeaking={isKiraSpeaking}
|
isSpeaking={isKiraSpeaking}
|
||||||
isListening={isRecording}
|
isListening={isRecording}
|
||||||
@@ -136,22 +132,18 @@ export default function App() {
|
|||||||
onTalkToggle={handleTalkToggle}
|
onTalkToggle={handleTalkToggle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Column 2: Timer + Music + Notes + WhiteNoise */}
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Timer />
|
|
||||||
<MusicPlayer />
|
|
||||||
<Notes />
|
|
||||||
<WhiteNoise />
|
|
||||||
</div>
|
</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">
|
<div className="space-y-4">
|
||||||
<ChatBubble messages={messages} isKiraSpeaking={isKiraSpeaking} userName={userName} livePartial={livePartial} />
|
<ChatBubble messages={messages} isKiraSpeaking={isKiraSpeaking} userName={userName} livePartial={livePartial} />
|
||||||
|
|
||||||
{/* Text input fallback */}
|
{/* Text input fallback */}
|
||||||
<div className="glass-card p-3">
|
<div className="glass-card p-3">
|
||||||
{/* Subtle greeting */}
|
|
||||||
<div className="text-[10px] text-kira-plum/30 mb-2">
|
<div className="text-[10px] text-kira-plum/30 mb-2">
|
||||||
hey {userName} ✨
|
hey {userName} ✨
|
||||||
</div>
|
</div>
|
||||||
@@ -174,8 +166,21 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Column 4: Cats + Wardrobe */}
|
{/* Column 2: Timer + Music */}
|
||||||
<div className="space-y-4">
|
<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 />
|
<PetZone />
|
||||||
<Wardrobe onOutfitChange={handleOutfitChange} onAccessoryChange={handleAccessoryChange} />
|
<Wardrobe onOutfitChange={handleOutfitChange} onAccessoryChange={handleAccessoryChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -55,8 +55,9 @@ export default function KiraAvatar(props: Props) {
|
|||||||
// Cast needed due to pixi-live2d-display expecting older Ticker type
|
// Cast needed due to pixi-live2d-display expecting older Ticker type
|
||||||
(Live2DModel as any).registerTicker(Ticker as any);
|
(Live2DModel as any).registerTicker(Ticker as any);
|
||||||
|
|
||||||
// Responsive sizing
|
// Responsive sizing — fill the container, target ~1/3 viewport
|
||||||
const size = Math.min(container.clientWidth || 260, 260);
|
const containerW = container.clientWidth || 400;
|
||||||
|
const size = Math.min(containerW, 500);
|
||||||
const app = new Application({
|
const app = new Application({
|
||||||
width: size,
|
width: size,
|
||||||
height: size * 1.25,
|
height: size * 1.25,
|
||||||
@@ -198,12 +199,12 @@ export default function KiraAvatar(props: Props) {
|
|||||||
}, [props.accessory, live2dReady]);
|
}, [props.accessory, live2dReady]);
|
||||||
|
|
||||||
return (
|
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 */}
|
{/* Live2D canvas */}
|
||||||
<div
|
<div
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
className={`relative w-full ${live2dReady ? 'block' : 'hidden'}`}
|
className={`relative w-full ${live2dReady ? 'block' : 'hidden'}`}
|
||||||
style={{ maxWidth: 260, height: 325 }}
|
style={{ maxWidth: 500, height: '30vh', minHeight: 250 }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* SVG fallback */}
|
{/* SVG fallback */}
|
||||||
|
|||||||
Reference in New Issue
Block a user