.
Cute Lamp Character is a free, copy-paste ready interactive CSS character animation
built with pure HTML, CSS, and vanilla JavaScript — zero external libraries. The 300×400px
.lamp-container floats on an infinite @keyframes float animation:
translateY(-15px) at 50% over 3 seconds with ease-in-out timing.
The trapezoid lampshade (180×120px) uses
clip-path: polygon(15% 0%, 85% 0%, 100% 100%, 0% 100%) with a purple gradient
(#b8a9d6 → #8b7ab8 → #6d5d95), and scales to 1.05 on hover via CSS transition.
The face lives in a 140×80px .face div inside the shade. Eyes blink
via @keyframes blink: at the 98% keyframe, eye height collapses from
8px to 2px, snapping back on the next frame — giving the appearance of a natural
blink every 4 seconds. A ::before white dot (4×4px) adds a glossy highlight.
Blush cheeks use radial-gradient(circle, rgba(255,150,180,0.5), transparent).
The light glow pulses opacity 0.6→1 and scale(1.1) over 2 seconds.
The power cord swings ±5° over 2 seconds. Four sparkle dots
stagger at 0/0.5/1/1.5s animation delays.
The entire on/off state is managed by a single CSS class: .light-off added or
removed from the #lamp container via lamp.classList.toggle('light-off').
CSS descendant selectors handle everything else — no JavaScript touches any style directly.
When .light-off is active: the lampshade gradient shifts to a darker palette
(#7a6b98 → #5d4d78 → #4a3d60); the glow fades out (opacity: 0);
eye elements grow to 14px height with full border-radius: 50%
(round sad eyes instead of flat happy eyes); the mouth flips from smile
(border-radius: 0 0 30px 30px) to frown
(border-radius: 30px 30px 0 0) by swapping which side has the curve.
This pure CSS state pattern is highly maintainable and animatable.
Cute Lamp Character is ideal for: kids' websites and educational apps, whimsical portfolio pages, kawaii / cute UI themes, loading screen mascots, onboarding characters, 404 error page companions, dark mode toggle mascots (the on/off state naturally maps to theme switching), CSS animation tutorials (blinking, floating, sparkle, clip-path, class-toggle patterns), and any project needing a charming interactive character without a library.
Released under Creative Commons Attribution 4.0 International (CC BY 4.0). Free for personal and commercial use with attribution to Coodeverse.
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Cute Lamp Character</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #1a2332 0%, #2d3e50 50%, #1a2332 100%); font-family: Arial, sans-serif; overflow: hidden; } .lamp-container { position: relative; width: 300px; height: 400px; animation: float 3s ease-in-out infinite; } @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-15px); } } .lampshade { position: absolute; width: 180px; height: 120px; background: linear-gradient(180deg, #b8a9d6 0%, #8b7ab8 50%, #6d5d95 100%); border-radius: 50% 50% 0 0 / 25% 25% 0 0; top: 50px; left: 50%; transform: translateX(-50%); box-shadow: 0 10px 30px rgba(0,0,0,0.3), inset 0 -20px 30px rgba(0,0,0,0.2), inset 0 5px 15px rgba(255,255,255,0.2); clip-path: polygon(15% 0%, 85% 0%, 100% 100%, 0% 100%); transition: all 0.3s ease; } .lampshade:hover { transform: translateX(-50%) scale(1.05); } .face { position: absolute; top: 60px; left: 50%; transform: translateX(-50%); width: 140px; height: 80px; z-index: 10; } .eyes { position: absolute; top: 25px; left: 50%; transform: translateX(-50%); width: 80px; display: flex; justify-content: space-between; } .eye { width: 24px; height: 8px; background: #2d3e50; border-radius: 50%; position: relative; animation: blink 4s ease-in-out infinite; } .eye::before { content: ''; position: absolute; width: 4px; height: 4px; background: white; border-radius: 50%; top: 1px; left: 6px; opacity: 0.8; } @keyframes blink { 0%,96%,100%{height:8px} 98%{height:2px} } .blush { position: absolute; width: 20px; height: 12px; background: radial-gradient(circle, rgba(255,150,180,0.5), transparent); border-radius: 50%; top: 38px; } .blush.left { left: 20px; } .blush.right { right: 20px; } .mouth { position: absolute; width: 30px; height: 15px; border: 3px solid #2d3e50; border-top: none; border-radius: 0 0 30px 30px; top: 48px; left: 50%; transform: translateX(-50%); background: #ff6b9d; } .light-glow { position: absolute; width: 200px; height: 200px; background: radial-gradient(circle, rgba(255,255,255,0.3), transparent 60%); top: 140px; left: 50%; transform: translateX(-50%); border-radius: 50%; animation: pulse 2s ease-in-out infinite; pointer-events: none; } @keyframes pulse { 0%,100%{opacity:0.6;transform:translateX(-50%) scale(1)} 50%{opacity:1;transform:translateX(-50%) scale(1.1)} } .lamp-rim { position: absolute; width: 200px; height: 15px; background: linear-gradient(180deg, #e8e8e8, #c0c0c0); border-radius: 50%; top: 168px; left: 50%; transform: translateX(-50%); box-shadow: 0 5px 15px rgba(0,0,0,0.3), inset 0 2px 5px rgba(255,255,255,0.5), inset 0 -2px 5px rgba(0,0,0,0.2); z-index: 5; } .lamp-stand { position: absolute; width: 12px; height: 120px; background: linear-gradient(90deg, #d0d0d0, #f0f0f0, #d0d0d0); top: 180px; left: 50%; transform: translateX(-50%); border-radius: 6px; box-shadow: 0 5px 20px rgba(0,0,0,0.2); } .lamp-base { position: absolute; width: 140px; height: 25px; background: linear-gradient(180deg, #f0f0f0, #d0d0d0); border-radius: 50%; top: 300px; left: 50%; transform: translateX(-50%); box-shadow: 0 10px 30px rgba(0,0,0,0.4); } .power-cord { position: absolute; width: 3px; height: 60px; background: #3d3d3d; bottom: 70px; right: 45px; transform-origin: top; border-radius: 2px; animation: swing 2s ease-in-out infinite; } @keyframes swing { 0%,100%{transform:rotate(5deg)} 50%{transform:rotate(-5deg)} } .switch { position: absolute; width: 16px; height: 24px; background: linear-gradient(135deg, #888, #666); border-radius: 8px; top: 220px; right: 80px; cursor: pointer; box-shadow: 0 3px 8px rgba(0,0,0,0.3); transition: all 0.2s ease; z-index: 20; } .lamp-container.light-off .lampshade { background: linear-gradient(180deg, #7a6b98 0%, #5d4d78 50%, #4a3d60 100%); } .lamp-container.light-off .light-glow { opacity: 0; } .lamp-container.light-off .eye { height: 14px; border-radius: 50%; } .lamp-container.light-off .mouth { border-radius: 30px 30px 0 0; border-bottom: 3px solid #2d3e50; border-top: none; } .sparkle { position: absolute; width: 4px; height: 4px; background: white; border-radius: 50%; animation: sparkle 2s ease-in-out infinite; box-shadow: 0 0 8px white; } @keyframes sparkle { 0%,100%{opacity:0;transform:scale(0)} 50%{opacity:1;transform:scale(1)} } .sparkle:nth-child(1){top:40px;left:60px} .sparkle:nth-child(2){top:50px;right:60px;animation-delay:0.5s} .sparkle:nth-child(3){top:80px;left:50px;animation-delay:1s} .sparkle:nth-child(4){top:90px;right:50px;animation-delay:1.5s} </style>
</head>
<body> <div class="lamp-container" id="lamp"> <div class="sparkle"></div> <div class="sparkle"></div> <div class="sparkle"></div> <div class="sparkle"></div> <div class="lampshade"> <div class="face"> <div class="eyes"> <div class="eye"></div> <div class="eye"></div> </div> <div class="blush left"></div> <div class="blush right"></div> <div class="mouth"></div> </div> </div> <div class="light-glow"></div> <div class="lamp-rim"></div> <div class="lamp-stand"></div> <div class="lamp-base"></div> <div class="power-cord"></div> <div class="switch" id="switch"></div> </div> <script> const lamp = document.getElementById('lamp'); const switchBtn = document.getElementById('switch'); let isOn = true; switchBtn.addEventListener('click', function() { isOn = !isOn; lamp.classList.toggle('light-off'); this.style.transform = 'scale(0.9)'; setTimeout(() => { this.style.transform = ''; }, 100); }); document.querySelector('.lampshade').addEventListener('click', function() { lamp.style.animation = 'none'; lamp.style.transform = 'rotate(10deg) scale(1.1)'; setTimeout(() => { lamp.style.animation = 'float 3s ease-in-out infinite'; lamp.style.transform = ''; }, 300); }); </script>
</body>
</html>
Common questions about the free Cute Lamp Character interactive CSS animation project.
Yes — 100% free under Creative Commons Attribution 4.0. No sign-up, no payment. Click Download Project and use it in kids' websites, kawaii UI, personal, or commercial projects with attribution to Coodeverse.
Use a keyframe that briefly collapses the height: @keyframes blink { 0%,96%,100% { height: 8px; } 98% { height: 2px; } }. Apply: animation: blink 4s ease-in-out infinite. The eye flattens at 98% of the 4-second cycle. A white ::before pseudo-element (4×4px circle at top:1px, left:6px) adds a glossy highlight for a cute, lively look.
Toggle a single class: lamp.classList.toggle('light-off'). CSS descendant selectors handle all visual changes: .lamp-container.light-off .mouth { border-radius: 30px 30px 0 0; } flips smile to frown. .lamp-container.light-off .eye { height: 14px; border-radius: 50%; } makes round sad eyes. .lamp-container.light-off .light-glow { opacity: 0; } removes glow. No JavaScript touches any style directly — only the class is toggled.
Define: @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-15px); } }. Apply: animation: float 3s ease-in-out infinite. The ease-in-out timing creates smooth deceleration at top and bottom of each bob. Change -15px to -8px for subtle hover, or -25px for exaggerated floating.
Use clip-path: polygon(15% 0%, 85% 0%, 100% 100%, 0% 100%) on a rectangular div. This clips the top to 70% of width (15%–85%) while leaving the bottom full width (0%–100%), creating a trapezoid. The div keeps its gradient background, box-shadow, and border-radius. Combine with border-radius: 50% 50% 0 0 / 25% 25% 0 0 for a subtle top curve.
Give all sparkles the same base animation: @keyframes sparkle { 0%,100% { opacity:0; transform:scale(0); } 50% { opacity:1; transform:scale(1); } }. Then offset each: .sparkle:nth-child(2) { animation-delay: 0.5s; }, :nth-child(3) { animation-delay: 1s; }, :nth-child(4) { animation-delay: 1.5s; }. The staggered delays make sparkles appear to twinkle asynchronously.
Browse coodeverse.com/projects — Neon Toggle Switch, Epic Animated Delete Button, Holographic Login, Cosmos Star Animation, Particle Fireworks and more. All 100% free with complete HTML CSS JavaScript source code.