Birthday Shout-Out Experience

Celebrate in Luxury

Host Setup

Birthday person: Set your name, birthday date, and photo. Add your RSVP details, gift links, and a thank-you message. Then click Generate Celebration Link and share it with guests.

Required
This name appears in the hero + invitation + thank you.
Countdown uses the next occurrence if the date already passed.
Use a direct image link that ends in .jpg/.png/.webp/.gif.
This saves only on the device that uploads it. Guests should use Photo URL.
Guests use this link so everything loads for the correct celebration.
Birthday person photo
Counting down to
their special day
Days
Hours
Minutes
Seconds

RSVP

Let the host know if you’re coming. Your RSVP saves instantly for this celebration link.

RSVP

Send a Gift

Tap the present to reveal the host’s gift options.

Gift

Thank You

A special note from the birthday person.

From the Host
Thank you for celebrating.
The host can write a thank-you message in Host Setup above.

Guest Shout-Out Wall

Add a message, optional GIF, optional audio — then watch it appear instantly.

Live
For guests across devices, use Audio URL.
Tap emojis to add them. GIF/Audio are optional.

After-Party Photo Gallery

Upload photos after the party or paste a hosted direct image link.

Gallery
Device-only upload. For cross-device, use Photo URL.

Interactive Polls

Vote to shape the vibe. Results update in real time.

Interactive

What should happen first?

Favorite birthday vibe?

Which surprise should they get?

Made for moments that feel unforgettable.
Host sets it up once. Guests simply celebrate.
`; const w = window.open("", "_blank", "noopener,noreferrer,width=980,height=720"); if(!w){ status("Pop-up blocked. Allow pop-ups to print.", "invite"); return; } w.document.open(); w.document.write(html); w.document.close(); }; $("[data-print-invite]")?.addEventListener("click", printInvite); // Generate $("[data-generate]")?.addEventListener("click", async () => { const name = safeText(hostNameInput?.value); const date = safeText(hostDateInput?.value); const photoUrl = safeText(hostPhotoUrlInput?.value); if(!name || !date){ status("Please enter the name and birthday date to generate the link.", "main"); return; } if(photoUrl){ if(isImgbbPageUrl(photoUrl)){ status("That ImgBB link is a page link (ibb.co). Use the DIRECT image link (i.ibb.co + ends in .jpg/.png/.gif).", "main"); showUrlWarning(photoUrl); return; } if(!/^https?:\/\//i.test(photoUrl)){ status("Photo URL must start with http(s).", "main"); return; } showUrlWarning(photoUrl); if(urlWarn && urlWarn.style.display === "block"){ status("Use a direct image URL ending in .jpg/.png/.webp/.gif.", "main"); return; } } const photoFile = hostPhotoInput?.files && hostPhotoInput.files[0] ? hostPhotoInput.files[0] : null; const existing = getHost(); const photoDataUrl = photoFile ? await fileToDataUrl(photoFile) : (existing.photoDataUrl || ""); const cid = ensureCid(); const url = new URL(location.href); url.searchParams.set("cid", cid); url.searchParams.set("n", name.slice(0, 40)); url.searchParams.set("d", date); if(photoUrl) url.searchParams.set("img", photoUrl); history.replaceState({}, "", url.toString()); const host = { name, date, photoUrl, photoDataUrl, location: safeText(hostLocInput?.value), time: safeText(hostTimeInput?.value), thankyou: safeText(hostThankYouInput?.value), cashapp: safeText(hostCashAppInput?.value), venmo: safeText(hostVenmoInput?.value), zelle: safeText(hostZelleInput?.value), paypal: safeText(hostPayPalInput?.value), giftlink: safeText(hostGiftLinkInput?.value), updatedAt: nowISO() }; setHost(host); startCountdown(); status("Celebration link created. Copy and share it!", "main"); sprinkleConfetti(1100); renderInvitationModal(host); }); // Reset host $("[data-reset-host]")?.addEventListener("click", () => { localStorage.removeItem(storageKey("host")); localStorage.removeItem(storageKey("cid")); if(hostNameInput) hostNameInput.value = ""; if(hostDateInput) hostDateInput.value = ""; if(hostPhotoUrlInput) hostPhotoUrlInput.value = ""; if(hostPhotoInput) hostPhotoInput.value = ""; if(hostLocInput) hostLocInput.value = ""; if(hostTimeInput) hostTimeInput.value = ""; if(hostThankYouInput) hostThankYouInput.value = ""; if(hostCashAppInput) hostCashAppInput.value = ""; if(hostVenmoInput) hostVenmoInput.value = ""; if(hostZelleInput) hostZelleInput.value = ""; if(hostPayPalInput) hostPayPalInput.value = ""; if(hostGiftLinkInput) hostGiftLinkInput.value = ""; if(shareLinkInput) shareLinkInput.value = ""; applyHost(getHost()); startCountdown(); status("Host setup reset. Re-enter details to generate a new link.", "main"); }); // Init const init = () => { const host = getHost(); applyHost(host); buildShareLink(host); renderWall(); renderRsvps(); renderGallery(); if(!loadJSON(storageKey("polls"), null)) saveJSON(storageKey("polls"), defaultPolls()); if(!loadJSON(storageKey("reactions"), null)) setReactions(defaultReactions()); renderPollBars(); startCountdown(); if(!safeText(host.name) || !safeText(host.date)){ status("Host: Set your name + date above, then generate your celebration link.", "main"); } }; init(); })();