fix: sing reaction only starts when recording begins, adjust animation timing
- Add onRecordingStart/onRecordingStop callbacks to InlineSingCard - Move singing reaction trigger from card open to actual recording start - Reduce sing bounce animation movement (6px → 3px for baby, 4px → 2px for egg) - Slow down sing bounce animation (0.4s → 0.5s for baby, 0.5s → 0.6s for egg) - Change Record button label to Sing
This commit is contained in:
@@ -29,6 +29,10 @@ interface InlineSingCardProps {
|
||||
onConfirm: () => Promise<void>;
|
||||
/** Called when user closes the sing card */
|
||||
onClose: () => void;
|
||||
/** Called when recording starts (for Blobbi reaction) */
|
||||
onRecordingStart?: () => void;
|
||||
/** Called when recording stops (for Blobbi reaction) */
|
||||
onRecordingStop?: () => void;
|
||||
/** Whether publishing is in progress */
|
||||
isPublishing: boolean;
|
||||
}
|
||||
@@ -62,6 +66,8 @@ function getSupportedAudioMimeType(): string | undefined {
|
||||
export function InlineSingCard({
|
||||
onConfirm,
|
||||
onClose,
|
||||
onRecordingStart,
|
||||
onRecordingStop,
|
||||
isPublishing,
|
||||
}: InlineSingCardProps) {
|
||||
// Recording state
|
||||
@@ -218,6 +224,9 @@ export function InlineSingCard({
|
||||
setRecordingState('recording');
|
||||
setRecordingDuration(0);
|
||||
|
||||
// Notify parent that recording started (for Blobbi reaction)
|
||||
onRecordingStart?.();
|
||||
|
||||
timerRef.current = setInterval(() => {
|
||||
setRecordingDuration(prev => prev + 1);
|
||||
}, 1000);
|
||||
@@ -236,7 +245,7 @@ export function InlineSingCard({
|
||||
}
|
||||
setRecordingState('error');
|
||||
}
|
||||
}, []);
|
||||
}, [onRecordingStart]);
|
||||
|
||||
// Stop recording
|
||||
const stopRecording = useCallback(() => {
|
||||
@@ -248,7 +257,10 @@ export function InlineSingCard({
|
||||
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
|
||||
mediaRecorderRef.current.stop();
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Notify parent that recording stopped (for Blobbi reaction)
|
||||
onRecordingStop?.();
|
||||
}, [onRecordingStop]);
|
||||
|
||||
// Handle preview playback
|
||||
const handlePreview = useCallback(() => {
|
||||
@@ -384,7 +396,7 @@ export function InlineSingCard({
|
||||
className="rounded-full px-6 bg-purple-500 hover:bg-purple-600"
|
||||
>
|
||||
<Mic className="size-4 mr-2" />
|
||||
Record
|
||||
Sing
|
||||
</Button>
|
||||
)}
|
||||
|
||||
|
||||
@@ -47,20 +47,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Bouncy animation for singing - more energetic than sway */
|
||||
/* Bouncy animation for singing - more energetic than sway but still cute */
|
||||
@keyframes egg-bounce {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(-4px) rotate(2deg);
|
||||
transform: translateY(-2px) rotate(1deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-4px) rotate(-2deg);
|
||||
transform: translateY(-2px) rotate(-1deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
}
|
||||
|
||||
.animate-egg-bounce {
|
||||
/* Egg bounce is gentler than baby/adult (0.5s vs 0.4s) */
|
||||
animation: egg-bounce 0.5s ease-in-out infinite;
|
||||
/* Egg sing bounce - gentler than baby/adult (0.6s vs 0.5s) */
|
||||
animation: egg-bounce 0.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.animate-egg-warmth {
|
||||
|
||||
+4
-4
@@ -183,13 +183,13 @@
|
||||
transform: translateY(0) rotate(0deg);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(-6px) rotate(3deg);
|
||||
transform: translateY(-3px) rotate(1.5deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(0) rotate(0deg);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-6px) rotate(-3deg);
|
||||
transform: translateY(-3px) rotate(-1.5deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,8 +199,8 @@
|
||||
}
|
||||
|
||||
.animate-blobbi-bounce {
|
||||
/* Baby/adult bounce is livelier than egg (0.4s vs 0.5s) */
|
||||
animation: blobbi-bounce 0.4s ease-in-out infinite;
|
||||
/* Baby/adult sing bounce - smoother and cuter than before (0.5s) */
|
||||
animation: blobbi-bounce 0.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
@@ -725,9 +725,8 @@ function BlobbiDashboard({
|
||||
setShowTrackPickerModal(true);
|
||||
} else if (action === 'sing') {
|
||||
// Open the inline sing card directly
|
||||
// Note: Singing reaction starts when recording actually begins (via onRecordingStart)
|
||||
setInlineActivity(createSingActivity());
|
||||
// Start singing reaction animation
|
||||
setBlobbiReaction('singing');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -782,6 +781,15 @@ function BlobbiDashboard({
|
||||
setBlobbiReaction('idle');
|
||||
};
|
||||
|
||||
// Handle sing recording state changes (for Blobbi reaction)
|
||||
const handleSingRecordingStart = () => {
|
||||
setBlobbiReaction('singing');
|
||||
};
|
||||
|
||||
const handleSingRecordingStop = () => {
|
||||
setBlobbiReaction('idle');
|
||||
};
|
||||
|
||||
// Handle opening track picker to change track (from inline player)
|
||||
const handleChangeTrack = () => {
|
||||
setShowTrackPickerModal(true);
|
||||
@@ -976,6 +984,8 @@ function BlobbiDashboard({
|
||||
<InlineSingCard
|
||||
onConfirm={handleConfirmSing}
|
||||
onClose={handleCloseInlineActivity}
|
||||
onRecordingStart={handleSingRecordingStart}
|
||||
onRecordingStop={handleSingRecordingStop}
|
||||
isPublishing={isDirectActionPending}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user