@manufosela/animation-handclock
SVG analog clock web component with animated hands built with Lit 3
Demo code (CodePen-ready HTML, CSS, JS)
HTML (html)
<div class="demo-container">
<h1>Animation Handclock Demo</h1>
<div class="controls">
<div class="control-group">
<label>Show Seconds</label>
<input type="checkbox" id="secondsToggle" checked />
</div>
<div class="control-group">
<label>Show Numbers</label>
<input type="checkbox" id="numbersToggle" checked />
</div>
<div class="control-group">
<label>Show Minute Markers</label>
<input type="checkbox" id="markersToggle" checked />
</div>
<div class="control-group">
<label>Theme</label>
<select id="themeSelect">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
</div>
<div class="clocks-grid">
<div class="clock-card">
<h3>Interactive Clock</h3>
<div class="clock-wrapper">
<animation-handclock id="mainClock"></animation-handclock>
</div>
<div class="digital-time" id="digitalTime">--:--:--</div>
</div>
<div class="clock-card">
<h3>Minimal Style</h3>
<div class="clock-wrapper">
<animation-handclock class="minimal-clock" .showNumbers=${false}></animation-handclock>
</div>
</div>
<div class="clock-card">
<h3>Elegant Gold</h3>
<div class="clock-wrapper">
<animation-handclock class="elegant-clock"></animation-handclock>
</div>
</div>
<div class="clock-card">
<h3>Neon Glow</h3>
<div class="clock-wrapper">
<animation-handclock class="neon-clock"></animation-handclock>
</div>
</div>
</div>
<h2>World Clocks</h2>
<div class="timezone-grid">
<div class="timezone-card">
<h4>New York</h4>
<animation-handclock class="timezone-clock" timezone="America/New_York" .showSeconds=${false}></animation-handclock>
</div>
<div class="timezone-card">
<h4>London</h4>
<animation-handclock class="timezone-clock" timezone="Europe/London" .showSeconds=${false}></animation-handclock>
</div>
<div class="timezone-card">
<h4>Paris</h4>
<animation-handclock class="timezone-clock" timezone="Europe/Paris" .showSeconds=${false}></animation-handclock>
</div>
<div class="timezone-card">
<h4>Tokyo</h4>
<animation-handclock class="timezone-clock" timezone="Asia/Tokyo" .showSeconds=${false}></animation-handclock>
</div>
<div class="timezone-card">
<h4>Sydney</h4>
<animation-handclock class="timezone-clock" timezone="Australia/Sydney" .showSeconds=${false}></animation-handclock>
</div>
<div class="timezone-card">
<h4>Dubai</h4>
<animation-handclock class="timezone-clock" timezone="Asia/Dubai" .showSeconds=${false}></animation-handclock>
</div>
</div>
</div> CSS (css)
:root {
--bg: #0c0f14;
--bg-elevated: #141923;
--bg-panel: #171d28;
--border: #262f3f;
--text: #f4f6fb;
--text-muted: #a7b0c2;
--text-dim: #7d879b;
--accent: #ff8a3d;
--accent-strong: #ff6a00;
--accent-soft: rgba(255, 138, 61, 0.16);
--shadow: 0 20px 50px rgba(5, 8, 14, 0.45);
--radius-lg: 22px;
--radius-md: 14px;
--radius-sm: 10px;
--max-width: 1160px;
}
<script type="module" src="../src/animation-handclock.js"></script>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
h1, h2 {
text-align: center;
color: var(--text);
margin-bottom: 2rem;
font-weight: 300;
letter-spacing: 2px;
}
.demo-container {
max-width: 1200px;
margin: 0 auto;
}
.clocks-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
margin-bottom: 3rem;
}
.clock-card {
background: var(--bg-elevated);
border-radius: 16px;
padding: 2rem;
text-align: center;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.clock-card h3 {
margin-bottom: 1rem;
font-weight: 500;
color: var(--accent);
}
.clock-wrapper {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.digital-time {
font-family: 'Courier New', monospace;
font-size: 1.5rem;
color: #667eea;
font-weight: bold;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
margin-bottom: 2rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.95);
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: center;
}
.control-group label {
font-size: 0.875rem;
color: var(--text-muted);
}
input[type='checkbox'] {
width: 20px;
height: 20px;
accent-color: #667eea;
}
select {
padding: 0.5rem 1rem;
border: 2px solid #667eea;
border-radius: 8px;
font-size: 1rem;
color: var(--accent);
background: var(--bg-elevated);
cursor: pointer;
}
/* Custom themed clocks */
.minimal-clock {
--handclock-size: 180px;
--handclock-face-color: #f5f5f5;
--handclock-border-color: #e0e0e0;
--handclock-border-width: 2;
--handclock-hour-hand-color: #424242;
--handclock-minute-hand-color: #757575;
--handclock-second-hand-color: #ff5722;
--handclock-marker-color: #bdbdbd;
}
.elegant-clock {
--handclock-size: 180px;
--handclock-face-color: var(--bg-panel);
--handclock-border-color: #c9a227;
--handclock-border-width: 3;
--handclock-hour-hand-color: #c9a227;
--handclock-minute-hand-color: #c9a227;
--handclock-second-hand-color: #ff6b6b;
--handclock-marker-color: #c9a227;
--handclock-number-color: #c9a227;
--handclock-center-color: #c9a227;
}
.neon-clock {
--handclock-size: 180px;
--handclock-face-color: #0a0a0a;
--handclock-border-color: #00ff88;
--handclock-border-width: 2;
--handclock-hour-hand-color: #00ff88;
--handclock-minute-hand-color: #00ff88;
--handclock-second-hand-color: #ff00ff;
--handclock-marker-color: #00ff88;
--handclock-number-color: #00ff88;
--handclock-center-color: #00ff88;
}
.timezone-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
}
.timezone-card {
background: var(--bg-elevated);
border-radius: 12px;
padding: 1.5rem;
text-align: center;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
}
.timezone-card h4 {
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: var(--text-muted);
}
.timezone-clock {
--handclock-size: 120px;
} JS (js)
const mainClock = document.getElementById('mainClock');
const digitalTime = document.getElementById('digitalTime');
const secondsToggle = document.getElementById('secondsToggle');
const numbersToggle = document.getElementById('numbersToggle');
const markersToggle = document.getElementById('markersToggle');
const themeSelect = document.getElementById('themeSelect');
mainClock.addEventListener('time-change', (e) => {
const { hours, minutes, seconds } = e.detail;
const h = hours.toString().padStart(2, '0');
const m = minutes.toString().padStart(2, '0');
const s = seconds.toString().padStart(2, '0');
digitalTime.textContent = `${h}:${m}:${s}`;
});
secondsToggle.addEventListener('change', (e) => {
mainClock.showSeconds = e.target.checked;
});
numbersToggle.addEventListener('change', (e) => {
mainClock.showNumbers = e.target.checked;
});
markersToggle.addEventListener('change', (e) => {
mainClock.showMinuteMarkers = e.target.checked;
});
themeSelect.addEventListener('change', (e) => {
mainClock.theme = e.target.value;
});