An open-source birthday landing page built to offer smooth animations, interactive features, and straightforward environment-driven customization. Created by Naboraj Sarkar.
📺 Click the thumbnail above to watch the official Birthday Bloom project overview.
Birthday Bloom is now env-first: names, relationship type, messages, colors, photos, captions, videos, audio, visible sections, animation behavior, accessibility, and family-template metadata can be changed from .env.local.
Repository: naborajs/birthday-bloom
Important: when this project says "env", it means environment variables, usually stored in .env.local during local development or in the hosting provider's Environment Variables/Secrets panel during deployment. These values are the intended customization layer. For normal changes, do not rewrite the app code.
If you ask an AI coding agent to customize Birthday Bloom, tell it this first:
This project is already built to be customized through env values. Before editing components or templates, check
.env.exampleanddocs/ENV_GUIDE.md, then tell me which env keys to update.
Direct docs:
- Complete env customization guide
- Quick start
- Family system
- Template architecture
- Developer guide
- Migration guide
- Documentation index
Copy .env.example to .env.local, change values, restart the dev server, and the experience updates without component edits.
Everything you need to get the most out of Birthday Bloom:
| If you want to... | Start here |
|---|---|
| Customize names, colors, photos, sections | ENV_GUIDE.md |
| Run the project locally | quick-start.md |
| Understand the codebase | architecture.md |
| Deploy to Vercel / Netlify / Docker | docs/deployment.md |
| Set up family profiles (brother, sister, etc.) | docs/family-system.md |
| Troubleshoot issues | docs/troubleshooting.md |
| Contribute to the project | CONTRIBUTING.md |
| See what's coming next | roadmap.md |
| Browse community standards | CODE_OF_CONDUCT.md |
| Report a security issue | SECURITY.md |
| Get help | SUPPORT.md / faq.md |
| View version history | CHANGELOG.md |
| Explore all docs | docs/DOCUMENTATION_INDEX.md |
This project provides a personalized landing page built with React 18, Framer Motion, and Tailwind CSS. Rather than static text, it uses sequenced visual transitions and user interactions to guide the recipient through a customized birthday experience.
- Interactive Birthday Quiz: A gamified trivia section that adapts questions based on the recipient's hobbies or relationship.
- Polaroid Memory Gallery: A responsive gallery featuring user-tilting photos and revealable captions.
- Interactive SVG Cake: A vector-based cake with animated candle flames that can be blown out (removing the flame paths) and cut (splitting the cake SVG layers apart with a bounce transition).
- Heartfelt Surprise Letter: A concluding message card utilizing glassmorphism styling and custom background sparkles.
- Interactive Balloons: Physics-correct drifting balloons that can be popped by clicking.
📖 Watch the Complete Birthday Bloom Explainer (8 Minutes)
Learn everything about Birthday Bloom—from the problem it solves, its vision, core features, customization options, workflow, open-source philosophy, future roadmap, and how you can use and contribute to the project.
Most landing page templates are static. Birthday Bloom treats the browser as a stage, using a linear state machine to control the pacing of messages, interactive transitions, and audio feedback.
By coordinating asynchronous delays and Framer Motion timelines, the application guides the user through typing scenes, simulated chats, and final interactive reveals.
- Optimized Performance: We rely on pure CSS and native SVG animations rather than heavy JavaScript physics libraries like Three.js or Matter.js. This ensures smooth 60fps animations on mobile devices while keeping the bundle size small.
- Engaging Text Flow: Typewriter animations, cursor tracking, and simulated messaging windows help build a natural reading pace.
- Environment-Driven Configuration: You can customize the name, relationship, messages, colors, and media simply by setting variables in a single
.env.localfile without editing code. - Vite Build System: Instant Hot-Module-Replacement (HMR) during local development and optimized assets for production deployments.
If you want to deploy Birthday Bloom on the web to share with your loved one, you can do it completely free on Vercel. You don't need any coding experience to follow these steps!
If you prefer a visual guide, click the thumbnail below to watch the complete step-by-step walkthrough:
🚀 Watch the Complete Deployment Guide
Learn how to deploy Birthday Bloom step by step using Vercel. This guide covers everything from forking the GitHub repository, importing the project into Vercel, configuring environment variables, deploying your website, customizing it, and publishing updates. Perfect for beginners and experienced developers alike.
Goal: Get a free space to hold your copy of the website code.
- Direct Link: 👉 GitHub Sign Up
- What to do: Enter your email, create a password, choose a username, and complete the sign-up.
- Why: You need a GitHub account so that Vercel can pull the code and build it for you.
Goal: Copy all of Birthday Bloom's files to your new GitHub account.
- Direct Link: 👉 Fork Birthday Bloom
- What to do:
- Leave the Repository name as
birthday-bloom.- Make sure the checkbox "Copy the main branch only" is checked.
- Click the green
Create forkbutton at the bottom of the page.- Why: This creates a copy under your name (e.g.,
github.com/your-username/birthday-bloom), allowing you to link it to Vercel.
Goal: Sign up for the hosting service that will put your website online for free.
- Direct Link: 👉 Vercel Sign Up
- What to do: Click the
Continue with GitHubbutton. This automatically links your Vercel account to your GitHub account.- Why: Linking with GitHub allows Vercel to read your code copy and automatically deploy updates.
Goal: Tell Vercel to start setting up your birthday website.
- Direct Link: 👉 Vercel - New Project Dashboard
- What to do:
- Under the "Import Git Repository" section, locate the repository named
birthday-bloom.- Click the black
Importbutton next to it.- Why: This imports the project files into Vercel so it can start setting up your deployment.
Goal: Set the name, date, messages, and colors for the birthday person without touching any code.
- What to do:
- On the project setup page in Vercel, find the section labeled
Environment Variables(it is a dropdown panel). Click it to expand.- For each variable below, type the Key in the first field, the Value in the second field, and click the blue
Addbutton:
Key (Environment Variable) Example Value What it controls VITE_USER_NAMESarahThe name of the birthday person. VITE_BIRTHDAY_DATE2026-07-25The birthday date in YYYY-MM-DDformat (sets up the countdown).VITE_TITLEHappy Birthday, Sarah! 🌸The text shown on the browser tab. VITE_CARD_TITLE_SURPRISEA Special Gift for You!The main title on the final letter envelope. VITE_THEME_COLOR#ff69b4The theme color (e.g. pink: #ff69b4, red:#e11d48, blue:#2563eb).[!TIP] For a full list of all 20+ customizable items (like custom messages, photos, and music), check the .env.example configuration file or the Environment Variables Guide section below.
Goal: Build the site and make it live.
- What to do: Click the blue
Deploybutton at the bottom.- What happens next: Vercel will spend about 60–90 seconds building your site. Once done, it will show a preview screen of your website with a shower of confetti!
- Why: This turns your source code files into a live, interactive website accessible from any phone or computer.
Goal: Send the surprise to your loved one!
- What to do:
- Click on the screenshot preview of your website in Vercel to open it.
- Copy the URL from your web browser's address bar. It will look like:
https://birthday-bloom-yourname.vercel.app- Send this link to the birthday person!
- Introduction
- Hyper-Personalization & Templates
- System Architecture
- Mastering the Lifecycle
- Environment Variables Guide
- In-Depth Code Explanation
- Personalization & Customization
- Environment Variables Guide
- Advanced Installation & Setup
- Component API Reference
- Custom Hooks Documentation
- Theming Engine & CSS Variables
- Performance Profiling & GPU Acceleration
- Browser Compatibility Matrix
- Cinematography Theory
- SEO, Social Sharing & OG Tags
- Folder Structure Guide
- Troubleshooting & Massive FAQ
- Author & Brand Identity
- Author & Brand Identity
- License
The transitions and visual layers in Birthday Bloom are timed around natural reading speeds and sequence progression rather than immediate information layout.
We simulate a camera lens depth shift using CSS perspective and Framer Motion's rotateX/Y tilt properties. This creates a clear hierarchy where active interactive elements (like the Cake or Polaroid frames) stand out visually from the floating ambient particles.
- Interactive Elements: 150ms transitions (such as button hover glows and button scales).
- Scene Transitions: 800ms - 1.2s fades to separate typing screens, chat bubbles, and the final dashboard view cleanly.
- Text Staggering: 4s delay per storyline line to ensure comfortable reading pacing.
A subtle background vignette gradient and a light noise overlay help blend the components together, providing a cohesive layout aesthetic.
Birthday Bloom operates as a structured timeline. The following diagram shows the chronological flow of scenes and interactive features from boot to the final reveal.
graph TD
Splash[Splash Screen] -->|Initialize| Intro[Cinematic Intro]
Intro -->|"Phase 1"| Story[Storyline Narrative]
Intro -->|"Phase 2"| Chat[Fake Chat Simulator]
Intro -->|"Phase 3"| Reveal[Birthday Reveal Screen]
Reveal -->|"Load Dashboard"| Main[Main Celebration View]
Main -->|Interact| Cake[Interactive SVG Cake]
Main -->|Interact| Gallery[Polaroid Memory Gallery]
Main -->|Interact| HeartTree[Growing Heart Tree]
Figure: Scene progression flow and interactive features from boot to the grand finale.
The project resolves environment variables and hydrates application state through a central config layer:
flowchart LR
Env[Environment Config] -->|"Load at runtime"| Config[Config Parser]
Config -->|"Hydrate state"| Store[State Store]
Store -->|"Inject values as props"| Components[React Components]
Figure: The data flow from raw environment variables to component properties.
The sequence is divided into two distinct interaction stages: the boot-to-intro phase, and the main dashboard user actions.
Part A: Boot & Intro Sequence
sequenceDiagram
actor User
participant App as "App.tsx"
participant Intro as "CinematicIntro.tsx"
participant Store as "useBirthdayStore.ts"
User->>App: Open Site
App->>Store: Initialize Configuration
App->>Intro: Mount Intro Component
loop Typing Sequences
Intro->>Intro: Play storytelling lines
Intro->>Intro: Play fake-chat typing
Intro->>Intro: Play birthday reveal
end
Intro->>App: Trigger onComplete Callback
App->>Intro: Unmount Intro Component
Figure: Interaction sequence during the initialization and cinematic intro stages.
Part B: Main Dashboard Interactions
sequenceDiagram
actor User
participant Dashboard as "MainBirthday.tsx"
participant Cake as "CakeCutting.tsx"
participant Confetti as "useConfetti.ts"
User->>Dashboard: View Dashboard
Dashboard->>Cake: Render SVG Cake UI
User->>Cake: Click "Blow Candles"
Cake->>Cake: Extinguish SVG flames
Cake->>Confetti: Fire Corner Cannons
User->>Cake: Cut Cake
Cake->>Cake: Split SVG cake layers
Figure: User interactions within the main dashboard and interactive cake cutting engine.
The animation sequence relies on a state machine configured in the entry files. Understanding how these scenes transition is essential before modifying the code.
flowchart LR
Boot[Boot Initializer] -->|Mount| Intro[Cinematic Intro]
subgraph State Machine Phases
Intro --> Story[storytelling scene]
Story -->|"Lines Complete"| Chat[fake-chat scene]
Chat -->|"Typing Complete"| PostChat[post-chat scene]
PostChat -->|"Reveal Trigger"| Reveal[reveal-sequence scene]
Reveal -->|Transition| Done[done scene]
end
Done -->|"Complete Callback"| Main[Main Birthday View]
Figure: The finite state machine phases and transitions of the application.
- Boot:
App.tsxinitializes, loads configuration settings, and decides whether to play the intro sequence based on setup parameters. - Mount:
CinematicIntro.tsxmounts and maps over the custom narrative lines. Timers trigger transitions sequentially. - Execution: During the chat phase, sequence timers control text entry, deletions, and sending animations to simulate active conversations.
- Transition: When the intro completes, the
onCompletecallback triggers the entry component to unmount the intro stage and render theMainBirthday.tsxdashboard. Modifying or removing these timers without care can lock the user inside the intro phase.
Because Birthday Bloom is designed to be fully customizable, the following sections deeply analyze exactly how the components function beneath the hood. If you intend to change pacing, layout, or animations, refer to this manual.
The CinematicIntro component is the bridge between the Splash Screen and the Main Dashboard. It handles a multi-phase emotional sequence.
Code Breakdown:
- State Machine: It uses a strongly typed literal state:
type Scene = "storytelling" | "fake-chat" | "post-chat" | "reveal-sequence" | "done". - Timer Management: Instead of having floating timeouts that could cause memory leaks if a user unmounts early, we use
useRef<ReturnType<typeof setTimeout>[]>([]);to store all timeout IDs, clearing them aggressively when the component unmounts or transitions. - The TypeWriter Component: We use a custom
TypeWritercomponent to begin rendering the string character-by-character based on specific speed delays. - Visuals: Uses dynamic localized backgrounds. Depending on the
scenestate, the background shifts from dark blues to deep maroons, building tension.
The most complex interactive piece of the platform.
Code Breakdown:
- SVG Mastery: The cake is drawn entirely with SVG. This prevents pixelation on high-density Retina displays (iPad Pro, 4K monitors, etc.).
- Layers & Slices: The SVG groups (
<g>) are structurally separated into left and right halves. - The Knife Phase:
- Phase 1: User selects a themed cake (Chocolate, Strawberry, Velvet).
- Phase 2: User triggers the "Blow Candles" mechanic. This toggles a boolean (
candlesLit), transforming the animated SVG<ellipse>flames into rising smoke paths linearly. - Phase 3: The
KnifeSVGenters with a CSS transform, splitting the left and right halves by applyingtranslateXandrotatestyles to the SVG groups.
- Custom Easing: The cake splits using
cubic-bezier(0.34, 1.56, 0.64, 1), a "bounce" easing that gives it physical weight, instead oflinearorease-in-out.
When building emotional tension, reading speed is everything. We moved away from instant text rendering to a programmatic typing approach.
Code Breakdown:
useEffect(() => {
if (!started) return;
if (displayed.length < text.length) {
const timer = setTimeout(() => {
setDisplayed(text.slice(0, displayed.length + 1));
}, speed);
return () => clearTimeout(timer);
} else {
setDone(true);
onComplete?.();
}
}, [started, displayed, text, speed, onComplete]);- Recursive Growth: It takes the current string, measures it against the target string length, and pushes exactly one additional character into the buffer.
- Cursor Blinking: A span element styled with
animate-blinkexists at the end of the text node while typing. Oncedoneis true, the cursor hides gracefully, handing focus to the next element.
A new, premium addition to the end of the user experience. The growing Heart Tree serves as an emotional crescendo at the very bottom of the website.
Code Breakdown:
- Sequential SVG Drawing: Standard SVGs paint instantly. We want the tree to "grow" organically out of the ground. We use
stroke-dasharrayandstroke-dashoffset.- By setting
stroke-dasharrayequal to the total path length, we can completely hide the stroke by settingstroke-dashoffsetto that same length. - A CSS transition reduces
stroke-dashoffsetto0over 1.5 seconds, creating a beautiful drawing effect.
- By setting
- Staging:
Stage 0: Seed/Base.Stage 1: Main thick branches grow.Stage 2: Secondary, thinner branches sprout from the main lines.Stage 3: Heart SVG paths (leaves) translate and scale up securely at branch nodes.Stage 4: A radial CSS gradient overlay fades in, giving the entire tree a mystical "bloom" effect alongside floatingTreeSparksparticles.
The primary dashboard that users explore after the intro completes.
Code Breakdown:
- Hero Stagger: Features a large, centered hero section that fades up on mount. Uses the
TypeWriterto write out the personalizedBIRTHDAY_NAME. - Particle System Integration: Implements both
Confetti.tsxandBalloons.tsx. - Message Card Styling: A meticulously crafted
divutilizingbackdrop-blur-lg(glassmorphism) and a complex dual-layer box-shadow (boxShadow: "0 0 60px hsl(330, 85%, 60%, 0.15)") to create a glowing neon effect against a dark background. - Responsive Typographic Guard: Heavy emphasis on
break-wordsandoverflow-hidden. As the TypeWriter injects strings into the DOM, it forces browser reflows; strict bounds ensure the layout does not jitter or expand horizontally on mobile screens. We lockmin-heightglobally for paragraphs holding TypeWriter instances.
Birthday Bloom is built to be customized using pure Environment Variables (Configuration Engine) and directly modifying assets. You do not need deep React knowledge to make this your own.
- Navigate to
/public/assets/birthday/. - Replace the background images (
birthday-cute.png,birthday-gold.png, etc.) with your own. Ensure they are optimized (WebP format recommended) and less than 500kb each to eliminate load stutter. High resolution images will delay the splash screen logic! - Replace
/public/assets/photo-1.jpg,photo-2.jpg, andphoto-3.jpgwith actual photos of the person. Maintain aspect ratios if possible, or useobject-covertailwind classes if you inject custom resolutions.
If the intro is too slow or too fast:
- Open
src/components/birthday/CinematicIntro.tsx. - Find the timer multipliers (e.g.,
i * 5000mapping over thestoryLines). - Reduce
5000to3500to speed up the pacing between storytelling lines. - Modify the
TypeWriterspeed props tospeed={30}for extremely fast typing, orspeed={120}for dramatic, slow typing.
The entire initialization process is controlled securely via the .env paradigm. If you configure these variables, the website will bypass the setup wizard and immediately start the cinematic experience for the birthday person.
| Variable Name | Required | Default Value | Description |
|---|---|---|---|
VITE_BIRTHDAY_NAME |
YES | "" |
The primary name of the person you are celebrating. Setting this automatically skips the config wizard. |
VITE_BIRTHDAY_AGE |
NO | null |
The age they are turning. |
VITE_BIRTHDAY_GENDER |
NO | "other" |
"male", "female", or "other". |
VITE_BIRTHDAY_DATE |
NO | null |
The specific date of the birthday. |
VITE_BIRTHDAY_RELATIONSHIP |
NO | "partner" |
Options: "partner", "friend", "family". This fundamentally changes the UI mood, colors, storytelling text, and emoji effects! |
VITE_BIRTHDAY_WISHER_NAME |
NO | "" |
The birthday wish sender's name, shown at the end of the emotional letter. |
VITE_BIRTHDAY_COLOR / VITE_FAVORITE_COLOR |
NO | "#FF6B6B" |
A hex code defining the dynamic global theme, neon glows, and gradient backgrounds. |
VITE_BIRTHDAY_INTERESTS / VITE_FAVORITE_ITEMS |
NO | "" |
Comma-separated list of interests/items to customize ambient particles. |
VITE_BIRTHDAY_LETTER_TITLE |
NO | "" |
Optional heading for the emotional letter card. |
VITE_BIRTHDAY_LETTER_OVERRIDE |
NO | "" |
Replace the generated letter body with your own multi-line letter. |
VITE_BIRTHDAY_CUSTOM_MESSAGE / VITE_CUSTOM_MESSAGE |
NO | "" |
A heartfelt, custom message to reveal with kinetic typography right before the grand cake reveal. |
VITE_SOUND_URL / VITE_BGM_URL |
NO | "" |
The background music audio URL. |
VITE_SOUND_EFFECTS |
NO | true |
Enable or disable SFX audio feedback. |
VITE_VIDEO_1, VITE_VIDEO_2, VITE_VIDEO_3 |
NO | "" |
Adds video links (YouTube or MP4) to the final cinematic Video Gallery at the bottom of the page. |
VITE_PASSWORD_REQUIRED |
NO | false |
Force enables the password lock page. |
VITE_PASSWORD |
NO | "" |
Manual password override (e.g. love or 1234). |
VITE_PASSWORD_HINT |
NO | "" |
Customized emotional hint displayed if the user gets stuck. |
VITE_PASSWORD_FORMAT |
NO | "MMDD" |
Format to auto-generate password from VITE_BIRTHDAY_DATE if VITE_PASSWORD is not set (e.g., MMDD, DDMM). |
How to set this up locally:
In the root of your project, create a file named .env. Add the following:
VITE_BIRTHDAY_NAME="Riya"
VITE_BIRTHDAY_AGE="25"
VITE_BIRTHDAY_GENDER="female"
VITE_BIRTHDAY_DATE="2026-10-15"
VITE_BIRTHDAY_RELATIONSHIP="partner"
VITE_BIRTHDAY_WISHER_NAME="Alex"
VITE_FAVORITE_COLOR="#00C2FF"
VITE_FAVORITE_ITEMS="coffee, stars, music"
VITE_CUSTOM_MESSAGE="You mean the universe to me."
VITE_VIDEO_1="https://www.youtube.com/watch?v=dQw4w9WgXcQ"To deploy this project to the world for free:
- Push this code to a private or public GitHub repository.
- Log into Vercel and click Add New -> Project.
- Import your GitHub repository.
- Open the Environment Variables section in the deployment settings.
- Add the keys exactly as shown above (
VITE_BIRTHDAY_NAME,VITE_BIRTHDAY_RELATIONSHIP, etc.) and provide the values. - Click Deploy! When the birthday person opens the Vercel link, it will launch their highly customized, surprise experience seamlessly without asking them for setup details.
For developers wanting to run this locally, clone, and fork:
- Node.js
v18.0.0or higher - npm
v9.0.0or higher - Git
- Clone the repository:
git clone https://github.com/naborajs/birthday-bloom.git cd birthday-bloom - Install local dependencies:
npm install
- Environment Setup:
cp .env.example .env # Edit .env with your favorite text editor - Boot the Dev Server:
The server will boot on
npm run dev
http://localhost:5173. Any changes to thesrcfolder will trigger an instant Hot-Module-Replacement (HMR) reload in the browser without losing application state.
This section provides a technical breakdown of every major component in the engine.
| Prop | Type | Default | Description |
|---|---|---|---|
text |
string |
required | The sentence to type out. |
speed |
number |
45 |
Speed in milliseconds between keystrokes. |
delay |
number |
0 |
Delay in milliseconds before typing begins. |
cursor |
boolean |
true |
Whether to show the blinking cursor. |
onComplete |
() => void |
undefined |
Callback fired when typing ends. |
className |
string |
"" |
Custom Tailwind classes for the text container. |
| Prop | Type | Default | Description |
|---|---|---|---|
delay |
number |
1000 |
Minimum delay before the trunk begins to grow. |
color |
string |
primary |
The color of the hearts (defaults to config). |
- Internal Logic: Uses a 4-phase state machine (
select->wish->cut->quotes). - SVG Structure: 100% vector-based, responsive to all screen sizes.
- Haptics: Triggers
navigator.vibrateduring the "burst" phase.
- Auto-Advance: Slides change every 6 seconds by default.
- 3D Tilt: Follows mouse position using Framer Motion
useMotionValue. - Lightbox: Uses
AnimatePresencefor a cinematic blur transition.
| Prop | Type | Default | Description |
|---|---|---|---|
onComplete |
() => void |
required | Triggered when the final scene finishes. |
speedMultiplier |
number |
1.0 |
Global multiplier for all scene timings. |
Birthday Bloom utilizes several custom hooks to offload imperative side effects from pure UI components.
Our central state manager built with Zustand.
config: The fullBirthdayConfigobject hydrated from ENV.getMood(): Returns'romantic' | 'energetic' | 'warm'based on relationship.getAnimationPacing(): Returns'slow' | 'fast' | 'moderate'.
Injects HSL variables into the :root element.
- Automatically calculates hover states and glow colors.
- Syncs the browser's
theme-colormeta tag with the user's favorite color.
A robust hook that wraps canvas-confetti.
fireConfetti(config): Triggers a localized burst with custom spread arrays.fireCannon(): Triggers a massive, multi-directional burst utilized primarily for the Cake Cutting finale.fireStars(): Interjects an SVG star-polygon shape into the physics engine for premium emotional moments.
Handles HTML5 Audio instances without cluttering the DOM with invisible <audio> tags.
- Provides
playWhoosh(),playType(),playBoom()closures. - Respects the
.envVITE_ALLOW_AUDIOboolean automatically.
- Client-Side Safety: All
VITE_variables are public. Do not store sensitive passwords in the environment variables. - Input Sanitization: The name and message fields are sanitized before being injected into the DOM to prevent basic XSS attempts.
- Audio Permissions: We respect browser autoplay policies by requiring a "Splash" interaction; audio is never forced without user consent.
Q: The website shows a blank screen on load?
A: Check your browser console. It's likely a missing .env variable or a typo in VITE_BIRTHDAY_NAME. Ensure you have run npm install.
Q: The animation stopped in the middle!
A: This happens if a timer is cleared incorrectly. Ensure you haven't modified the timersRef logic in CinematicIntro.tsx. Check for VITE_BIRTHDAY_DATE formatting errors.
Q: Audio isn't playing on my iPhone? A: iOS requires a "user gesture" to play sound. Ensure you clicked the "Start" button on the Splash Screen.
Q: How do I change the font?
A: Import your Google Font in index.css and update the --font-display variable.
Q: The text is too long and overlaps!
A: Use the VITE_BIRTHDAY_CUSTOM_MESSAGE for long messages. The VITE_BIRTHDAY_NAME should be kept under 15 characters for best results.
Q: Can I add more than 3 photos?
A: Yes, but you must update the photos array in PhotoGallery.tsx and add corresponding VITE_PHOTO_X variables to the store.
Q: How do I deploy to GitHub Pages?
A: Use the gh-pages package or a GitHub Action. Note that client-side routing may require a 404.html redirect hack.
Q: Vercel build failed?
A: Ensure your Node version is 18+. Check for case-sensitive file imports (e.g., Component.tsx vs component.tsx).
Q: How do I remove the "Naboraj Sarkar" branding?
A: You are free to modify the footer in MainBirthday.tsx, but keeping a small "Powered by Birthday Bloom" is appreciated!
Despite the visual complexity, this repository maintains an incredibly lightweight footprint.
- No Heavy Physics Libraries: Rather than including
matter.jsorthree.jswhich parse 500kb-1MB of JS memory chunks, we userequestAnimationFramehooks and native CSS for sparkles, balloons, and typing. - SVG Over Images: The Interactive Cake and Heart Tree are 100% vector SVG geometries.
- GPU Offloading: Animations (
translate3d) utilize hardware acceleration, shifting work from the CPU to the GPU rendering pipeline. This secures 60 frames per second on both desktop and mobile iOS/Android browsers. - Lighthouse Goals:
- LCP (Largest Contentful Paint): < 1.2s
- FID (First Input Delay): < 100ms
- CLS (Cumulative Layout Shift): 0.00
The diagram below shows the high-level responsibilities of the primary directories:
graph TD
Root[src directory] --> Components[birthday components]
Root --> Features[features directory]
Root --> Pages[pages directory]
Root --> Config[config directory]
Components -->|Renders| Actors[Interactive Actors]
Features -->|Manages| Back[State and Theme Engine]
Pages -->|Controls| Entry[Index Entry and NotFound]
Config -->|Resolves| ENV[Personalization Fallbacks]
Figure: High-level directory structure and core responsibilities.
Balloons.tsx: Floating SVG background balloons with random drift velocity.CakeCutting.tsx: Interactive birthday cake (handles candle extinguishing, layered SVG splitting, and quotes).CinematicIntro.tsx: Sequence orchestrator running the introduction scene state machine.FakeChatScene.tsx: Simulates the typing and bubbles of the fake messaging interface.FloatingElements.tsx: Manages the floating background particles and dust effects.HeartProgression.tsx: Visual heart tracker showing interaction progress.HeartTree.tsx: Sprouts and draws the growing branches and heart leaves using SVG stroke offsets.MainBirthday.tsx: Main landing view hosting the birthday message and interactive components.PhotoGallery.tsx: Polaroid photo gallery with dynamic 3D tilt effects.Sparkles.tsx: Controls individual sparkle particle emission.TypeWriter.tsx: Typographic component that types strings character-by-character recursively.
cinematic-story: Animation variants and layout details for the intro text sequences.core: Global store (useBirthdayStore), theme loaders (useDynamicTheme), and global utilities.
Index.tsx: Directs routing by rendering either the Splash screen, Cinematic Intro, or Main Dashboard.NotFound.tsx: Custom 404 page for route handling.
For our users in India and Bangladesh, we have provided native language setup guides to make your journey smoother.
If you encounter any specific issues with sound, animations, or deployment, please refer to our master troubleshooting suite:
Vercel is the native home for Vite projects.
- Push to GitHub.
- Link repo.
- Environment Variables: Add all
VITE_keys. - Build Settings:
npm run build,distdirectory.
Similar to Vercel, but ensure you add a _redirects file if you use React Router.
For those who want to host it on their own VPS.
FROM node:18-alpine AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build
FROM nginx:stable-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]SVG is the heart of Birthday Bloom. Unlike raster images (JPEG/PNG), SVGs are code-based, which allows us to animate them with mathematical precision.
We use this for the Heart Tree. By setting stroke-dasharray and stroke-dashoffset to the total length of the path, we can "draw" the tree in real-time.
@keyframes draw {
to { stroke-dashoffset: 0; }
}The 3D Cake isn't just flat shapes. We use <feDropShadow> and <feGaussianBlur> filters inside the SVG <defs> to create dynamic lighting. When you "blow" the candles, the light source shifts, changing the shadows on the cake layers.
While not used extensively yet, our engine supports path morphing. You can transform a circle into a heart by animating the d attribute using Framer Motion.
| Feature | Birthday Bloom | Generic Templates |
|---|---|---|
| Performance | 60fps (GPU Accelerated) | Laggy (CPU intensive) |
| Customization | Zero-Config (.env) | Manual Code Edits |
| 3D Effects | Interactive & Tilting | Static Images |
| Narrative | Finite State Machine | Single Scroll Page |
| Branding | Naboraj Sarkar Premium | Generic / Watermarked |
This project is a labor of love. We would like to thank:
- The Naboraj Sarkar Community: For testing early alphas and providing feedback on the 3D physics.
- Vite Team: For making development feel like magic.
- Framer Motion Team: For giving us the power of physics in the browser.
- Every Developer: Who has ever sent a digital birthday card.
For large-scale deployments or enterprise-level birthday surprises (yes, they exist), we support full containerization.
Our Docker image is optimized using a multi-stage build to keep the footprint under 50MB.
# Stage 1: Build
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Serve
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]If you are deploying this for a celebrity or a high-traffic event, use this manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: birthday-bloom
spec:
replicas: 3
selector:
matchLabels:
app: birthday-bloom
template:
metadata:
labels:
app: birthday-bloom
spec:
containers:
- name: birthday-bloom
image: naborajs/birthday-bloom:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: birthday-bloom-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: birthday-bloom
Launch your cinematic birthday surprise with env-driven configuration and a modern deployment workflow.
We welcome contributions of all types. If you find a bug, want to suggest features, improve documentation, or refine styles, please feel free to open an issue or submit a pull request. We thank everyone who uses, stars, or contributes to this repository.
Birthday Bloom welcomes contributions of all kinds — bug fixes, documentation improvements, UI polish, accessibility enhancements, performance optimizations, and new features.
We have created two animated walkthrough guides to help you contribute to Birthday Bloom:
🤝 Watch the Official Contributing Guide
Learn how to contribute to Birthday Bloom, whether you're a first-time open-source contributor or an experienced developer. This guide covers GitHub Issues, feature requests, bug reports, forking the repository, creating branches, making meaningful commits, submitting Pull Requests, the code review process, and open-source best practices to help you become a successful contributor.
📚 Watch the Complete Contributor Guide
Learn how to contribute to Birthday Bloom from start to finish. This step-by-step guide covers GitHub Issues, feature requests, bug reporting, forking the repository, cloning the project, creating branches, writing meaningful commit messages, opening Pull Requests, the review process, and open-source best practices. Whether you're making your first contribution or you're an experienced developer, this guide will help you confidently contribute to the project.
- Read CONTRIBUTING.md for the full workflow
- Read styleguide.md for code conventions
- Read architecture.md to understand the codebase
- Check good first issues for beginner-friendly tasks
- Fork, branch, commit, push, and PR — see the PR template
- 🐛 Bug fixes — Report and fix issues
- 📖 Documentation — Improve guides, fix typos, add examples
- ✨ UI & Animations — Polish the cinematic experience
- ♿ Accessibility — Make Birthday Bloom work for everyone
- ⚡ Performance — Keep it smooth on all devices
- 💡 Features — Extend existing systems, don't duplicate them
All contributors are expected to follow our CODE_OF_CONDUCT.md. Please be respectful, inclusive, and constructive.
- React.js Team
- Framer Motion
- Tailwind CSS
- Vite
- Canvas-Confetti
- All the open-source contributors who have made this project possible.
This project is licensed under the MIT License. You are completely free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software with adequate attribution. Commercial use is permitted, though providing credit and starring the repository is deeply appreciated! See the LICENSE file for more details.
We believe that code is a gift. That's why we made Birthday Bloom open-source and free for everyone. If you've used this to make someone happy, consider "paying it forward" by contributing a new feature or helping another developer in the community.
- Write a blog post or share how you used Birthday Bloom.
- Record a guide or tutorial to help other users.
- Donate to open-source libraries that we depend on (like Framer Motion).
Birthday Bloom comes with a complete open-source operating system to make contributing, maintaining, and collaborating easy.
- Issue Templates — Structured forms for bugs, features, docs improvements, and performance reports
- PR Template — Contributor checklist to ensure quality
- CI Pipeline — Automated lint, typecheck, build, and test on every PR
- Dependabot — Weekly automated dependency updates
- CODEOWNERS — Clear ownership map for the repository
See CHANGELOG.md for the full version history.
This project follows Semantic Versioning. Major releases are tracked in releases and summarized in the changelog.
Birthday Bloom is more than code. It's a bridge between technology and human emotion. Whether you're a developer looking for a cool project or a friend looking to make a surprise, we hope this engine serves you well.
- Star the Repo: Help us reach the top of GitHub Trending!
- Share your Story: Use
#BirthdayBloomon social media. - Contribute: We welcome all PRs.
Birthday Bloom was created and is maintained by Naboraj Sarkar. If you find this project useful or want to support future work, feel free to connect via the contact channels below.
Developed by Naboraj Sarkar. Contributions and improvements are welcome.
Need help, collab, or just want to connect? 👇
- 📧 Email → nishant.ns.business@gmail.com
- 💬 WhatsApp → Message Me now
- 💬 Telegram → @Nishantsarkar10k
- 🐦 Twitter (X) → @NSGAMMING699
- 📸 Instagram → @naborajs
- 🌐 Website → naborajs.com
- 📧 Support / Business → nishant.ns.business@gmail.com
- 🐙 GitHub → [github.com/naborajs]
- 🎥 YouTube → Naboraj Sarkar Channel
- 🚀 Report Issue → Open GitHub Issue
- 💡 Suggest Feature → Create Request
- ⭐ Support Project → Star this repo





