Skip to main content
Back to discovery

Live preview recorded from Bakai Lab; experiment and demo by Bakai Tolondu uulu. Preview: platform recorded · rights authorized.

ComponentDemo Only

Charts

A membership analytics card with animated totals, chart transitions, and selectable time ranges.

LSource LandLab - Bakai Tolondu uulu

Why it stands out

A membership analytics card with animated totals, chart transitions, and selectable time ranges.

Prompt

Build a members-growth line chart rendered as an animated field of small square tiles instead of a solid area fill. A light-gray page #ECEEF1 holds a column of max-width 500px. Inside, a #FAFAFB tray (14px radius, 6px padding, 6px gap) with a KPI card row on top and a white chart card below, both 10px radius and shadow 0 0 1.76px rgba(0,0,0,0.08), 0 1px 1.76px rgba(25,28,33,0.06), 0 0 0 1px rgba(25,28,33,0.04). The chart card has 16px padding.

Render exactly ONE KPI card, "New members" (the component supports three tabs sharing one curve, members, revenue, check-ins, but only members shows here). It is a raised white button: a 13px icon in #8A90A0, a 12.5px weight 500 label at -0.006em in #171717, a hero number at clamp(21px,2.9vw,27px) weight 600 at -0.015em in #171717 formatted "+1,234" with toLocaleString, and a 12px weight 500 delta reading "↑ 12%" in #2563EB (or "↓ N%" in #6B7280 if negative). The hero number is not an odometer, it is one continuous spring (stiffness 190, damping 27, mass 0.7) that retargets from wherever it sits and writes straight to the DOM text, tabular figures, jumping instantly under reduced motion.

Chart card: a 30px y-axis on the left with 4 ticks at fractions 1, 0.66, 0.33, 0 of the current max, 10px weight 400 #9AA0A6, tabular numerals. The plot is clamp(160px, 22vh, 194px) tall with a faint diagonal hatch behind everything (repeating-linear-gradient(-45deg, rgba(79,96,132,0.04) 0 1px, transparent 1px 7px)), plus 4 horizontal gridlines on the y-ticks, the zero baseline solid 1.5px #E7E9EE, the rest 1px dashed rgba(120,130,150,0.18). Below the plot, 5 evenly spaced date labels, 10px weight 400 #5F5F6F.

Data: a members series whose length equals the selected range, 7, 14, 30, or 90 days, chosen with a segmented pill selector below the card (track #F3F4F6, 9px radius, 3px padding, active white pill sliding on a spring, duration 0.32, bounce 0.2). Generate day i deterministically (no Math.random or Date.now, it must hydrate identically): t = i / (days - 1), base = 9 + t * 23, wave = 6 * sin(i * 0.7 + 1) + 3 * sin(i * 1.9), value = max(3, round(base + wave)). Label each day with its calendar date counting back from a fixed anchor.

Tile engine on a canvas, devicePixelRatio-aware capped at 2x, imageSmoothingEnabled false for crisp squares. Cell size = max(3, round(canvas width / 180)). For each grid column, sample the curve with smoothstep interpolation at that x fraction, normalize by the current max, and fill every cell from that column's curve height down to the floor (a filled area, not just an edge line), leaving 16% headroom above the tallest point. Every cell always paints a faint rest tile, oklch(0.9 0.02 264), and cells nearer the curve also paint a larger (up to 70% of the cell), more saturated blue tile in the same hue-264 family (roughly #2563EB), with a barely visible traveling shimmer (a sine wave moving top to bottom at about plus or minus 7% modulation). Add a cursor-follow glow: track the pointer globally, smooth it by lerping 45% per frame toward the raw position, and light tiles within a speed-dependent radius (24% to 50% of plot height), rising fast (22% per frame) and decaying slow (5% per frame); about 6% of tiles are sparks that jitter in place instead of glowing steady.

When the KPI or range changes, do NOT remount the canvas: interpolate the whole field from its current curve and current max to the new curve and new max linearly over 460ms, rebuilding which cells are on every frame from the blended values, so the shape reflows and the vertical scale re-zooms rather than cutting.

Scrubber: overlay a full-bleed pointer layer on the plot. On pointer down or move, find the nearest day by rounding (pointerX - plot left) / plot width * (n - 1), then spring a marker's x (percent across) and y (percent down, using the same 16% headroom as the tiles) to that day using ONE spring config (stiffness 650, damping 42, mass 0.5) on BOTH axes, so an 11px round #2563EB marker with a 2px white ring and shadow 0 1px 5px rgba(15,23,42,0.28) chases the pointer without lag. Show a 1px vertical crosshair rgba(37,99,235,0.28) and a floating white readout above the marker (border #E5E7EB, 10px radius, shadow 0 6px 20px -6px rgba(15,23,42,0.22), padding 7px 11px) with the date at 11px weight 500 #6B7280 and the value at 14px weight 600 #171717, both fading in and out over 160 to 180ms ease-out.

On first mount only, wipe the plot in with a left-to-right clip-path reveal (inset(0 100% 0 0) to inset(0 0% 0 0)) plus blur(9px) to blur(0px) and opacity 0 to 1 over 500ms on cubic-bezier(0.19,1,0.22,1). Use Inter throughout and honour prefers-reduced-motion (disable the springs, shimmer, and glow, jump to final values).

Discovery vocabulary

Related by governed terms

Continue comparing

More from Lab - Bakai Tolondu uulu