Skip to content

Commit 6c2bc9a

Browse files
Custom cell completion celebration with Nurro + stats
Dedicated overlay (not badge hero) with: - Random Nurro image (bounces in) - "Congratulations, Cell Complete!" in Orbitron gradient - "Thank you for helping to map the brain. For science!" - "+1 cell brings your total to N" with glowing count - Cyan confetti burst - Auto-dismisses after 6s or click - Triggers from both Cell Library Complete and lightbulb menu Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 55ee33b commit 6c2bc9a

File tree

4 files changed

+134
-6
lines changed

4 files changed

+134
-6
lines changed

src/components/AchievementToast.vue

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,22 @@ watch(() => backend.pendingBadgeCelebration, (pending) => {
293293
fireConfetti('gold', 1.5);
294294
backend.pendingBadgeCelebration = null;
295295
});
296+
297+
// ── Cell completion celebration ──
298+
const cellCelebration = ref<{ totalCells: number; imageUrl: string } | null>(null);
299+
300+
watch(() => backend.pendingCellCelebration, (pending) => {
301+
if (!pending) return;
302+
cellCelebration.value = { ...pending };
303+
fireConfetti('cyan', 2);
304+
backend.pendingCellCelebration = null;
305+
// Auto-dismiss after 6s
306+
setTimeout(() => { cellCelebration.value = null; }, 6000);
307+
});
308+
309+
function dismissCellCelebration() {
310+
cellCelebration.value = null;
311+
}
296312
</script>
297313

298314
<template>
@@ -346,6 +362,21 @@ watch(() => backend.pendingBadgeCelebration, (pending) => {
346362
</div>
347363
</Transition>
348364

365+
<!-- Cell completion celebration overlay -->
366+
<Transition name="nge-cell-celebrate">
367+
<div v-if="cellCelebration" class="nge-cell-overlay" @click="dismissCellCelebration">
368+
<div class="nge-cell-card">
369+
<img v-if="cellCelebration.imageUrl" :src="cellCelebration.imageUrl" class="nge-cell-nurro" />
370+
<div class="nge-cell-text">
371+
<div class="nge-cell-congrats">Congratulations, Cell Complete!</div>
372+
<div class="nge-cell-thanks">Thank you for helping to map the brain. For science!</div>
373+
<div class="nge-cell-stats">+1 cell brings your total to <strong>{{ cellCelebration.totalCells }}</strong></div>
374+
</div>
375+
<div class="nge-cell-hint">Click to dismiss</div>
376+
</div>
377+
</div>
378+
</Transition>
379+
349380
<div class="nge-toast-container">
350381
<TransitionGroup name="nge-toast">
351382
<div
@@ -938,4 +969,101 @@ watch(() => backend.pendingBadgeCelebration, (pending) => {
938969
.nge-toast-move {
939970
transition: transform 0.3s ease;
940971
}
972+
973+
/* ═══ Cell Completion Celebration ═══ */
974+
.nge-cell-overlay {
975+
position: fixed;
976+
inset: 0;
977+
z-index: 100000;
978+
display: flex;
979+
align-items: center;
980+
justify-content: center;
981+
background: rgba(0, 8, 20, 0.85);
982+
backdrop-filter: blur(8px);
983+
cursor: pointer;
984+
}
985+
.nge-cell-card {
986+
display: flex;
987+
flex-direction: column;
988+
align-items: center;
989+
text-align: center;
990+
max-width: 500px;
991+
padding: 40px 50px;
992+
animation: nge-cell-float 3s ease-in-out infinite alternate;
993+
}
994+
.nge-cell-nurro {
995+
width: 200px;
996+
height: 200px;
997+
object-fit: contain;
998+
margin-bottom: 24px;
999+
filter: drop-shadow(0 0 20px rgba(0, 200, 255, 0.3));
1000+
animation: nge-cell-bounce 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
1001+
}
1002+
.nge-cell-text {
1003+
display: flex;
1004+
flex-direction: column;
1005+
gap: 10px;
1006+
}
1007+
.nge-cell-congrats {
1008+
font-family: 'Orbitron', 'Rajdhani', 'Audiowide', monospace;
1009+
font-size: 24px;
1010+
font-weight: 700;
1011+
letter-spacing: 0.06em;
1012+
text-transform: uppercase;
1013+
background: linear-gradient(135deg, #a0ffd4 0%, #00dca0 40%, #58a6ff 100%);
1014+
-webkit-background-clip: text;
1015+
-webkit-text-fill-color: transparent;
1016+
background-clip: text;
1017+
animation: nge-cell-title-in 0.5s ease-out 0.3s both;
1018+
}
1019+
.nge-cell-thanks {
1020+
font-size: 15px;
1021+
color: #99aabb;
1022+
font-style: italic;
1023+
line-height: 1.5;
1024+
animation: nge-cell-fade-in 0.4s ease-out 0.6s both;
1025+
}
1026+
.nge-cell-stats {
1027+
font-size: 16px;
1028+
color: #e0ecff;
1029+
margin-top: 6px;
1030+
font-family: 'Orbitron', monospace;
1031+
letter-spacing: 0.04em;
1032+
animation: nge-cell-fade-in 0.4s ease-out 0.9s both;
1033+
}
1034+
.nge-cell-stats strong {
1035+
font-size: 22px;
1036+
color: #00dca0;
1037+
text-shadow: 0 0 10px rgba(0, 220, 160, 0.4);
1038+
}
1039+
.nge-cell-hint {
1040+
margin-top: 28px;
1041+
font-size: 11px;
1042+
color: #556;
1043+
letter-spacing: 0.1em;
1044+
animation: nge-cell-fade-in 0.4s ease-out 1.2s both;
1045+
}
1046+
1047+
@keyframes nge-cell-bounce {
1048+
0% { transform: scale(0.3) translateY(40px); opacity: 0; }
1049+
60% { transform: scale(1.1) translateY(-8px); opacity: 1; }
1050+
100% { transform: scale(1) translateY(0); opacity: 1; }
1051+
}
1052+
@keyframes nge-cell-title-in {
1053+
0% { opacity: 0; transform: translateY(10px); }
1054+
100% { opacity: 1; transform: translateY(0); }
1055+
}
1056+
@keyframes nge-cell-fade-in {
1057+
0% { opacity: 0; }
1058+
100% { opacity: 1; }
1059+
}
1060+
@keyframes nge-cell-float {
1061+
from { transform: translateY(0); }
1062+
to { transform: translateY(-6px); }
1063+
}
1064+
1065+
/* Transition */
1066+
.nge-cell-celebrate-enter-active { transition: opacity 0.4s ease-out; }
1067+
.nge-cell-celebrate-leave-active { transition: opacity 0.5s ease-in; }
1068+
.nge-cell-celebrate-enter-from, .nge-cell-celebrate-leave-to { opacity: 0; }
9411069
</style>

src/components/CellLibraryPanel.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,8 @@ function triggerCellCelebration() {
287287
const statsStore = useUserStatsStore();
288288
const total = statsStore.stats.cellsSubmitted;
289289
const nurro = NURRO_IMAGES[Math.floor(Math.random() * NURRO_IMAGES.length)];
290-
backend.pendingBadgeCelebration = {
291-
title: '+1 Cell Complete!',
292-
body: `Total cells proofread: ${total}`,
290+
backend.pendingCellCelebration = {
291+
totalCells: total,
293292
imageUrl: nurro,
294293
};
295294
}

src/store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,7 @@ export const useProofreadingBackendStore = defineStore('proofreadingBackend', ()
24002400

24012401
/** Trigger badge celebration from notification click — AchievementToast watches this */
24022402
const pendingBadgeCelebration = ref<{ title: string; body: string; imageUrl: string } | null>(null);
2403+
const pendingCellCelebration = ref<{ totalCells: number; imageUrl: string } | null>(null);
24032404

24042405
const unreadNotificationCount = computed(() =>
24052406
notifications.value.filter(n => !notificationReads.value.has(n.id)).length
@@ -2861,6 +2862,7 @@ export const useProofreadingBackendStore = defineStore('proofreadingBackend', ()
28612862
createNotification, createSelfNotification, deleteNotification, dismissNotification,
28622863
subscribeToNotifications, unsubscribeFromNotifications,
28632864
pendingBadgeCelebration,
2865+
pendingCellCelebration,
28642866
// User Groups
28652867
groups, loadGroups, createGroup, deleteGroup,
28662868
loadGroupMembers, addGroupMembers, removeGroupMember, searchUsers,

src/widgets/lightbulb_service.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,8 @@ export async function setCellComplete(
282282
const statsStore = useUserStatsStore();
283283
const total = statsStore.stats.cellsSubmitted;
284284
const nurro = NURRO_IMAGES[Math.floor(Math.random() * NURRO_IMAGES.length)];
285-
backend.pendingBadgeCelebration = {
286-
title: '+1 Cell Complete!',
287-
body: `Total cells proofread: ${total}`,
285+
backend.pendingCellCelebration = {
286+
totalCells: total,
288287
imageUrl: nurro,
289288
};
290289
} catch { /* non-critical */ }

0 commit comments

Comments
 (0)