DEV Community

Vamsi Kocherlakota
Vamsi Kocherlakota

Posted on

🍜 “Steam & Soul — A Bowl Written in CSS” ⭐

<!DOCTYPE html>




Steam & Soul — A Bowl Written in CSS * { box-sizing: border-box; margin: 0; padding: 0; } :root { --wood1: #3b1710; --wood2: #71351f; --wood3: #a9572d; --red1: #43050c; --red2: #86101a; --red3: #d72b28; --broth1: #721006; --broth2: #c9330d; --broth3: #ff9228; --noodle1: #fff2ad; --noodle2: #ffd35c; --noodle3: #a95e1d; --gold: #ffbe42; } body { min-height: 100vh; overflow: hidden; display: grid; place-items: center; background: radial-gradient( circle at 50% 32%, #fffdf4 0%, #ffe9c7 28%, #e9a269 65%, #864029 100% ); font-family: Inter, Arial, sans-serif; } /* ===================================================== SCENE ===================================================== */ .scene { position: relative; width: 800px; height: 800px; perspective: 1100px; cursor: pointer; animation: floatingScene 7s ease-in-out infinite; } @keyframes floatingScene { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-5px); } } /* ===================================================== TITLE ===================================================== */ .title { position: absolute; top: 30px; left: 0; width: 100%; text-align: center; color: #641f12; font-size: 36px; font-weight: 950; letter-spacing: 10px; text-shadow: 2px 2px 0 #ffd99e, 0 8px 20px rgba(70,20,0,.15); z-index: 200; } .subtitle { position: absolute; top: 82px; width: 100%; text-align: center; color: #8b4a2d; font-size: 11px; font-weight: 700; letter-spacing: 5px; z-index: 200; } /* ===================================================== LIGHT ===================================================== */ .light { position: absolute; left: 50%; top: 170px; width: 550px; height: 420px; transform: translateX(-50%); background: radial-gradient( ellipse, rgba(255,220,150,.4), transparent 68% ); filter: blur(20px); animation: lightPulse 5s ease-in-out infinite; z-index: 0; } @keyframes lightPulse { 0%,100% { opacity: .55; } 50% { opacity: .9; } } /* ===================================================== TABLE ===================================================== */ .table { position: absolute; left: -100px; right: -100px; bottom: -40px; height: 280px; background: repeating-linear-gradient( 92deg, #572819 0 30px, #74351e 31px 60px, #4a2117 61px 92px, #8a4224 93px 120px ); border-top: 13px solid #37150e; box-shadow: inset 0 15px 30px rgba(255,180,100,.12), 0 -15px 35px rgba(40,5,0,.25); transform: perspective(800px) rotateX(9deg); z-index: 1; } .table::after { content: ""; position: absolute; inset: 25px; background: repeating-linear-gradient( 8deg, transparent 0 23px, rgba(30,8,2,.15) 24px 27px, transparent 28px 50px ); opacity: .7; } /* ===================================================== PLATE ===================================================== */ .plate-shadow { position: absolute; width: 610px; height: 110px; left: 50%; bottom: 145px; transform: translateX(-50%); border-radius: 50%; background: radial-gradient( ellipse, rgba(30,5,0,.48), rgba(30,5,0,.18) 45%, transparent 73% ); filter: blur(10px); z-index: 2; } .plate { position: absolute; width: 600px; height: 175px; left: 50%; bottom: 140px; transform: translateX(-50%); border-radius: 50%; background: radial-gradient( ellipse, #fffdf0 0%, #ead8b5 60%, #b28d69 100% ); box-shadow: 0 20px 25px rgba(50,10,0,.28), inset 0 -10px 16px rgba(80,35,10,.18); z-index: 3; } .plate::after { content: ""; position: absolute; inset: 22px 35px; border-radius: 50%; border: 3px solid rgba(130,65,25,.18); } /* ===================================================== BOWL ===================================================== */ .bowl { position: absolute; left: 50%; bottom: 180px; width: 525px; height: 345px; transform: translateX(-50%) rotateX(6deg); border-radius: 30px 30px 48% 48%; background: linear-gradient( 90deg, #40040b 0%, #700913 10%, #b81720 25%, #e03b2d 47%, #c01b22 67%, #710913 88%, #3b0409 100% ); box-shadow: inset 0 -40px 45px rgba(30,0,0,.55), inset 18px 0 28px rgba(255,100,70,.16), inset -22px 0 30px rgba(30,0,0,.35), 0 30px 30px rgba(40,7,0,.38); overflow: hidden; z-index: 10; } .bowl::before { content: ""; position: absolute; top: 25px; left: 50px; width: 90px; height: 245px; border-radius: 50%; background: linear-gradient( 90deg, transparent, rgba(255,200,160,.2), transparent ); transform: rotate(8deg); filter: blur(2px); } .bowl::after { content: ""; position: absolute; left: 45px; right: 45px; bottom: 55px; height: 7px; border-radius: 50%; background: var(--gold); box-shadow: 0 23px 0 rgba(255,190,66,.9), 0 46px 0 rgba(255,190,66,.3); z-index: 60; } /* ===================================================== SOUP ===================================================== */ .soup { position: absolute; left: 50%; top: -10px; width: 470px; height: 165px; transform: translateX(-50%); border-radius: 50%; background: radial-gradient( ellipse at 45% 38%, #ffad3c 0%, #f06b1d 27%, #bd3110 57%, #6d0e08 100% ); border: 12px solid #f3a82e; box-shadow: inset 0 12px 20px rgba(255,220,100,.3), inset 0 -15px 25px rgba(70,0,0,.35), 0 5px 10px rgba(40,5,0,.4); z-index: 20; } /* ===================================================== BROTH SHIMMER ===================================================== */ .shimmer { position: absolute; width: 170px; height: 35px; border-radius: 50%; background: linear-gradient( 100deg, transparent, rgba(255,240,170,.45), transparent ); filter: blur(3px); animation: shimmer 4s ease-in-out infinite; z-index: 70; } .shimmer1 { left: 80px; top: 45px; } .shimmer2 { left: 245px; top: 82px; animation-delay: 1.7s; } @keyframes shimmer { 0%,100% { transform: translateX(-25px); opacity: .25; } 50% { transform: translateX(35px); opacity: .8; } } /* ===================================================== NOODLES ===================================================== */ .noodle { position: absolute; height: 9px; border-radius: 50%; background: linear-gradient( 180deg, var(--noodle1), var(--noodle2) 55%, var(--noodle3) ); box-shadow: 0 2px 3px rgba(75,20,0,.5); z-index: 40; } .n1 { width: 285px; left: 40px; top: 54px; transform: rotate(4deg); } .n2 { width: 310px; left: 65px; top: 72px; transform: rotate(-7deg); } .n3 { width: 245px; left: 80px; top: 91px; transform: rotate(13deg); } .n4 { width: 230px; left: 145px; top: 42px; transform: rotate(-16deg); } .n5 { width: 270px; left: 125px; top: 80px; transform: rotate(19deg); } .n6 { width: 200px; left: 115px; top: 108px; transform: rotate(-6deg); } /* Curved noodles */ .curve { position: absolute; width: 105px; height: 32px; border: 8px solid var(--noodle2); border-left-color: transparent; border-radius: 50%; z-index: 42; } .curve1 { left: 50px; top: 45px; transform: rotate(-18deg); } .curve2 { right: 45px; top: 75px; transform: rotate(20deg); } .curve3 { left: 170px; top: 102px; transform: rotate(8deg); } /* ===================================================== EGG ===================================================== */ .egg { position: absolute; width: 110px; height: 125px; left: 65px; top: 4px; border-radius: 54% 46% 48% 52%; background: radial-gradient( ellipse at 38% 30%, #ffffff, #fff4d0 63%, #d9bc82 ); transform: rotate(-17deg); box-shadow: 0 5px 8px rgba(60,15,0,.4); z-index: 50; } .yolk { position: absolute; width: 55px; height: 55px; left: 28px; top: 35px; border-radius: 50%; background: radial-gradient( circle at 32% 27%, #ffe35c, #ff9d0a 55%, #cf5700 ); box-shadow: inset -7px -8px 10px rgba(150,50,0,.25), 0 3px 5px rgba(80,20,0,.35); } /* ===================================================== SEAWEED ===================================================== */ .seaweed { position: absolute; width: 40px; height: 92px; right: 145px; top: 25px; border-radius: 6px; background: repeating-linear-gradient( 90deg, #041c14 0 5px, #145436 6px 10px ); transform: rotate(12deg); box-shadow: 3px 4px 6px rgba(0,0,0,.4); z-index: 47; } /* ===================================================== NARUTO ===================================================== */ .naruto { position: absolute; width: 76px; height: 76px; right: 75px; top: 20px; border-radius: 50%; background: radial-gradient( circle, #fff8d8 0 57%, #df4930 58% 65%, #fff8d8 66% ); border: 5px solid #e55535; box-shadow: 0 4px 7px rgba(60,15,0,.35); z-index: 52; } .naruto::before { content: ""; position: absolute; left: 15px; top: 14px; width: 36px; height: 36px; border: 5px solid #d7442f; border-left-color: transparent; border-radius: 50%; transform: rotate(45deg); } /* ===================================================== MUSHROOM ===================================================== */ .mushroom { position: absolute; right: 115px; bottom: 8px; width: 82px; height: 60px; z-index: 50; } .mushroom-cap { position: absolute; width: 82px; height: 46px; border-radius: 50% 50% 35% 35%; background: radial-gradient( circle at 40% 25%, #f09a5d, #a94024 ); box-shadow: 0 4px 5px rgba(60,15,0,.3); } .mushroom-stem { position: absolute; width: 30px; height: 38px; left: 26px; top: 25px; border-radius: 20% 20% 40% 40%; background: linear-gradient( 90deg, #c48c5c, #fff0c9, #c18a59 ); } /* ===================================================== CORN ===================================================== */ .corn { position: absolute; width: 14px; height: 14px; border-radius: 50%; background: radial-gradient( circle at 35% 30%, #fff68c, #ffd23c 60%, #d88800 ); box-shadow: 1px 2px 3px rgba(80,30,0,.3); z-index: 55; } .c1 { left: 238px; top: 52px; } .c2 { left: 264px; top: 66px; } .c3 { left: 291px; top: 52px; } .c4 { left: 315px; top: 75px; } .c5 { left: 278px; top: 95px; } .c6 { left: 245px; top: 99px; } /* ===================================================== GREEN ONION ===================================================== */ .onion { position: absolute; width: 7px; height: 67px; border-radius: 10px; background: linear-gradient( 90deg, #236c32, #76d05b, #236c32 ); transform-origin: bottom; z-index: 57; } .o1 { left: 190px; top: 25px; transform: rotate(-30deg); } .o2 { left: 215px; top: 20px; transform: rotate(14deg); } .o3 { left: 235px; top: 29px; transform: rotate(36deg); } .o4 { left: 257px; top: 20px; transform: rotate(-10deg); } /* ===================================================== SESAME ===================================================== */ .sesame { position: absolute; width: 8px; height: 3px; border-radius: 50%; background: #fff3bd; transform: rotate(35deg); z-index: 60; } .s1 { left: 130px; top: 72px; } .s2 { left: 168px; top: 96px; } .s3 { left: 205px; top: 67px; } .s4 { left: 335px; top: 61px; } .s5 { left: 355px; top: 89px; } .s6 { left: 305px; top: 105px; } /* ===================================================== CHILI OIL ===================================================== */ .oil { position: absolute; width: 18px; height: 8px; border-radius: 50%; background: radial-gradient( circle, #ffbd35, #e43a0c ); box-shadow: 0 0 8px rgba(255,80,0,.45); animation: oilPulse 3.5s ease-in-out infinite; z-index: 65; } .oil1 { left: 95px; top: 108px; } .oil2 { left: 310px; top: 96px; animation-delay: 1s; } .oil3 { left: 220px; top: 43px; animation-delay: 2s; } @keyframes oilPulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.35); } } /* ===================================================== BOWL RIM ===================================================== */ .rim { position: absolute; left: 50%; top: -8px; width: 505px; height: 120px; transform: translateX(-50%); border: 10px solid #ffb537; border-radius: 50%; box-shadow: 0 3px 5px rgba(60,10,0,.35); z-index: 100; pointer-events: none; } /* ===================================================== BOWL PATTERN ===================================================== */ .pattern { position: absolute; left: 50%; bottom: 82px; width: 310px; transform: translateX(-50%); display: flex; justify-content: space-between; z-index: 90; opacity: .7; } .pattern span { width: 18px; height: 18px; border: 3px solid #ffc148; transform: rotate(45deg); } /* ===================================================== CHOPSTICKS ===================================================== */ .chopsticks { position: absolute; right: 105px; top: 115px; width: 250px; height: 470px; z-index: 150; transform: rotate(5deg); } .chopstick { position: absolute; width: 15px; height: 470px; border-radius: 10px; background: linear-gradient( 90deg, #461a10, #d08443 45%, #642719 ); box-shadow: 4px 6px 10px rgba(30,5,0,.4); transform-origin: bottom; } .cs1 { right: 75px; transform: rotate(29deg); } .cs2 { right: 117px; transform: rotate(37deg); } /* ===================================================== NOODLE FROM CHOPSTICKS ===================================================== */ .lifted { position: absolute; right: 195px; top: 275px; width: 240px; height: 260px; z-index: 145; transform: rotate(-8deg); } /* Multiple curved strands */ .lifted span { position: absolute; width: 210px; height: 150px; border-left: 9px solid var(--noodle2); border-bottom: 9px solid var(--noodle1); border-radius: 0 0 0 80%; filter: drop-shadow(0 3px 2px rgba(70,20,0,.45)); transform-origin: top left; } .lifted span:nth-child(1) { left: 0; top: 0; transform: rotate(8deg) skewY(-8deg); } .lifted span:nth-child(2) { left: 25px; top: 5px; transform: rotate(12deg) skewY(-10deg); } .lifted span:nth-child(3) { left: 50px; top: 12px; transform: rotate(16deg) skewY(-12deg); } /* Noodle ends */ .lifted span::after { content: ""; position: absolute; right: -8px; bottom: -8px; width: 15px; height: 15px; border-radius: 50%; background: #ffd66b; } /* ===================================================== STEAM ===================================================== */ .steam-glow { position: absolute; left: 50%; top: 145px; width: 470px; height: 280px; transform: translateX(-50%); background: radial-gradient( ellipse, rgba(255,255,255,.25), transparent 70% ); filter: blur(20px); z-index: 110; } .steam-container { position: absolute; left: 50%; top: 125px; width: 450px; height: 330px; transform: translateX(-50%); z-index: 120; pointer-events: none; } .steam { position: absolute; bottom: 0; width: 25px; height: 210px; border-left: 9px solid rgba(255,255,255,.6); border-radius: 50%; filter: blur(2px); opacity: 0; animation: steamRise 4.5s ease-in-out infinite; } .steam:nth-child(1) { left: 55px; } .steam:nth-child(2) { left: 145px; height: 250px; animation-delay: 1.1s; } .steam:nth-child(3) { left: 245px; height: 195px; animation-delay: 2s; } .steam:nth-child(4) { left: 330px; height: 235px; animation-delay: 2.8s; } @keyframes steamRise { 0% { opacity: 0; transform: translateY(30px) rotate(5deg) scale(.7); } 20% { opacity: .65; } 50% { opacity: .35; transform: translateY(-65px) rotate(-12deg) scale(1); } 80% { opacity: .18; } 100% { opacity: 0; transform: translateY(-190px) rotate(17deg) scale(1.3); } } /* ===================================================== INTERACTION ===================================================== */ .scene.active .steam { animation-duration: 2.1s; } .scene.active .lifted { animation: noodleLift 1.5s ease-in-out; } .scene.active .chopsticks { animation: chopMove 1.5s ease-in-out; } @keyframes noodleLift { 0%,100% { transform: rotate(-8deg) translateY(0); } 50% { transform: rotate(-3deg) translateY(-40px); } } @keyframes chopMove { 0%,100% { transform: rotate(5deg); } 50% { transform: rotate(1deg) translateY(-12px); } } /* ===================================================== BADGE ===================================================== */ .badge { position: absolute; left: 50%; bottom: 35px; transform: translateX(-50%); padding: 9px 20px; border-radius: 30px; background: rgba(255,244,216,.72); border: 1px solid rgba(100,40,15,.2); backdrop-filter: blur(8px); color: #71351f; font-size: 10px; font-weight: 800; letter-spacing: 3px; z-index: 200; } /* ===================================================== RESPONSIVE ===================================================== */ @media(max-width:850px) { .scene { transform: scale(.8); } } @media(max-width:650px) { .scene { transform: scale(.6); } } @media(max-height:720px) { .scene { transform: scale(.65); } } STEAM & SOUL A BOWL WRITTEN IN CSS CSS ART • MINIMAL JS • 100% HAND CODED const scene = document.getElementById("ramen"); scene.addEventListener("click", () => { scene.classList.remove("active"); // Restart CSS animation void scene.offsetWidth; scene.classList.add("active"); });

Top comments (0)