All examples / feature card
Isometric schedule: a calendar that fills itself in (SVG SMIL)
A desk calendar and a small clock on an isometric platform. The clock hand turns once per loop, four day tiles fold down and flip back up one by one, and a check lands on the booked day. The motion is SMIL inside the SVG, started and paused by a tiny module.
Prompt tested
Feature card size
Prompt
Draw a looping isometric illustration for a 'Scheduling' feature card as one inline SVG animated with SVG SMIL (<animate> and <animateTransform> elements inside the SVG; no CSS keyframes, no libraries), started by a tiny JavaScript module. Scene: a light paper-coloured isometric platform (30° projection). At the back stands a desk calendar block: an upright pale slab with a coral header band and two short navy binder rings on top, and a grid of 4 × 2 pale day slots drawn in the plane of its front face. Four slots hold coloured day tiles (sky, mint, warm yellow, coral); the coral one is the booked day and carries a small paper-coloured circle with a navy check. In front on the left a round sky-blue clock with a paper face and four ticks stands on a small isometric pedestal, drawn in the same isometric plane (a sheared circle), with a short navy hour hand and a long coral minute hand. Motion, one 6-second loop: the coral hand turns once around the clock; after a one-second hold the four tiles fold down together (scale to zero height from their bottom edge while fading), then flip back up one after another, and the check fades back onto the coral day. Give every SMIL element begin="indefinite", repeatCount="indefinite", dur="6s" and values whose first and last entries are equal (timing with keyTimes, not begin offsets); start them all at once from JavaScript with beginElement(), and map pause/play to svg.pauseAnimations()/unpauseAnimations(). Under prefers-reduced-motion start nothing, so the still frame (all tiles up, check on) stays. Use a navy outline (#1F2A44, 1.5 px, round joins) and the palette ink #1F2A44, slate #5B6B8C, sky #7FB6FF, mint #6FD6B4, sun #FFC861, coral #FF8A7A, paper #F6F4EF; shade each box with a light top, mid right face and darker left face.
Words it rests on
- isometric illustration (30° projection)
- inline SVG
- SVG SMIL animation (<animate>, <animateTransform>)
- begin="indefinite" + beginElement()
- keyTimes / values stagger
- pauseAnimations() / unpauseAnimations()
- drawing in an isometric plane (matrix transform)
- prefers-reduced-motion still frame
- feature card
Prompt test
A fresh AI session given only this prompt rebuilt this on 2026-11-04 using claude-opus-5-5; a separate fresh session using claude-opus-5-5 judged it “like this”.


Lesson: For SMIL, naming the exact contract (begin="indefinite", repeatCount="indefinite", equal first and last values, timing with keyTimes rather than begin offsets, start with beginElement(), pause with pauseAnimations()) got a rebuild that keeps every motion rule on the first try; describing the timeline as a story ("hold, fold down together, flip up one after another, check fades back") fixed the order of events, while the platform side colours, left unnamed, drifted.
Facts
- Tags
- feature card svg smil inline svg isometric flat shaded harbor
- Weight
- 1.8 KB gzip (SVG + CSS + JS)
- Needs
- No library; a small JavaScript module
- Browser support
- All current browsers (Chrome, Edge, Firefox, Safari): SVG SMIL animation, started and paused by a small ES module (beginElement, pauseAnimations).
- Loop
- 6 s, seamless; still frame with reduced motion
- Link
/examples/iso-schedule/
Source
Paste all three parts into any page. Wrap the SVG in <div class="ma-iso-schedule"> and put the CSS in a <style> element or your stylesheet; every class, id and animation name starts with ma-iso-schedule, so it will not clash with your styles.
demo.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" role="img" aria-labelledby="ma-iso-schedule-title">
<title id="ma-iso-schedule-title">An isometric desk calendar beside a clock: the clock hand turns, day tiles flip up one by one and a check lands on the booked day</title>
<g stroke="#1F2A44" stroke-width="1.5" stroke-linejoin="round">
<path d="M156.3 93.7L346.8 203.7L232.5 269.7L42 159.7Z" fill="#1F2A44" opacity=".08"/>
<path d="M352.5 185L238.2 251L238.2 240L352.5 174Z" fill="#C9D2E3"/>
<path d="M47.7 141L238.2 251L238.2 240L47.7 130Z" fill="#A3B0C8"/>
<path d="M162 64L352.5 174L238.2 240L47.7 130Z" fill="#F6F4EF"/>
<path d="M300.6 184L288.4 191L288.4 91L300.6 84Z" fill="#B7C1D3"/>
<path d="M172.4 124L288.4 191L288.4 91L172.4 24Z" fill="#E8ECF3"/>
<path d="M184.5 17L300.6 84L288.4 91L172.4 24Z" fill="#E8ECF3"/>
<path d="M172.4 46L288.4 113L288.4 91L172.4 24Z" fill="#FF8A7A"/>
<path d="M198.4 45v-12" stroke="#1F2A44" stroke-width="3" stroke-linecap="round"/>
<path d="M262.5 82v-12" stroke="#1F2A44" stroke-width="3" stroke-linecap="round"/>
<g transform="matrix(.866 .5 0 1 172.4 24)" stroke-width="1.2">
<rect x="10" y="28" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="41" y="28" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="72" y="28" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="103" y="28" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="10" y="62" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="41" y="62" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="72" y="62" width="26" height="28" rx="2" fill="#DDE3EE"/>
<rect x="103" y="62" width="26" height="28" rx="2" fill="#DDE3EE"/>
</g>
<g transform="matrix(.866 .5 0 1 172.4 24) translate(41 56)">
<g class="ma-iso-schedule-tile">
<animateTransform attributeName="transform" type="scale" values="1 1;1 1;1 0;1 0;1 1;1 1" keyTimes="0;0.2;0.2;0.3;0.4;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<animate attributeName="opacity" values="1;1;0;0;1;1" keyTimes="0;0.2;0.2;0.3;0.4;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<rect x="0" y="-28" width="26" height="28" rx="2" fill="#7FB6FF"/>
<path d="M5 -21h16" stroke="#F6F4EF" stroke-width="2.5" stroke-linecap="round"/>
</g></g>
<g transform="matrix(.866 .5 0 1 172.4 24) translate(103 56)">
<g class="ma-iso-schedule-tile">
<animateTransform attributeName="transform" type="scale" values="1 1;1 1;1 0;1 0;1 1;1 1" keyTimes="0;0.2;0.2;0.4;0.5;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<animate attributeName="opacity" values="1;1;0;0;1;1" keyTimes="0;0.2;0.2;0.4;0.5;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<rect x="0" y="-28" width="26" height="28" rx="2" fill="#6FD6B4"/>
<path d="M5 -21h16" stroke="#F6F4EF" stroke-width="2.5" stroke-linecap="round"/>
</g></g>
<g transform="matrix(.866 .5 0 1 172.4 24) translate(10 90)">
<g class="ma-iso-schedule-tile">
<animateTransform attributeName="transform" type="scale" values="1 1;1 1;1 0;1 0;1 1;1 1" keyTimes="0;0.2;0.2;0.6;0.7;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<animate attributeName="opacity" values="1;1;0;0;1;1" keyTimes="0;0.2;0.2;0.6;0.7;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<rect x="0" y="-28" width="26" height="28" rx="2" fill="#FFC861"/>
<path d="M5 -21h16" stroke="#F6F4EF" stroke-width="2.5" stroke-linecap="round"/>
</g></g>
<g transform="matrix(.866 .5 0 1 172.4 24) translate(72 90)">
<g class="ma-iso-schedule-tile">
<animateTransform attributeName="transform" type="scale" values="1 1;1 1;1 0;1 0;1 1;1 1" keyTimes="0;0.2;0.2;0.7;0.8;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<animate attributeName="opacity" values="1;1;0;0;1;1" keyTimes="0;0.2;0.2;0.7;0.8;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<rect x="0" y="-28" width="26" height="28" rx="2" fill="#FF8A7A"/>
<path d="M5 -21h16" stroke="#F6F4EF" stroke-width="2.5" stroke-linecap="round"/>
<g stroke-width="1.6">
<circle cx="13" cy="-11" r="7" fill="#F6F4EF"/>
<path d="M9.7 -11l2.3 2.4 4.3-4.7" fill="none" stroke-linecap="round"/>
<animate attributeName="opacity" values="1;1;0;0;1;1" keyTimes="0;0.2;0.2;0.8;0.9;1" dur="6s" begin="indefinite" repeatCount="indefinite"/>
</g>
</g></g>
<path d="M137.8 142L110 158L110 142L137.8 126Z" fill="#B7C1D3"/>
<path d="M73.7 137L110 158L110 142L73.7 121Z" fill="#8F9BB3"/>
<path d="M101.4 105L137.8 126L110 142L73.7 121Z" fill="#E8ECF3"/>
<g transform="matrix(.866 .5 0 1 105.7 89.5)">
<path d="M-9 34L-5 25h10l4 9Z" fill="#5B6B8C"/>
<circle r="27" fill="#7FB6FF"/>
<circle r="21" fill="#F6F4EF" stroke-width="1.2"/>
<path d="M0 -18L0 -15" stroke="#5B6B8C" stroke-width="1.4" stroke-linecap="round"/>
<path d="M18 -0L15 -0" stroke="#5B6B8C" stroke-width="1.4" stroke-linecap="round"/>
<path d="M0 18L0 15" stroke="#5B6B8C" stroke-width="1.4" stroke-linecap="round"/>
<path d="M-18 0L-15 0" stroke="#5B6B8C" stroke-width="1.4" stroke-linecap="round"/>
<path d="M0 0L7 -5" stroke="#1F2A44" stroke-width="2.5" stroke-linecap="round"/>
<g class="ma-iso-schedule-hand">
<animateTransform attributeName="transform" type="rotate" values="0 0 0;360 0 0" dur="6s" begin="indefinite" repeatCount="indefinite"/>
<path d="M0 3V-15" stroke="#FF8A7A" stroke-width="2" stroke-linecap="round"/>
</g>
<circle r="2.4" fill="#1F2A44" stroke="none"/>
</g>
</g>
</svg>
demo.css
/* Isometric schedule card. The motion is SMIL inside the SVG (6 s loop): the clock hand turns once,
four day tiles fold down together and flip back up one by one, and a check lands on the booked
day. Every SMIL element waits for demo.js (begin="indefinite"), so the markup's resting state is
the still frame: all tiles up, the check on. */
.ma-iso-schedule svg {
display: block;
width: 100%;
height: auto;
}
/* Calm still frame: demo.js starts nothing under reduced motion; this keeps any CSS still too. */
@media (prefers-reduced-motion: reduce) {
.ma-iso-schedule,
.ma-iso-schedule * {
animation: none !important;
}
}
The motion lives in a small module. Load it with <script type="module"> and start it with mount(document.querySelector('.ma-iso-schedule')); it returns { play, pause } and starts nothing when the visitor prefers reduced motion.
demo.js
// Starts the SVG's SMIL animation and maps pause/play onto the SVG timeline. Every animation
// element waits with begin="indefinite", so with no script, or when the visitor prefers reduced
// motion (prefers-reduced-motion: reduce), the drawing stays on its calm still frame.
export function mount(root, options = {}) {
const mm = options.matchMedia ?? (globalThis.matchMedia ? (q) => globalThis.matchMedia(q) : undefined);
const reduced = options.reduced ?? (mm ? mm('(prefers-reduced-motion: reduce)').matches : false);
const svg = root.querySelector('svg');
if (!svg || reduced) return { play() {}, pause() {} };
// Begin every element at the same moment so the 6 s timeline stays in step.
for (const el of svg.querySelectorAll('animate, animateTransform')) el.beginElement();
return {
play() {
svg.unpauseAnimations();
},
pause() {
svg.pauseAnimations();
},
};
}