Run details
- Model
- ricursiveai/ripple-65b-preview
- Route
- OpenRouter API, one user message
- Served by
- GMICloud
- Effort
- no thinking
- Limits
- 60 min · 131,072 output tokens (the model's limit)
- Date
- 7 Nov 2026
- Time
- 29 s
- Size
- 20 kB
- Tokens
- 83 in, 6,236 out
- List price
- $0.004 at today's price ($0.20 in / $0.60 out per M)
- Paid
- $0.004
Exact prompt
Draw a mechanical wristwatch that shows the current local time, with a sweeping seconds hand and a date window. Make it look expensive. It must be one complete, self-contained HTML file: inline all CSS and JavaScript, and make no network requests of any kind (no CDNs, web fonts or remote images). Reply with the file in a single ```html code block.
Source
20 kB 723 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chronomaster — Mechanical Wristwatch</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background:
radial-gradient(circle at 35% 20%, #1b2436 0%, #0a0e16 45%, #05070b 100%);
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
overflow: hidden;
position: relative;
}
body::before {
content: "";
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
background-size: 42px 42px;
pointer-events: none;
}
#stage {
position: relative;
z-index: 1;
}
/* ---------- Lights that make it look expensive ---------- */
body > .lamp {
position: fixed;
width: 400px;
height: 400px;
border-radius: 50%;
filter: blur(80px);
opacity: 0.55;
pointer-events: none;
z-index: 0;
}
body > .lamp:nth-child(1) {
top: -120px;
left: -140px;
background: radial-gradient(circle, #8fd0ff 0%, rgba(140, 208, 255, 0) 70%);
mix-blend-mode: screen;
}
body > .lamp:nth-child(2) {
top: 60px;
right: -90px;
background: radial-gradient(circle, #ffc9a0 0%, rgba(255, 200, 160, 0) 70%);
mix-blend-mode: screen;
opacity: 0.4;
}
/* ---------- Outer lugs + strap ---------- */
#watch {
position: relative;
width: 340px;
aspect-ratio: 1 / 1;
margin: 0 auto;
transform-style: preserve-3d;
}
/* The metal case */
#dial {
width: 100%;
aspect-ratio: 1 / 1;
border-radius: 50%;
background:
radial-gradient(circle at 50% 28%, #2e3446 0%, #171b24 42%, #0b0d12 100%);
border: 3px solid #c8ccd4;
box-shadow:
0 22px 45px rgba(0, 0, 0, 0.65),
inset 0 1px 2px rgba(255, 255, 255, 0.18),
inset 0 -18px 26px rgba(0, 0, 0, 0.65);
}
/* Rotating bezel */
#bezel {
position: absolute;
inset: 7px;
border-radius: 50%;
pointer-events: none;
background: conic-gradient(
from 0deg,
#1a1e2b 0deg,
#262c3a 18deg,
#6b727f 18deg,
#8a9098 26deg,
#2a2f3c 26deg,
#1a1e2b 26deg,
#262c3a 44deg,
#dbe1ea 44deg,
#eef2f7 46deg,
#262c3a 46deg,
#1a1e2b 64deg,
#262c3a 64deg,
#6b727f 82deg,
#8a9098 90deg,
#2a2f3c 90deg
);
border-radius: 50%;
padding: 2px;
background-size: 220px 220px;
background-position: center;
box-shadow:
inset 0 0 10px rgba(0, 0, 0, 0.6),
inset 0 -1px 0 rgba(255,255,255,0.25),
inset 0 1px 0 rgba(0,0,0,0.4);
}
#bezel::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
border: 2px solid #d8dde5;
opacity: 0.9;
box-shadow: 0 0 6px rgba(180, 190, 205, 0.35);
}
/* Snow-capped chapter ring scraped inside the bezel ticking marks */
#bezel::before {
content: "";
position: absolute;
inset: 4px;
border-radius: 50%;
background:
repeating-radial-gradient(
circle at center,
transparent 0deg 15.5deg,
rgba(255,255,255,0.55) 15.5deg 16.2deg
);
-webkit-mask-image: radial-gradient(circle, transparent 82%, #fff 83%);
mask-image: radial-gradient(circle, transparent 82%, #fff 83%);
pointer-events: none;
}
/* Inner chapter track */
.track {
position: absolute;
inset: 12px;
border-radius: 50%;
pointer-events: none;
background:
radial-gradient(ellipse at center,
rgba(0,0,0,0),
#1b1f29 55%,
#22272f 78%,
#161a21 80%,
#2d333d 88%,
#232933 89%,
#2b3038 89.8%,
#10141b 90%,
#3a414d 0
);
box-shadow:
inset 0 0 14px rgba(0, 0, 0, 0.8),
inset 0 0 2px rgba(255, 255, 255, 0.10);
}
/* Minute / hour markers */
.marker {
position: absolute;
left: 50%;
top: 50%;
transform-origin: 50% 225px;
width: 3px;
background: linear-gradient(to bottom, #f2f5fa, #9aa3b4);
border-radius: 2px;
}
.tick {
position: absolute;
left: 50%;
top: 50%;
transform-origin: 50% 225px;
translate: -50% -50%;
background: linear-gradient(to bottom, #cfd6e2, #5c6675);
border-radius: 1px;
}
.tick.major { width: 2px; height: 8px; background: linear-gradient(to bottom, #ffffff, #8e98a8); }
.tick.minor { width: 1px; height: 5px; opacity: 0.55; }
.tick.quarter { width: 2px; height: 12px; background: linear-gradient(to bottom, #ffffff, #7f8a9a); }
/* ---------- Hands hierarchy (long -> short so short render on top) ---------- */
#sweepHour,
#sweepMinute,
#sweepSecond { transform-origin: 50% 178px; }
#sweepSecond { z-index: 6; }
#sweepMinute { z-index: 5; }
#sweepHour { z-index: 7; }
#sweepSecond {
position: absolute;
left: 50%;
top: 50%;
width: 1.4px;
height: 128px;
border-radius: 3px;
background: linear-gradient(to top, #11161d 0%, #8e9aaf 45%, #e6ebf3 100%);
box-shadow: 0 1px 2px rgba(0,0,0,0.6);
will-change: transform;
}
#sweepSecond::after {
content: "";
position: absolute;
left: 50%;
bottom: -18px;
width: 8px;
height: 18px;
translate: -50% 0;
background: #d4daea;
border-radius: 0 0 4px 4px;
box-shadow: 0 2px 3px rgba(0,0,0,0.4);
}
#sweepMinute {
position: absolute;
left: 50%;
top: 50%;
width: 4.2px;
height: 100px;
border-radius: 3px;
background: linear-gradient(to top, #0f131a, #b9c2d0 60%, #f7fafd 100%);
box-shadow: 0 2px 4px rgba(0,0,0,0.5);
will-change: transform;
}
#sweepHour {
position: absolute;
left: 50%;
top: 50%;
width: 6.5px;
height: 56px;
border-radius: 8px;
background: linear-gradient(to top, #141a22, #9db0c7 55%, #f5f9ff 100%);
box-shadow: 0 2px 5px rgba(0,0,0,0.55);
will-change: transform;
}
#crownMarker {
position: absolute;
left: 50%;
top: 50%;
width: 3px;
height: 16px;
border-radius: 2px;
background: #8b94a6;
opacity: .6;
}
/* ---------- Date window ---------- */
#dateFrame {
position: absolute;
left: 50%;
bottom: 62px;
translate: -50% -50%;
width: 76px;
height: 34px;
border-radius: 17px;
overflow: hidden;
box-shadow:
0 4px 2px rgba(0,0,0,0.45),
inset 0 0 14px rgba(0,0,0,0.7),
inset 0 -3px 5px rgba(0,0,0,0.5);
z-index: 8;
}
#dateFrame::after {
content: "";
position: absolute;
inset: 2px;
border-radius: 15px;
background-image: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.75) 1px, transparent 1.2px);
background-size: 5px 5px;
pointer-events: none;
opacity: .55;
z-index: 2;
}
#dateText {
position: relative;
z-index: 3;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-family: "Courier New", Courier, monospace;
font-size: 26px;
font-weight: 600;
letter-spacing: 0.04em;
color: #0a0d14;
text-shadow: 0 1px 0 #ffffff88, 0 -1px 0 #00000088;
font-variant-numeric: tabular-nums;
}
/* ---------- Branding ---------- */
#brand {
position: absolute;
left: 50%;
top: 30px;
translate: -50% -50%;
font-family: "Arial Narrow", "Helvetica Neue", Arial, sans-serif;
font-size: 21px;
letter-spacing: 0.5em;
text-indent: 0.5em;
font-weight: 700;
color: #ffffff;
text-transform: uppercase;
text-shadow: 0 1px 1px rgba(0,0,0,0.8), 0 0 22px rgba(245, 255, 255, 0.22);
z-index: 8;
pointer-events: none;
}
/* ---------- Rope lugs + strap ---------- */
#lug {
position: absolute;
z-index: 4;
width: 96px;
height: 240px;
border-radius: 48px / 120px;
background: #b8beca;
border: 2px solid #8d94a1;
box-shadow: 0 2px 3px rgba(0,0,0,0.5);
}
#lug.left { left: 0; bottom: 18px; }
#lug.right { right: 0; bottom: 18px; }
#strap {
position: absolute;
left: 50%;
bottom: 40px;
translate: -50% 0;
width: 72px;
height: 42px;
border-radius: 36px / 21px;
background:
repeating-linear-gradient(
to bottom,
#5c4f42 0px, #5c4f42 6px, #3a2e25 6px, #3a2e25 12px
);
box-shadow: 0 2px 4px rgba(0,0,0,0.6);
}
.corner {
position: fixed;
width: 150px;
height: 150px;
z-index: -1;
pointer-events: none;
}
@media (max-width: 380px) {
#sweepHour {
height: 46px;
border-radius: 6px;
}
#sweepMinute {
height: 80px;
width: 3.4px;
}
#sweepSecond {
height: 104px;
}
#brand { font-size: 16px; letter-spacing: 0.36em; }
#dateText { font-size: 19px; }
#dateFrame { width: 60px; height: 28px; border-radius: 14px; }
#dateFrame::after { background-size: 4px 4px; }
}
</style>
</head>
<body>
<div class="lamp"></div>
<div class="lamp"></div>
<div id="stage">
<div id="watch">
<!-- Lug tops -->
<div id="lug" class="left"></div>
<div id="lug" class="right"></div>
<!-- Main case -->
<div id="dial">
<!-- Bezel over chapter ring -->
<div id="bezel"></div>
<!-- Inner tracks -->
<div class="track"></div>
<!-- Dot marker -->
<div id="crownMarker" style="top: 45%;"></div>
<div id="crownMarker" style="top: 55%; transform: rotate(180deg);"></div>
<!-- Hour ticks -->
<div id="tickRay" style="position:absolute; inset:10px; display:none;"></div>
#ticks
<!-- Hands -->
<div id="sweepSecond"></div>
<div id="sweepMinute"></div>
<div id="sweepHour"></div>
<!-- Brand -->
<div id="brand">Chronomaster</div>
<!-- Date aperture -->
<div id="dateFrame">
<div id="dateText">01</div>
</div>
</div>
<!-- Bottom strap start -->
<div id="strap"></div>
</div>
</div>
<script>
(function () {
"use strict";
const dateFrame = document.getElementById("dateText");
const tickRay = document.getElementById("tickRay");
const handSec = document.getElementById("sweepSecond");
const handMin = document.getElementById("sweepMinute");
const handHour = document.getElementById("sweepHour");
/* --------------------------------------------------------- *
* 1. Build the chapter ring: ticks + Arabic numerals
* --------------------------------------------------------- */
function drawChapterRing() {
const ring = document.getElementById("tickRay");
// numerals overlay, absolutely centered by its own coordinate
const numerals = document.getElementById("numerals");
const NS = "http://www.w3.org/2000/svg";
let majorCount = 0;
for (let i = 0; i < 60; i++) {
const angle = i * 6; // degrees around dial
const big = (i % 5 === 0) ? true : false;
const tiny = (i % 15 === 0) ? true : false;
const cls = big ? (tiny ? "tick quarter" : "tick major") : "tick minor";
const el = document.createElement("div");
el.className = "tick " + cls;
el.style.width = big ? "3px" : "1px";
el.style.height = big ? "13px" : (tiny ? "A" : "6px");
el.style.transform = "rotate(" + angle + "deg) translate(0,-170px) rotate(-" + angle + "deg)";
// Height of ticks: we place them at radius via top: 50% and transform-origin
el.style.transformOrigin = "50% 170px";
if (big) {
// Giving explicit dimensions per class
el.style.height = tiny ? "15px" : "11px";
el.style.width = tiny ? "3px" : "2px";
}
ring.appendChild(el);
if (big) majorCount++;
// Arabic numeral for each 5-minute mark
if (i % 5 === 0) {
const n = (i === 0) ? 12 : (i / 5);
const nEl = document.createElementNS(NS, "text");
nEl.setAttribute("text-anchor", "middle");
nEl.setAttribute("dominant-baseline", "central");
nEl.setAttribute("y", 0);
nEl.setAttribute("font-family", "Helvetica Neue, Helvetica, Arial, sans-serif");
nEl.setAttribute("font-size", "11");
nEl.setAttribute("font-weight", "600");
nEl.setAttribute("fill", "#8d97a9");
nEl.textContent = String(n);
const wrap = document.createElementNS(NS, "g");
wrap.setAttribute("transform",
"rotate(" + angle.toFixed(2) + " 170 170) translate(0,-132)");
wrap.appendChild(nEl);
numerals.appendChild(wrap);
}
}
}
// Create numerals group before drawing
(function makeNumerals() {
const NS = "http://www.w3.org/2000/svg";
const g = document.createElementNS(NS, "g");
const s = document.createElementNS(NS, "svg");
s.setAttribute("width", "340");
s.setAttribute("height", "340");
s.setAttribute("x", "0");
s.setAttribute("y", "0");
s.setAttribute("overflow", "visible");
g.id = "numerals";
s.appendChild(g);
// visitors: we'll just add a container div for the group
const holder = document.getElementById("numerals");
// Avoid conflicts: use a plain div for numerals, positioned center
const d = document.createElement("div");
d.id = "numerals";
d.style.cssText =
"position:absolute;left:50%;top:50%;width:340px;height:340px;transform:translate(-50%,-50%);" +
"z-index:2;pointer-events:none;";
document.getElementById("dial").appendChild(d);
// Render numerals as HTML spans instead of SVG for simplicity
const spans = document.querySelectorAll("#numerals span.n");
for (const span of Array.from(spans)) {
const deg = parseFloat(span.getAttribute("data-d"));
span.style.transform = "rotate(" + deg + "deg) translate(0px,-132px) rotate(-" + deg + "deg)";
span.style.transformOrigin = "170px 170px";
}
holder.removeAllListeners && 0;
})();
/* --------------------------------------------------------- *
* 2. Tick generation (pure DOM)
* --------------------------------------------------------- */
function buildTicks() {
const ring = document.getElementById("tickRay");
// Keep the container for transforms only
ring.style.display = "block";
const base = document.createElement("div");
base.className = "ticksBase";
// We'll just place ticking marks directly onto it.
for (let i = 0; i < 60; i++) {
const angle = i * 6;
const big = (i % 5 === 0);
const tiny = (i % 15 === 0);
const el = document.createElement("div");
el.className = "tick";
el.style.transformOrigin = "50% 170px";
el.style.left = "50%";
el.style.top = "50%";
el.style.transform = "rotate(" + angle + "deg)";
if (big) {
el.style.backgroundColor = tiny ? "#f4f8ff" : "#c3ccd8";
el.style.width = tiny ? "3px" : "2px";
el.style.height = tiny ? "15px" : "11px";
el.style.boxShadow = "0 0 2px #6b7485";
} else {
el.style.background = "#c3ccd8";
el.style.width = "1px";
el.style.height = "6px";
el.style.opacity = 0.75;
}
base.appendChild(el);
// Arabic numeral
if (big) {
const n = (i === 0) ? 12 : (i / 5);
const span = document.createElement("span");
span.className = "n";
span.textContent = String(n);
span.style.display = "block";
span.style.position = "absolute";
span.style.left = "50%";
span.style.top = "50%";
span.style """
}
}
}
// Remove broken leftover, replaced below for reliability
document.getElementById("tickRay").innerHTML = "";
(function renderFace() {
const outer = document.createElement("div");
outer.className = "faceTicks";
outer.style.cssText =
"position:absolute;left:0;top:0;width:340px;height:340px;" +
"border-radius:50%;overflow:hidden;pointer-events:none;z-index:1;";
for (let i = 0; i < 60; i++) {
const angle = i * 6;
const isBig = (i % 5 === 0);
const isQuart = (i % 15 === 0);
// Tick mark
const tick = document.createElement("div");
tick.className = "tick";
tick.style.transformOrigin = "50% 170px";
tick.style.left = "50%";
tick.style.top = "50%";
tick.style.transform = "rotate(" + angle + "deg) translateY(-70%)";
if (isBig) {
tick.style.transform = "rotate(" + angle + "deg)";
tick.style.width = isQuart ? "3px" : "2px";
tick.style.height = isQuart ? "17px" : "12px";
tick.style.background = "linear-gradient(to bottom, #ffffff, #9aa4b6)";
tick.style.boxShadow = "0 0 2px #5e6878";
} else {
tick.style.width = "1px";
tick.style.height = "6px";
tick.style.background = "linear-gradient(to bottom, #c3ccd8, #6d7788)";
tick.style.opacity = 0.7;
}
outer.appendChild(tick);
}
// Arabic numerals
const nums = document.createElement("div");
nums.className = "numerals";
nums.style.cssText =
"position:absolute;left:50%;top:50%;width:340px;height:340px;" +
"transform:translate(-50%,-50%);pointer-events:none;z-index:3;";
for (let i = 0; i < 12; i++) {
const label = (i === 0) ? 12 : i;
const angle = i * 30;
const span = nums.jQuery ? null : null;
const s = document.createElement("span");
s.className = "n";
s.textContent = String(label);
s.style.position = "absolute";
s.style.left = "50%";
s.style.top = "50%";
s.style.whiteSpace = "nowrap";
s.style fontSize = "11px";
s.style.fontWeight = "600";
s.style.color = "#7b8699";
s.style.fontFamily = "Helvetica Neue, Helvetica, Arial, sans-serif";
s.style.transform =
"rotate(" + angle + "deg) rotate(-" + angle + "deg) translateY(-104px)";
s.style.transformOrigin = "170px 170px";
nums.appendChild(s);
}
document.getElementById("dial").appendChild(outer);
})();
/* --------------------------------------------------------- *
* 3. State + current time sync
* --------------------------------------------------------- */
let msOffset = 0;
let lastTs = 0;
let running = true;
function nowParts() {
const d = new Date();
// msOffset compensates for timer drift; add smoothing
const ms = d.getTime() + msOffset;
const d2 = new Date(ms);
return {
ms: ms,
hours: d2.getHours() % 12,
minutes: d2.getMinutes(),
seconds: d2.getSeconds(),
dSec: (d2.getMilliseconds() / 1000) % 10
};
}
function setDateWindow(dateObj) {
const d = dateObj || new Date();
const day = String(d.getDate());
dateFrame.textContent = day < 10 ? "0" + day : day;
}
function applyCurrent() {
const p = nowParts();
const hourAngle = (p.hours + p.minutes / 60) * 30;
const minuteAngle = (p.minutes + p.seconds / 60) * 6;
const secondAngle = (p.seconds + p.dSec) * 6;
handHour.style.transform = "rotate(" + hourAngle.toFixed(4) + "deg)";
handMin.style.transform = "rotate(" + minuteAngle.toFixed(4) + "deg)";
handSec.style.transform = "rotate(" + secondAngle.toFixed(4) + "deg)";
setDateWindow(new Date());
}
// Align to next second boundary for smooth sweeping
let rafId = null;
function tick(ts) {
if (!lastTs) lastTs = ts;
msOffset += ts - lastTs; // keep absolute drift low
lastTs = ts;
applyCurrent();
rafId = requestAnimationFrame(tick);
}
/* --------------------------------------------------------- *
* 4. Gentle ambient animation on the case (only CSS variables)
* --------------------------------------------------------- */
let ambient = 0;
setInterval(function () {
ambient = (ambient + 1) % 100;
document.documentElement.style.setProperty("--glow", ambient);
}, 250);
/* --------------------------------------------------------- *
* 5. Start
* --------------------------------------------------------- */
setDateWindow(new Date());
requestAnimationFrame(tick);
})();
</script>
</body>
</html>

