├── img ├── abhika.jpg ├── afsify.png ├── favicon.png ├── profile.jpg ├── ballon3.svg ├── ballon1.svg ├── ballon2.svg └── hat.svg ├── music └── hbd.mpeg ├── README.md ├── style └── main.css ├── index.html └── script └── main.js /img/abhika.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afsify/happy-birthday/HEAD/img/abhika.jpg -------------------------------------------------------------------------------- /img/afsify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afsify/happy-birthday/HEAD/img/afsify.png -------------------------------------------------------------------------------- /img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afsify/happy-birthday/HEAD/img/favicon.png -------------------------------------------------------------------------------- /img/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afsify/happy-birthday/HEAD/img/profile.jpg -------------------------------------------------------------------------------- /music/hbd.mpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afsify/happy-birthday/HEAD/music/hbd.mpeg -------------------------------------------------------------------------------- /img/ballon3.svg: -------------------------------------------------------------------------------- 1 | happy birthday -------------------------------------------------------------------------------- /img/ballon1.svg: -------------------------------------------------------------------------------- 1 | happy birthday -------------------------------------------------------------------------------- /img/ballon2.svg: -------------------------------------------------------------------------------- 1 | happy birthday -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Birthday Wishes Generator 2 | 3 | Create personalized birthday wishes with style and ease! This project allows you to create and deploy a beautifully designed webpage to celebrate someone special. 4 | 5 | ## Features 6 | 7 | - **Customizable Greetings:** Personalize birthday messages with names, photos, and themes. 8 | - **Responsive Design:** Looks perfect on any device, from desktops to smartphones. 9 | - **Quick Deployment:** Share the joy by hosting it online effortlessly. 10 | - **Animated Elements:** Add a touch of magic with interactive and animated designs. 11 | 12 | ## How to Use 13 | 14 | 1. **Clone the Repository** 15 | 16 | ```bash 17 | # Clone this repository 18 | $ git clone https://github.com/afsify/happy-birthday 19 | 20 | # Navigate to the project directory 21 | $ cd birthday-wishes-generator 22 | 23 | # Open the project in your text editor 24 | $ code . 25 | ``` 26 | 27 | 2. **Start the Local Server** 28 | 29 | Use any local server setup, such as Live Server in VS Code, to view the project in your browser. 30 | 31 | 3. **Customize the Greetings** 32 | 33 | - Update the `img` folder to include your custom images. 34 | - Modify the `index.html` file for layout adjustments. 35 | 36 | 4. **Deploy Online** 37 | 38 | - Enable GitHub Pages in the repository settings. 39 | - Alternatively, deploy using [Netlify](https://www.netlify.com/) or [Vercel](https://vercel.com/). 40 | 41 | ## Live Demo 42 | 43 | Check out the demo: [https://afsify.github.io/happy-birthday](https://afsify.github.io/happy-birthday) 44 | 45 | ## Technologies Used 46 | 47 | - **HTML5**: Markup for structure 48 | - **CSS3**: Styling and animations 49 | - **JavaScript**: Interactive features 50 | 51 | ## Contributing 52 | 53 | Contributions are welcome! If you have ideas to improve this project, feel free to: 54 | 55 | - Open a new issue 56 | - Submit a pull request 57 | 58 | Let’s make birthdays even more special together! 🎉 59 | -------------------------------------------------------------------------------- /style/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | font-family: "Poppins", sans-serif; 7 | margin: 0; 8 | } 9 | 10 | .song { 11 | visibility: hidden; 12 | } 13 | 14 | .container { 15 | height: 100vh; 16 | margin: 0 auto; 17 | overflow: hidden; 18 | position: relative; 19 | text-align: center; 20 | visibility: hidden; 21 | width: 100vw; 22 | } 23 | 24 | .container > div { 25 | left: 0; 26 | position: absolute; 27 | right: 0; 28 | top: 20vh; 29 | } 30 | 31 | .one { 32 | font-size: 4.5rem; 33 | } 34 | 35 | .two { 36 | font-size: 1.2rem; 37 | font-weight: lighter; 38 | } 39 | 40 | .three { 41 | font-size: 3rem; 42 | } 43 | 44 | .birthday-info { 45 | font-size: 1.5rem; 46 | font-weight: bold; 47 | color: #007bff; 48 | margin-top: 20px; 49 | } 50 | 51 | .date-container span, 52 | .age-container span { 53 | display: inline-block; 54 | font-size: 2rem; 55 | margin: 0 5px; 56 | animation: fadeIn 0.5s ease-in-out; 57 | } 58 | 59 | @keyframes fadeIn { 60 | from { 61 | opacity: 0; 62 | transform: scale(0.9); 63 | } 64 | to { 65 | opacity: 1; 66 | transform: scale(1); 67 | } 68 | } 69 | 70 | .age-container { 71 | margin-top: 10px; 72 | font-size: 1.8rem; 73 | } 74 | 75 | .date-container span { 76 | transition: all 0.3s ease; 77 | } 78 | 79 | .four .text-box { 80 | border: 3px solid #aaa; 81 | border-radius: 5px; 82 | margin: 0 auto; 83 | padding: 10px; 84 | position: relative; 85 | width: 600px; 86 | } 87 | 88 | .four { 89 | width: 100%; 90 | max-width: 600px; 91 | margin: 20px auto; 92 | color: #333; 93 | } 94 | 95 | .profile { 96 | display: flex; 97 | align-items: center; 98 | margin-bottom: 15px; 99 | } 100 | 101 | .profile-image { 102 | width: 60px; 103 | height: 60px; 104 | border-radius: 50%; 105 | object-fit: cover; 106 | margin-right: 10px; 107 | } 108 | 109 | .profile-name { 110 | font-size: 1.5rem; 111 | font-weight: bold; 112 | color: #333; 113 | } 114 | 115 | .text-box p { 116 | margin: 0; 117 | text-align: left; 118 | } 119 | 120 | .text-box span { 121 | visibility: hidden; 122 | } 123 | 124 | .text-box .fake-btn { 125 | background-color: rgb(21, 161, 237); 126 | border-radius: 3px; 127 | bottom: -50px; 128 | color: #fff; 129 | padding: 0.5rem 1rem; 130 | position: absolute; 131 | right: 5px; 132 | } 133 | 134 | .five p { 135 | font-size: 2rem; 136 | left: 0; 137 | position: absolute; 138 | right: 0; 139 | } 140 | 141 | .idea-3 strong { 142 | border-radius: 3px; 143 | display: inline-block; 144 | padding: 3px 5px; 145 | } 146 | 147 | .five .idea-5 { 148 | font-size: 4rem; 149 | } 150 | 151 | .idea-5 span, 152 | .idea-6 span, 153 | .wish-hbd span { 154 | display: inline-block; 155 | } 156 | 157 | .idea-6 span { 158 | font-size: 15rem; 159 | } 160 | 161 | .six { 162 | position: relative; 163 | top: 10vh; 164 | z-index: 1; 165 | } 166 | 167 | .six img { 168 | display: inline-block; 169 | height: 350px; 170 | max-width: 100%; 171 | /* height: auto; */ 172 | } 173 | 174 | .six .hat { 175 | left: 41.5%; 176 | position: absolute; 177 | /* transform: scale(0.1); */ 178 | top: -35%; 179 | width: 80px; 180 | } 181 | 182 | .baloons img { 183 | display: inline-block; 184 | position: absolute; 185 | } 186 | 187 | .baloons img:nth-child(even) { 188 | left: -10%; 189 | } 190 | 191 | .baloons img:nth-child(odd) { 192 | right: -10%; 193 | } 194 | 195 | .baloons img:nth-child(3n + 0) { 196 | left: 30%; 197 | } 198 | 199 | .seven, 200 | .eight { 201 | height: 100vh; 202 | position: fixed; 203 | top: 0; 204 | width: 100vw; 205 | } 206 | 207 | .eight svg { 208 | left: 0; 209 | position: absolute; 210 | top: 0; 211 | visibility: hidden; 212 | width: 25px; 213 | z-index: -1; 214 | } 215 | 216 | .eight svg:nth-child(1) { 217 | fill: #bd6ecf; 218 | left: 5vw; 219 | top: 7vh; 220 | } 221 | 222 | .eight svg:nth-child(2) { 223 | fill: #7dd175; 224 | left: 35vw; 225 | top: 23vh; 226 | } 227 | 228 | .eight svg:nth-child(3) { 229 | fill: #349d8b; 230 | left: 23vw; 231 | top: 33vh; 232 | } 233 | 234 | .eight svg:nth-child(4) { 235 | fill: #347a9d; 236 | left: 57vw; 237 | top: 43vh; 238 | } 239 | 240 | .eight svg:nth-child(5) { 241 | fill: #c66053; 242 | left: 7vw; 243 | top: 68vh; 244 | } 245 | 246 | .eight svg:nth-child(6) { 247 | fill: #bfaa40; 248 | left: 77vw; 249 | top: 42vh; 250 | } 251 | 252 | .eight svg:nth-child(7) { 253 | fill: #e3bae8; 254 | left: 83vw; 255 | top: 68vh; 256 | } 257 | 258 | .eight svg:nth-child(8) { 259 | fill: #8762cb; 260 | left: 37vw; 261 | top: 86vh; 262 | } 263 | 264 | .eight svg:nth-child(9) { 265 | fill: #9a90da; 266 | left: 87vw; 267 | top: 94vh; 268 | } 269 | 270 | .wish-hbd { 271 | font-size: 3em; 272 | margin: 0; 273 | text-transform: uppercase; 274 | } 275 | 276 | .wish h5 { 277 | font-size: 2rem; 278 | font-weight: lighter; 279 | margin: 10px 0 0; 280 | } 281 | 282 | .nine p { 283 | font-size: 2rem; 284 | font-weight: lighter; 285 | } 286 | 287 | #replay { 288 | cursor: pointer; 289 | z-index: 3; 290 | } 291 | 292 | /* Media Queries */ 293 | @media screen and (max-height: 1000px) { 294 | .six .hat { 295 | left: 40%; 296 | } 297 | } 298 | 299 | @media screen and (max-height: 800px) { 300 | .six .hat { 301 | left: 37%; 302 | } 303 | } 304 | 305 | @media screen and (max-height: 700px) { 306 | .six .hat { 307 | left: 32%; 308 | } 309 | } 310 | 311 | @media screen and (max-height: 850px) and (max-width: 450px) { 312 | .six .hat { 313 | left: 32%; 314 | } 315 | } 316 | 317 | @media screen and (max-width: 500px) { 318 | .container { 319 | width: 90%; 320 | } 321 | 322 | .four .text-box { 323 | width: 90%; 324 | } 325 | 326 | .text-box .fake-btn { 327 | bottom: -38px; 328 | right: 5px; 329 | } 330 | 331 | .idea-5 span { 332 | display: block; 333 | } 334 | 335 | .idea-6 span { 336 | font-size: 10rem; 337 | } 338 | 339 | .six .hat { 340 | /* top: -20px; */ 341 | width: 50px; 342 | } 343 | 344 | .wish-hbd { 345 | font-size: 2.2em; 346 | } 347 | 348 | .wish h5 { 349 | font-size: 1.4rem; 350 | } 351 | 352 | .nine p { 353 | font-size: 1.5rem; 354 | font-weight: lighter; 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Happy Birthday!!! :) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 |
29 |
30 |

31 | Hi 32 | Abhika 33 |

34 |

I really like your name btw, but I’ll always love calling you Abhibee!

35 |
36 | 37 |
38 |

It's your birthday!! :D

39 |
40 |
41 | 1 January 2001 42 |
43 |
44 |

🎂0 Years

45 |
46 |
47 |
48 | 49 |
50 |
51 | Profile Picture 52 |

Abhibee 💚

53 |
54 |
55 |

56 | Happy Birthday to the most beautiful soul who lights up my world! 🌹✨ Every moment with you feels like a celebration, but today is extra special because it's all about you. I’m so grateful for your love, your smile, and the endless joy you bring into my life. 57 |

58 |

Send

59 |
60 |
61 | 62 |
63 |

That's what I was going to do.

64 |

But then I stopped.

65 |

66 | I realised, I wanted to do something
67 | special 68 | . 69 |

70 |

Because,

71 |

72 | You are Special 73 | :) 74 |

75 |

76 | S 77 | O 78 |

79 |
80 | 81 |
82 | profile 83 | hat 84 |
85 |

Happy Birthday!

86 |
You’re the {code} that keeps my heart running! ;)
87 |
88 |
89 | 90 |
91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 |
127 | 128 |
129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
157 | 158 |
159 |

Okay, now come back and tell me if you liked it.

160 |

Or click, if you want to watch it again.

161 |

With all my love, from your Afsify

162 |

:)

163 |
164 |
165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /script/main.js: -------------------------------------------------------------------------------- 1 | // trigger to play music in the background with sweetalert 2 | window.addEventListener("load", () => { 3 | Swal.fire({ 4 | title: "Do you want to play music in the background?", 5 | icon: "warning", 6 | showCancelButton: true, 7 | confirmButtonColor: "#3085d6", 8 | cancelButtonColor: "#d33", 9 | confirmButtonText: "Yes", 10 | cancelButtonText: "No", 11 | }).then((result) => { 12 | if (result.isConfirmed) { 13 | document.querySelector(".song").play(); 14 | animationTimeline(); 15 | } else { 16 | animationTimeline(); 17 | } 18 | }); 19 | }); 20 | 21 | document.addEventListener("DOMContentLoaded", function () { 22 | const dayElement = document.getElementById("day"); 23 | const monthElement = document.getElementById("month"); 24 | const yearElement = document.getElementById("year"); 25 | const ageElement = document.getElementById("age"); 26 | 27 | const months = [ 28 | "January", 29 | "February", 30 | "March", 31 | "April", 32 | "May", 33 | "June", 34 | "July", 35 | "August", 36 | "September", 37 | "October", 38 | "November", 39 | "December", 40 | ]; 41 | 42 | const targetDay = 7; 43 | const targetMonthIndex = 11; // December 44 | const targetYear = 2024; 45 | const birthYear = 2001; 46 | 47 | let currentDay = 1; 48 | let currentMonthIndex = 0; 49 | let currentYear = birthYear; 50 | let currentAge = 0; 51 | 52 | const interval = setInterval(() => { 53 | // Update day, month, year, and age in the DOM 54 | dayElement.textContent = currentDay; 55 | monthElement.textContent = months[currentMonthIndex]; 56 | yearElement.textContent = currentYear; 57 | ageElement.textContent = currentAge; 58 | 59 | // Smoothly increment day, month, year, and age 60 | if (currentDay < targetDay) { 61 | currentDay++; 62 | } else if (currentMonthIndex < targetMonthIndex) { 63 | currentDay = targetDay; // Fix day 64 | currentMonthIndex++; 65 | } else if (currentYear < targetYear) { 66 | currentMonthIndex = targetMonthIndex; // Fix month 67 | currentYear++; 68 | currentAge++; 69 | } else { 70 | // Stop animation when target is reached 71 | clearInterval(interval); 72 | } 73 | }, 250); // Smoother speed adjustment 74 | }); 75 | 76 | // animation timeline 77 | const animationTimeline = () => { 78 | // split chars that needs to be animated individually 79 | const textBoxChars = document.getElementsByClassName("hbd-chatbox")[0]; 80 | const hbd = document.getElementsByClassName("wish-hbd")[0]; 81 | 82 | textBoxChars.innerHTML = `${textBoxChars.innerHTML 83 | .split("") 84 | .join("")}`; 85 | 86 | hbd.innerHTML = `${hbd.innerHTML 87 | .split("") 88 | .join("")}`; 89 | 90 | const ideaTextTrans = { 91 | opacity: 0, 92 | y: -20, 93 | rotationX: 5, 94 | skewX: "15deg", 95 | }; 96 | 97 | const ideaTextTransLeave = { 98 | opacity: 0, 99 | y: 20, 100 | rotationY: 5, 101 | skewX: "-15deg", 102 | }; 103 | 104 | // timeline 105 | const tl = new TimelineMax(); 106 | 107 | tl.to(".container", 0.6, { 108 | visibility: "visible", 109 | }) 110 | .from(".one", 0.9, { 111 | opacity: 0, 112 | y: 10, 113 | }) 114 | .from(".two", 0.9, { 115 | opacity: 0, 116 | y: 10, 117 | }) 118 | .to( 119 | ".one", 120 | 0.7, 121 | { 122 | opacity: 0, 123 | y: 10, 124 | }, 125 | "+=3.5" 126 | ) 127 | .to( 128 | ".two", 129 | 0.7, 130 | { 131 | opacity: 0, 132 | y: 10, 133 | }, 134 | "-=1" 135 | ) 136 | .from(".three", 0.7, { 137 | opacity: 0, 138 | y: 10, 139 | }) 140 | .to( 141 | ".three", 142 | 0.7, 143 | { 144 | opacity: 0, 145 | y: 10, 146 | }, 147 | "+=3" 148 | ) 149 | .from(".four", 0.7, { 150 | scale: 0.2, 151 | opacity: 0, 152 | }) 153 | .from(".fake-btn", 0.3, { 154 | scale: 0.2, 155 | opacity: 0, 156 | }) 157 | .staggerTo( 158 | ".hbd-chatbox span", 159 | 1.5, 160 | { 161 | visibility: "visible", 162 | }, 163 | 0.05 164 | ) 165 | .to( 166 | ".fake-btn", 167 | 0.1, 168 | { 169 | backgroundColor: "rgb(127, 206, 248)", 170 | }, 171 | "+=4" 172 | ) 173 | .to( 174 | ".four", 175 | 0.5, 176 | { 177 | scale: 0.2, 178 | opacity: 0, 179 | y: -150, 180 | }, 181 | "+=1" 182 | ) 183 | .from(".idea-1", 0.7, ideaTextTrans) 184 | .to(".idea-1", 0.7, ideaTextTransLeave, "+=2.5") 185 | .from(".idea-2", 0.7, ideaTextTrans) 186 | .to(".idea-2", 0.7, ideaTextTransLeave, "+=2.5") 187 | .from(".idea-3", 0.7, ideaTextTrans) 188 | .to(".idea-3 strong", 0.5, { 189 | scale: 1.2, 190 | x: 10, 191 | backgroundColor: "rgb(21, 161, 237)", 192 | color: "#fff", 193 | }) 194 | .to(".idea-3", 0.7, ideaTextTransLeave, "+=2.5") 195 | .from(".idea-4", 0.7, ideaTextTrans) 196 | .to(".idea-4", 0.7, ideaTextTransLeave, "+=2.5") 197 | .from( 198 | ".idea-5", 199 | 0.7, 200 | { 201 | rotationX: 15, 202 | rotationZ: -10, 203 | skewY: "-5deg", 204 | y: 50, 205 | z: 10, 206 | opacity: 0, 207 | }, 208 | "+=1.5" 209 | ) 210 | .to( 211 | ".idea-5 span", 212 | 0.7, 213 | { 214 | rotation: 90, 215 | x: 8, 216 | }, 217 | "+=1.4" 218 | ) 219 | .to( 220 | ".idea-5", 221 | 0.7, 222 | { 223 | scale: 0.2, 224 | opacity: 0, 225 | }, 226 | "+=2" 227 | ) 228 | .staggerFrom( 229 | ".idea-6 span", 230 | 0.8, 231 | { 232 | scale: 3, 233 | opacity: 0, 234 | rotation: 15, 235 | ease: Expo.easeOut, 236 | }, 237 | 0.2 238 | ) 239 | .staggerTo( 240 | ".idea-6 span", 241 | 0.8, 242 | { 243 | scale: 3, 244 | opacity: 0, 245 | rotation: -15, 246 | ease: Expo.easeOut, 247 | }, 248 | 0.2, 249 | "+=1.5" 250 | ) 251 | .staggerFromTo( 252 | ".baloons img", 253 | 2.5, 254 | { 255 | opacity: 0.9, 256 | y: 1400, 257 | }, 258 | { 259 | opacity: 1, 260 | y: -1000, 261 | }, 262 | 0.2 263 | ) 264 | .from( 265 | ".profile-picture", 266 | 0.5, 267 | { 268 | scale: 3.5, 269 | opacity: 0, 270 | x: 25, 271 | y: -25, 272 | rotationZ: -45, 273 | }, 274 | "-=2" 275 | ) 276 | .from(".hat", 0.5, { 277 | x: -100, 278 | y: 350, 279 | rotation: -180, 280 | opacity: 0, 281 | }) 282 | .staggerFrom( 283 | ".wish-hbd span", 284 | 0.7, 285 | { 286 | opacity: 0, 287 | y: -50, 288 | // scale: 0.3, 289 | rotation: 150, 290 | skewX: "30deg", 291 | ease: Elastic.easeOut.config(1, 0.5), 292 | }, 293 | 0.1 294 | ) 295 | .staggerFromTo( 296 | ".wish-hbd span", 297 | 0.7, 298 | { 299 | scale: 1.4, 300 | rotationY: 150, 301 | }, 302 | { 303 | scale: 1, 304 | rotationY: 0, 305 | color: "#ff69b4", 306 | ease: Expo.easeOut, 307 | }, 308 | 0.1, 309 | "party" 310 | ) 311 | .from( 312 | ".wish h5", 313 | 0.5, 314 | { 315 | opacity: 0, 316 | y: 10, 317 | skewX: "-15deg", 318 | }, 319 | "party" 320 | ) 321 | .staggerTo( 322 | ".eight svg", 323 | 1.5, 324 | { 325 | visibility: "visible", 326 | opacity: 0, 327 | scale: 80, 328 | repeat: 3, 329 | repeatDelay: 1.4, 330 | }, 331 | 0.3 332 | ) 333 | .to(".six", 0.5, { 334 | opacity: 0, 335 | y: 30, 336 | zIndex: "-1", 337 | }) 338 | .staggerFrom(".nine p", 1, ideaTextTrans, 1.2) 339 | .to( 340 | ".last-smile", 341 | 0.5, 342 | { 343 | rotation: 90, 344 | }, 345 | "+=1" 346 | ); 347 | 348 | // Restart Animation on click 349 | const replyBtn = document.getElementById("replay"); 350 | replyBtn.addEventListener("click", () => { 351 | tl.restart(); 352 | }); 353 | }; 354 | -------------------------------------------------------------------------------- /img/hat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 19 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 58 | 64 | 82 | 100 | 118 | 136 | 154 | 172 | 190 | 208 | 226 | 236 | 237 | 238 | --------------------------------------------------------------------------------