In this document
SVG animation format
This page is written to be pasted into an AI chat such as Claude or ChatGPT, together with the SVG animation prompt. It describes the one file the kiosk accepts as an animated welcome screen: a single animated SVG, with a loop that repeats without a jump. Follow every rule below exactly, and reply with only the SVG file.
For the whole picture (photos, videos, layouts and where to upload), see Welcome screen: photos, videos and animations.
Shape: which screens it is for
The shape of the drawing (its viewBox) says which kiosk screens it is made for:
| Shape | Example viewBox | Shown on |
|---|---|---|
| Square | 0 0 1000 1000 | landscape and portrait screens |
| Wide, at least 1.6 times as wide as tall | 0 0 1600 1000 | landscape screens only |
| Tall, at least 1.6 times as tall as wide | 0 0 1000 1600 | portrait screens only |
A shape in between, such as 0 0 1200 1000, is refused. Draw for the screen
your kiosk actually has: a wide drawing uses a landscape screen fully.
Positions: where the logo and buttons go
The welcome screen is split into three zones. On a portrait screen they are Top, Middle and Bottom; on a landscape screen Left, Centre and Right. The logo, the Start button and the language button each go in one zone; things in the same zone stack, logo first. Zones with nothing in them are free for the animation.
You choose the positions when you add the animation, and can change them any time in QR Menu → Kiosk. So tell the AI which zones to keep clear: for "logo at the top, buttons at the bottom" the subject belongs in the middle; for "everything on the left" of a landscape screen, keep the left third of the drawing quiet and put the action on the right.
Two layouts
Subject. A single thing, such as a dish, a drink or your mascot, on a transparent background. The kiosk fits it into the free zones, as large as they allow. If no zone is free, it sits behind the middle zone.
Full screen. A scene or pattern that fills the whole screen behind the logo and buttons, which get a soft shade so they stay readable. The kiosk scales the drawing to cover the screen and crops what does not fit, so keep anything that matters away from the edges. A square drawing loses the most: on both screen shapes only its central 56% is sure to show (560 × 560 of a 1000 × 1000 canvas). A wide or tall drawing made for one screen shape loses very little.
Colours
The kiosk tells the animation its five colours, the ones you set under QR Menu → Kiosk → Colours:
| Variable | Colour |
|---|---|
--kiosk-bg | background |
--kiosk-title | titles |
--kiosk-text | body text |
--kiosk-small | small text |
--kiosk-accent | accent (buttons, highlights) |
Use them for anything that should follow your branding, and keep natural colours
for food. Always give a fallback colour, so the file also looks right when you
open it on its own: var(--kiosk-accent, #c8553d).
If the Start button is hidden
You can hide the Start button. A tap anywhere still starts an order, but nothing on screen says so, so your animation should invite guests to tap: a pointing hand, a pulsing ring, or words such as "Tap to order".
Specification
These are the rules a file must follow. The back office checks all of them except the timing rules (durations that divide the loop, no positive delays) and the performance rules, which are up to you. A file that breaks a checked rule is refused with a list of the problems; nothing is removed or fixed for you.
The file
- One SVG file (
<svg xmlns="http://www.w3.org/2000/svg" …>), at most 500 KB. - At most 5,000 elements, nested at most 256 deep.
- A
viewBoxthat is square (0 0 1000 1000, for landscape and portrait screens), wide (at least 1.6 : 1, such as0 0 1600 1000, landscape only) or tall (at least 1 : 1.6, such as0 0 1000 1600, portrait only). Width and height are optional; the kiosk sizes it.
Root attributes
All on the <svg> element:
| Attribute | Required | Value |
|---|---|---|
data-kiosk-layout | yes | subject (transparent background) or fullscreen (paint the whole canvas; keep what matters away from the edges) |
data-kiosk-loop | yes | the loop length in seconds, a plain number from 2 to 60 without a unit, such as 4 or 7.5 |
data-kiosk-still | no | the second of the loop to show as a still picture when the tablet is set to reduce motion; from 0 up to (not including) the loop length; default 0. Pick a moment where the picture looks complete. |
Timing
The kiosk sets every animation in the file to the same point in the loop, so that kiosks side by side play in step. For that to work:
- Every CSS animation's duration is
data-kiosk-loopor a length that fits into it a whole number of times, and it repeats forever:animation: rise 4s ease-in-out infinitefor a 4-second loop, or2sfor something that happens twice in each loop. - Every SMIL animation (
<animate>,<animateTransform>,<animateMotion>,<set>) has adurequal to the loop or a length that divides it evenly, andrepeatCount="indefinite". - To make things happen at different moments, use keyframe percentages
(
40% { … }), or a negativeanimation-delay(-1.5s) to shift a copy of the same animation. Never a positive delay. - The end of the loop must match its start, so it repeats without a jump.
- A CSS
transformanimation replaces the element's owntransform="…"attribute. Animate a plain<g>and put any fixed transform on an element inside it.
Colours
- Use the five variables
--kiosk-bg,--kiosk-title,--kiosk-text,--kiosk-smalland--kiosk-accent, each with a fallback colour:var(--kiosk-bg, #fff8f0). - Write them in CSS, in a
<style>element or astyle="…"attribute, not infill="…"orstroke="…"attributes.
Allowed elements
svg, g, defs, symbol, use, path, circle, ellipse, rect,
line, polyline, polygon, text, tspan, linearGradient,
radialGradient, stop, clipPath, mask, pattern, filter,
feGaussianBlur, feOffset, feFlood, feComposite, feMerge,
feMergeNode, feColorMatrix, feDropShadow, image, style, title,
desc, animate, animateTransform, animateMotion, set, mpath.
Any other element is refused. Use ordinary presentation, geometry, text,
gradient, filter and animation attributes; id, class, style, role, aria-… and data-…
attributes are fine (tabindex is not).
Not allowed
- Scripts,
<foreignObject>, links (<a>), and any element not in the list above. - Event attributes: anything starting with
on, such asonclickoronload. - References to anything outside the file.
hrefandxlink:hrefmay only point at anidin the same file (href="#leaf"). In CSS and attributes, aurl(…)may only point at anidin the same file (url(#glow)). - Pictures (
<image>) only as an embedded PNG, JPEG or WebP:href="data:image/png;base64,…". Not SVG, not GIF, not a web address. - In CSS: no
@import, no@font-face, noimage-set,image,src,cross-fadeorexpressionfunctions, and no backslash escapes (\). - No elements inside
<style>; only CSS text (aCDATAsection is fine). - No
<!ENTITY …>declarations. - Fonts: no web fonts. Use generic families such as
sans-serif,seriforsystem-ui. - The check is cautious and reads all text in the file, titles and visible
words included. Do not write
url(,image(,src(,@import,@font-faceor a backslash anywhere, even in a<title>, in visible text or in a CSS comment.
Keep it smooth on kiosk tablets
Kiosk tablets have little graphics memory. Each moving group is kept as its own picture, and only the part near the screen is ready to draw. If big pieces jump far at the moment the loop restarts, the tablet must redraw several screens at once and the screen flashes. Follow these rules:
- Keep every moving group small. Any element or
<g>that has an animation must fit within 1.5 times the canvas in each direction (at most 1500 × 1500 on a0 0 1000 1000canvas), including all its children. Never build one long strip (2, 3 or 4 screens wide or tall) and slide it across the screen. - Keep moves short. No moving group may move more than half the canvas (500 units) in one animation cycle. For endless motion, such as a scrolling row of trees, falling snow or drifting clouds, draw a pattern that repeats every P units (P at most 500, for example trees every 250 units), make the group just wide or tall enough to cover the canvas plus one repeat (canvas + P), and move it by exactly P per cycle. At the end of each cycle it looks identical to the start, so the jump back is invisible and cheap.
- Animations may be shorter than the loop, as long as they fit into it a
whole number of times. With
data-kiosk-loop="60", the allowed durations are 60, 30, 20, 15, 12, 10, 6, 5, 4, 3 and 2 seconds (all withinfinite). Use this for fast motion: snow that falls 250 units every 6 s instead of 3000 units every 60 s. Never use a duration that does not divide the loop. - Prefer many small moving things over a few huge ones. Dozens of small shapes (snowflakes, leaves, toppings) are fine; avoid more than 4 moving groups that are each larger than the canvas.
- Static scenery (sky, ground, a still background) can be any size and does not count against these rules, as long as it does not move.
Before answering, check every moving group against rules 1 to 3: its size (width and height including children), its travel per cycle, and that its duration divides the loop.
Good to know
- Keep it light: a few KB to a few hundred KB. Shapes and gradients are smaller and sharper than embedded pictures.
- Test it by opening the
.svgfile in a web browser. It should loop smoothly.
Worked example
A subject, looping every 4 seconds: a cup that gently bobs while steam rises. The cup follows the kiosk's accent colour, the steam its small-text colour.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"
data-kiosk-layout="subject" data-kiosk-loop="4" data-kiosk-still="1">
<title>A steaming cup of coffee</title>
<style>
.cup { fill: var(--kiosk-accent, #c8553d); }
.handle { fill: none; stroke: var(--kiosk-accent, #c8553d); stroke-width: 16; }
.shadow { fill: var(--kiosk-text, #3b2f2a); opacity: 0.15; }
.coffee { fill: #5a3825; }
.steam { fill: none; stroke: var(--kiosk-small, #9a8f85); stroke-width: 10;
stroke-linecap: round; opacity: 0;
animation: rise 4s ease-in-out infinite; }
.s2 { animation-delay: -1.3s; }
.s3 { animation-delay: -2.7s; }
.bob { animation: bob 4s ease-in-out infinite; }
@keyframes rise {
0% { opacity: 0; transform: translateY(30px); }
30% { opacity: 0.9; }
100% { opacity: 0; transform: translateY(-40px); }
}
@keyframes bob {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
</style>
<ellipse class="shadow" cx="200" cy="340" rx="130" ry="20"/>
<g class="bob">
<path class="cup" d="M110 200 h180 v60 a70 70 0 0 1 -70 70 h-40 a70 70 0 0 1 -70 -70 z"/>
<path class="handle" d="M290 220 a35 35 0 0 1 0 70"/>
<ellipse class="coffee" cx="200" cy="200" rx="90" ry="14"/>
</g>
<path class="steam" d="M160 170 c-20 -25 20 -45 0 -75"/>
<path class="steam s2" d="M200 160 c-20 -25 20 -45 0 -75"/>
<path class="steam s3" d="M240 170 c-20 -25 20 -45 0 -75"/>
</svg>
Every animation lasts 4 s, the same as data-kiosk-loop. The three wisps share
one animation and are shifted with negative delays. Each animation ends where it
starts, so the loop has no jump.