Design Lounge
Install

Nº 576 of 605

Cozy farm HUD

A farming-sim HUD over a painterly SVG field: a stitched day clock with a moving sun, an energy bar, a wooden hotbar, and a quest note pinned like paper.

Preview

Open full size
1280 × 800 · 19.8 KB · 210 lines

Use it

Free to use · credit appreciated

1 Once, in your project · Node 22.20+

npx skills add SusanAcharya/Design-Lounge

2 Then ask

Using the Design Lounge skill, build "Cozy farm HUD" (piece game-cozy-farm-hud) in my stack. Match its brief; restyle it onto my product's theme.

No skill? Paste the brief instead. It carries the numbers, tokens and behaviour.

Brief

190 lines

Build brief for a coding agent. Rebuild this piece in the reader’s stack. If they haven’t said which stack, ask once, then default to semantic HTML + CSS + a little vanilla JS. Match the numbers below; don’t “improve” them.

What it is

The in-game HUD of a cozy farming game, laid over a hand-made afternoon scene: rolling hills, a red barn, a sandy path, a fence and eight turnip beds, all drawn in SVG and pushed through a turbulence displacement filter so every edge wobbles like gouache. The HUD is four soft objects: a cream day card with a stitched inner border and a tiny dial where the sun travels an arc, an energy pill with a leaf, a wooden hotbar of ten tool slots, and a quest note on ruled paper, pinned with a red pin and torn along the bottom. You can actually play it: pick the watering can and click the dry beds. The detail worth copying is the stitched border (a dashed line 6px inside a 22px-radius card), which makes flat UI read as sewn and friendly without a single texture image.

Reference behaviour

  1. Initial state: Spring 14, Thursday, 2:40 pm. Slot 1 (watering can) is selected and raised 8px; the tag above the hotbar reads “Watering can” with a water gauge at 18 / 40. Energy 72 / 120. Five of eight beds are dark (watered), three are light (dry). The note’s first task reads “Water the turnip beds (5 of 8)”; the second task is already ticked and struck through.
  2. Click a slot or press 1 to 9, 0: that slot rises 8px with a springy 220ms ease and gains a 3px ink ring; the tag text changes (for seeds: “Turnip seeds · 24 left”). Slot 0 is empty and disabled.
  3. With the watering can, click or press Enter on a dry bed: three drops fall into it (700ms), the soil darkens over 600ms, water −1, energy −2 (bar animates 400ms), and the task count goes up by one.
  4. Watering the eighth bed ticks the task with a springy check and strikes it through; a paper hint pops above the hotbar: “All eight beds watered. Granny Odile will be pleased.”
  5. Clicking a bed with any other tool, a watered bed, or with an empty can shows a hint bubble that explains why, for 2.2s.
  6. The clock advances 10 game minutes every 4 real seconds until 8:00 pm; the sun dot moves along the dial’s arc (6 am on the left horizon, 8 pm on the right).
  7. Ambient: two clouds drift 60px over 60s, two grass sprigs sway 3° over 5s. Nothing else loops.

Structure

1280 × 800, scene full bleed (SVG 1280 × 800, xMidYMax slice)
┌──────────────────────────────────────────────────────────────────────────┐
│┌ day card 28,24 ───────────┐                        ● pin               │
││ (dial 78) Spring 14        │                  ┌ note 300 wide, 2.2° ──┐ │
││           Thursday · 2:40  │      sun          │ Granny Odile's list    │ │
││           [Clear 19°][1,286 g]                 │ ☐ Water beds (5 of 8)  │ │
│└────────────────────────────┘                  │ ☑ Feed the hens        │ │
│┌ energy 28,152 ────────────┐                   │ ☐ Take 3 honey jars    │ │
││ (leaf) ENERGY ▓▓▓▓░░ 72/120│                   │ Reward …               │ │
│└────────────────────────────┘                  └╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱┘ │
│   barn   tree   hay          fence ─────────              tree           │
│      path                    [bed][bed][bed][bed]   (row 1, y 508)        │
│                             [bed][bed][bed][bed]    (row 2, y 588)        │
│                   ( Watering can ▬▬▬ 18 / 40 )                           │
│          ┌ hotbar: 10 × 60px slots, gap 6, wood 8px padding ┐            │
└──────────────────────────────────────────────────────────────────────────┘
  • <svg class="scene">: sky is the body gradient; the SVG holds sun glow, clouds, three hill bands, barn, trees, hay, path, fence, the light field, the <g id="plots"> of 8 bed groups (role="button", tabindex="0"), sprigs and flowers. One filter#rough (feTurbulence 0.035, 2 octaves, displacement 7) on the land and clouds; the beds are not filtered so they stay crisp and clickable.
  • <svg class="grain">: full-size turbulence noise at 22% opacity, mix-blend-mode:multiply.
  • <section class="card clock">, <section class="card energy">, <section class="note"> plus a separate .pin.
  • .bar: the .tag pill above a role="toolbar" of 10 <button class="slot">.
  • .hint (role="status") floats 150px above the bottom.

Tokens

:root {
  --sky-1: #a6d0dc;   /* sky top */
  --sky-2: #f4e4c4;   /* horizon haze; body ends at #e9d3a6 */
  --paper: #fff8ea;   /* note, hint bubble */
  --card: #fbf0d9;    /* HUD cards */
  --stitch: #d8bf93;  /* dashed inner border */
  --ink: #4a3324;     /* primary text, selected ring, tag fill */
  --ink-2: #6e5340;   /* secondary text, checkbox stroke */
  --ink-3: #7f6450;   /* labels, struck tasks */
  --wood: #8a5d3b;    /* hotbar */
  --wood-2: #a77650;  /* hotbar top highlight */
  --wood-dark: #5e3c24; /* hotbar bottom lip */
  --slot: #f6e7c8;    /* slot face */
  --leaf: #5f8f3e;    /* energy, ticks */
  --leaf-2: #86b35a;  /* energy highlight, turnip leaves */
  --water: #2c6a94;   /* task count, focus ring */
  --pin: #c9513a;
  --soil: #b98a5e;    /* dry bed */
  --soil-wet: #7b5638;/* watered bed */
  --font: "Baloo 2", ui-rounded, sans-serif;
  --r: 22px;          /* card radius; slots 14px, hotbar 20px, pills 99px */
  --card-shadow: 0 2px 0 #d9c29a, 0 10px 24px rgba(94,60,36,.18);
  --ease: cubic-bezier(.2,.7,.2,1);
  --spring: cubic-bezier(.34,1.56,.64,1);
}

Typography

One family, Baloo 2, at four weights.

RoleSizeWeightLine-heightTrackingNotes
Day (“Spring 14”)30px8001−.01em
Note heading22px8001.20
Time line17px6001.20--ink-2
Task line16px60030px0sits on the 30px ruling
Tag, hint, energy value15px7001.3 to 1.40
Chips, from line, reward14px600 to 7001.3 to 1.50
Energy label13px6001.08emupper
Slot key number / count12 / 13px700 / 8001.30

Motion

ElementTriggerPropertyFrom → ToDurationEasing
SlotselectedtranslateY0 → −8px220ms--spring
Bed soilwateredfill--soil → --soil-wet600ms--ease
Dropswateredopacity, translateY0, −14 → 1 → 0, 8px700ms--ease
Energy barspentwidthold → new400ms--ease
Water gaugespentwidthold → new300ms--ease
Check marktask donescale, opacity.4, 0 → 1, 1300ms--spring
Hintshownopacity, translateY0, 8 → 1, 0200 / 300ms--ease / --spring
CloudsalwaystranslateX0 → 60px60s alternatelinear (ambient only)
Sprigsalwaysrotate0 → 3°5s alternateease-in-out
Sun dotclock tickcx, cyalong arcinstant, every 4s

Reduced motion: drop the clouds, sprigs and drops, make every transition 1ms. Watering, ticks and the clock still work.

States

  • Slot hover: face lightens to #fff4dc.
  • Slot selected: aria-pressed="true", raised 8px, face #fffaf0, 3px --ink ring.
  • Slot empty: sunken #d8bd92 with an inner top shadow, disabled.
  • Bed hover: 3px --paper stroke. Bed focus-visible: 4px --water stroke.
  • Task done: green tick in a slightly wonky 20px box (radii 5 7 4 6px), text struck with a 2px line in --ink-3.
  • Focus-visible (HTML): 3px --water outline, 3px offset.

Accessibility

  • Hotbar is role="toolbar" with aria-label="Hotbar, keys 1 to 0"; each slot is a button with aria-pressed and a label that includes the stack count (“Turnip seeds, 24”).
  • Number keys 1 to 9 and 0 pick slots anywhere on the page.
  • Beds are focusable SVG groups with role="button"; Enter and Space water them; their label flips “dry” to “watered”.
  • Energy is role="meter" with aria-valuenow kept in sync.
  • The hint bubble is role="status", so refusals and the completion line are announced.
  • The clock text is not a live region (it would chatter every 4s).
  • Contrast: --ink on --card 10.4:1, --ink-2 6.2:1, --ink-3 4.8:1, --water on --paper 5.5:1; --paper on --ink tag 11.1:1. Slot key numbers use --ink-2, because --ink-3 falls to 4.5:1 on the slot face.

Responsive rules

  • ≥ 1280: as drawn. The scene uses xMidYMax slice, so wider screens add sky and side field, not stretch.
  • 1024 to 1279: unchanged; the note’s 300px width and the 640px hotbar still fit.
  • 820 and below: the page may scroll vertically (min-height 844px). The scene shrinks to 640px tall and anchors right (xMaxYMax slice, set from JS on a media query) so the beds stay in view. The day card and energy pill sit at 12px insets; the note shrinks to its heading and first task at 1° tilt; the hotbar wraps into two rows of five with slots calc((100vw - 64px) / 5), max 60px.

Acceptance checklist

Always

  • Every HUD card has a 22px radius, a two-part shadow and a 2px dashed stitch 6px inside.
  • The scene is all SVG with one displacement filter on the land; interactive objects stay unfiltered.
  • One hotbar slot is always selected, raised 8px with a spring curve; number keys select slots.
  • The tool tag above the hotbar reflects the selected tool and its resource.
  • Using the right tool on a valid target changes the world, the resource, energy and the quest count together.
  • Every refusal explains itself in a hint bubble that is a live region.
  • The note is ruled at 30px, tilted, pinned, and torn along the bottom with a polygon clip.
  • Ambient loops are slow (5s and 60s) and stop under reduced motion.
  • At 390 wide nothing scrolls sideways and the beds remain visible above the hotbar.

This demo

  • Spring 14, Thursday, 2:40 pm; Clear, 19°; 1,286 g.
  • Energy 72 / 120, water 18 / 40, beds 5 of 8 watered, 24 seeds, 5 apples.
  • Note reads “Granny Odile’s list” with the reward “rhubarb pie and 120 g”.
  • Baloo 2 is the only family.

Implementation notes

The stitch. A pseudo-element 6px inside, radius 6px smaller, so the dash follows the corner:

.card{background:var(--card);border-radius:var(--r);position:relative;
  box-shadow:0 2px 0 #d9c29a,0 10px 24px rgba(94,60,36,.18)}
.card::after{content:"";position:absolute;inset:6px;border:2px dashed var(--stitch);
  border-radius:calc(var(--r) - 6px);pointer-events:none}

Painterly edges without images. Displace the land with noise, and draw shapes past the viewBox so the wobble never pulls transparent pixels in at the frame edge. Give the filter a generous region, or soft shapes get a flat cut:

<filter id="rough" x="-20%" y="-60%" width="140%" height="220%">
  <feTurbulence type="fractalNoise" baseFrequency=".035" numOctaves="2" seed="4"/>
  <feDisplacementMap in="SourceGraphic" scale="7"/>
</filter>
<path d="M-40 452C200 400 … 1320 425V860H-40z" fill="#9cb67a" filter="url(#rough)"/>

CSS transforms overwrite SVG transform attributes. Put the position on an outer <g transform> and the animation on an inner <g class="sway"> with transform-box: fill-box; transform-origin: 50% 100%, or the sprig jumps to the origin.

The sun’s arc. Map 6 am to 8 pm onto π to 0 and place the dot on a 28px radius around the dial’s horizon point (40, 46):

const a = Math.PI * (1 - (mins - 360) / 840);
dot.setAttribute('cx', 40 + 28 * Math.cos(a));
dot.setAttribute('cy', 46 - 28 * Math.sin(a));

Common mistakes: an SVG without width and height inside inset:0 (it renders at 300 by 150); filtering the clickable beds (hit areas wobble); a clock live region that speaks every tick.

Details

Palette
Type
Baloo 2
Motion
Subtle motion
Build
One session
Designed bySusan AcharyaKathmandu

Studied

UseArticle

A control. It studies this site for quiet, not for a show.

All sources