Innehållssamlare
Why Accessibility Is An Operational Capability, Not A Feature
This article is a sponsored by Level Access
We know that right now, a senior engineer is shipping a checkout flow they “built” in a single afternoon. AI assistant does the heavy lifting, happy path runs clean, and a rotating chevron spins on the order summary. Two weeks later, engineering gets a notice from customer support: a blind customer using a screen reader can’t complete the purchase because the “Pay Now” control is a <div> with a click handler. No role. Not focusable. Not working.
That gap — between code that runs and a product people can actually use — is becoming one of the defining engineering challenges of the AI era. Teams can generate UI faster than ever, but they still have to guarantee that what they ship is usable, secure, and maintainable.
Accessibility sits right in the middle of that problem.
This is not an article about compliance checklists or end-of-project audits. It’s about engineering systems. Specifically, why accessibility should be treated as an operational capability — alongside privacy, security, reliability, and observability — and what that looks like in practice.
The Audit TrapFor years, the default way to “do” accessibility was the one-time, audit-only approach: hire a firm, get a list of 200 findings, fix some of them, file the report. A lot of teams have now moved beyond this model — and the reason is worth looking into.
Audits do matter. For sales, procurement, governance — they’re essential. When a buyer asks for a VPAT or an ACR, you need one. When legal asks if you’re meeting requirements, you need documentation. Audits serve those purposes well.
But audits don’t help you build accessible features during sprint planning. Audits can cost points during a sprint. They don’t catch problems before merge requests. They don’t scale with deployment velocity. The mistake, essentially, is tackling accessibility as a snapshot when you really need constant monitoring. Six months after the audit, the product has shipped dozens of releases, multiple new features, and a redesigned nav. The report is now fiction. Compliance is not a state you reach — it’s a state you maintain, and complexity fights you the whole way.
The WebAIM Million report, which scans the top one million home pages every year, found that 95.9% of pages had detectable WCAG failures in its 2026 run, with an average of 56.1 errors per page. The number of page elements jumped more than 20% in a single year, likely driven by AI-enabled development and 'vibe coding’ — and more elements mean more places to break. Accessibility debt behaves exactly like technical debt: every inaccessible component you ship becomes a future remediation project, and the interest compounds.
Any strategy that treats accessibility as a periodic event rather than a continuous property of the system is going to lose.
The AI Problem Nobody Wants To NameWith the scale at which teams now generate UI, the gap doesn’t just persist; it multiplies.
Start with how fast this arrived. In February 2025, Andrej Karpathy coined “vibe coding” — a way of working where you "fully give in to the vibes" and "forget that the code even exists". You describe intent, the model generates, you accept the diffs without reading them. It was meant for weekend projects. It did not stay there. Y Combinator reported that 25% of its Winter 2025 batch had codebases that were 95% AI-generated.
Models don’t land on non-semantic markup by accident — three forces push them there. Most React code on GitHub uses non-semantic “soup”, so that’s what the models learn. Human reviewers and evaluators judge output visually, so the feedback loop rewards looks, not semantics. And <div onClick> is fewer tokens than <button aria-expanded="true" ...>, so absent a constraint, the model takes the cheap path.
Here’s the thing about AI-generated UI: it’s inaccessible by default. Not occasionally — by default. A developer writing in Frontend Masters tested AI-generated React components across multiple tools and documented the pattern. A typical AI-generated sidebar had ten distinct accessibility failures in twenty-nine lines: no landmark, no heading, no list structure, elements with click handlers instead of buttons, no aria-expanded, no keyboard handling, and unlabeled icons. The accessibility tree — the structure screen readers actually read — came back as flat, unstructured text. “Same pixels” as the author put it. “One is a door. The other is a painting of a door”.
Now connect this to security, because the two failures come from the same root. Veracode’s 2025 GenAI Code Security Report tested large language models across dozens of coding tasks and found that a large fraction of AI-generated code introduced security vulnerabilities — including OWASP Top 10 flaws. Cross-site scripting failures were particularly common, and security performance did not meaningfully improve with newer, larger models. The issue wasn’t model intelligence. It was process: developers generating code without specifying security constraints and accepting output without systematic verification.
The same shortcut that skips the security review skips the accessibility review. At scale, AI won’t close the accessibility gap — it has industrialized the very thing that creates it.
The fix is not to ban AI. Your developers are already using it. The fix is to constrain it and verify it — to treat AI as a very fast teammate who always needs guardrails.
Velocity and Accessibility Are Not EnemiesThis is usually where someone says, “Guardrails? Sounds great, but they will slow us down.”
In practice, the opposite tends to be true.
Shift-left is the entire DevOps thesis, and it applies cleanly here. An accessibility issue caught during design review is a comment. The same issue found in production is a remediation project.
Catching an accessibility issue as a component is built takes minutes. Fixing one after the fact — discovering it in an audit, diagnosing the root cause, restructuring the markup, applying the necessary fix, writing tests — can easily take hours. Multiply that across hundreds of findings from a late-stage audit, and you have weeks of unplanned work that earlier automated checks — whether in design reviews, development workflows, or CI — could have prevented.
Teams that integrate accessibility into everyday workflows avoid the expensive surprises: emergency audits, remediation sprints, procurement blockers, and redesigns that quietly break core user journeys. Accessibility doesn’t reduce velocity. Unexpected work reduces velocity. In-flow accessibility is one way of eliminating unexpected work.
What Enterprise-Ready Actually Looks LikeThe organizations that scale accessibility successfully do not rely on heroes. They rely on systems.
The highest-leverage place to start is the design system. One accessible component can be reused thousands of times. The GOV.UK Design System is a useful example: components undergo both automated and manual testing using assistive technologies such as JAWS, NVDA, VoiceOver, and TalkBack. The team is explicit about the limits of automation and supplements tooling with user testing involving people with disabilities. They’re equally clear that using the design system doesn’t “magically” make a service accessible; it just gives you a higher starting point.
Accessibility becomes infrastructure. That’s the lesson.
From there, it moves into the engineering workflow:
- Accessibility requirements are included in the Definition of Done.
- Pull request reviews include explicit accessibility checks.
- Interactive controls use semantic elements (<button>, <a>) by default.
- Keyboard navigation and focus management are treated as standard engineering concerns, not optional polish.
Finally, accessibility becomes enforceable through automation:
- eslint-plugin-jsx-a11y catches common issues before code is committed.
- LevelCI, Pa11y, and similar tools provide automated testing in CI/CD pipelines.
- @storybook/addon-a11y surfaces issues during component development.
At that point, accessibility stops depending on memory and starts depending on the process. It becomes part of your platform.
Patterns That Actually ScaleA few implementation patterns consistently show up in teams that do this well.
Constrain AI Before It GeneratesInstead of fixing accessibility after generation, bake requirements directly into tooling through Cursor rules, Copilot instructions, or repository-level standards. Tell the model to use semantic HTML. Tell it when to use buttons versus links. Tell it to expose the state and labels correctly. Models follow persistent constraints far more reliably than one-off prompts.
Stop Hand-Rolling Complex WidgetsComboboxes, menus, tabs, modals, and similar controls routinely become accessibility hotspots. Libraries such as Radix UI, React Aria, and Headless UI already solve many of these problems. The scalable approach is not about repeatedly implementing accessibility correctly. It’s inheriting accessible behavior from well-tested primitives.
Capture Accessibility During Design HandoffFocus order, labels, heading hierarchy, and interaction states should be specified before implementation begins. If accessibility requirements are absent from the design artifact, they are often absent from the final product. A simple memo at design handoff — what is the tab order, what are the labels, what happens on error — removes a huge amount of guesswork later.
None of these patterns is exotic. They’re just DevOps and platform thinking applied to accessibility.
The Broader Business ImpactEngineering leaders rarely prioritize accessibility solely because of regulations. But regulations, procurement requirements, user retention, and product quality all point in the same direction.
Legal pressure continues to increase. Digital accessibility lawsuits in the United States have stayed in the thousands per year, and they are not limited to large enterprises. The European Accessibility Act is now enforceable across the EU, applying to e‑commerce, banking, ticketing, telecoms, and more, regardless of where the company is headquartered. The message is clear: accessibility is no longer a “nice-to-have” in the eyes of regulators.
But compliance is only part of the story. The bigger story is the market you leave on the table. The World Economic Forum (December 2023) estimates that the world’s 1.3 billion people with disabilities, “along with their friends and family, has a spending power of $13 trillion”; disabled consumers alone control roughly $8 trillion in annual disposable income, per the Valuable 500.
In the UK alone, the Click-Away Pound Report 2019 found the “Click-Away Pound has risen to £17.1 billion” — more than 4.9 million users with access needs who abandon inaccessible sites and spend elsewhere, up almost 45% from £11.75 billion in 2016. People don’t file a bug report. They leave and buy from a competitor.
There is also a procurement reality that turns accessibility from a cost into a moat. If you sell B2B or to government, you will increasingly be asked for proof of accessibility — VPATs/ACRs or equivalent documentation. According to Level Access’s Seventh Annual State of Digital Accessibility Report, 75% of organizations now require proof of accessibility at least most of the time when purchasing digital products — essentially unchanged from 74% in the previous report, but with a notable shift towards stricter enforcement, as those that always require it rose from 27% to 31%. A strong ACR accelerates the sales cycle; a weak one, or none at all, creates redlines that stall or kill it. For some buyers, this is a hard requirement before your product can even enter evaluation. A strong accessibility story accelerates the sales cycle. A weak one creates redlines that stall or kill it.
Step back and the deeper pattern is clear: accessibility is a proxy for engineering maturity. A team that ships semantic HTML, manages focus, exposes state correctly, and tests it in CI is a team that has its house in order. The same discipline that produces an accessible component produces a maintainable, testable, less buggy one.
For dev and product leaders, that’s the real business case: accessibility work is platform work. It pays off every time a feature ships faster and more smoothly, with less rework, than it otherwise would have.
Systems, Not SprintsIf you take one thing from this, make it this: accessibility doesn’t come from an audit, a hero, or a heroic remediation sprint before launch. It comes from systems.
An accessible design system so components start right. A Definition of Done so they stay right. Automated testing and CI gates so regressions fail the build. Governance, so someone owns it. Guardrails for AI-assisted development so your fastest tool stops being your biggest liability.
None of those practices is particularly glamorous. That’s exactly why they work. They’re the same kinds of boring, reliable systems you already trust for security, reliability, and performance.
But there’s one thing no tool on that list can do. No linter, no automated scanner run, no dashboard will ever tell you what it’s actually like to use your product as a blind person with a screen reader, or to navigate your checkout with a keyboard because a tremor makes a mouse inoperable. So build the systems — you need them, and they’re the only way accessibility survives contact with a real release schedule. But test with real users with disabilities regularly. The first time you sit behind someone using JAWS to fight through a form your team thought was “done”, something changes. The tooling tells you whether you passed. A real person tells you whether it actually works.
Accessibility is not a feature. It’s an operational capability. Treat it that way, and you get something dev and product leaders already care about: a faster, safer, more reliable way to ship software.
Snapshots Of Summer (July 2026 Wallpapers Edition)
The scent of rain after a hot day, watching the moon rise on a summer night’s sky, or going for a swim in a nearby lake — July is full of small, distinctive moments that can quietly spark new inspiration. So, why not bring a bit of that summer joy to your desktop, too, this month?
For this post, artists and designers from across the globe once again tickled their creativity and designed desktop wallpapers that capture that very special July feeling, just as it has been a monthly tradition here at Smashing Magazine for more than 15 years already. You’ll find their creations compiled below, along with a selection of summery favorites from our wallpapers archives that are just too good to be forgotten.
A huge thank-you to everyone who shared their designs with us this month — this post wouldn’t be possible without your wonderful support! If you too would like to get featured in one of our upcoming wallpapers posts, please don’t hesitate to join in. We can’t wait to see your story come to life! Happy July!
- You can click on every image to see a larger preview.
- We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.
“There is a quiet, hypnotic rhythm that exists just beneath the surface of our busy lives. When we slow down enough to notice, we see that the universe moves in beautiful, repeating circles — in the way light filters through water, how leaves dance as they fall, and how we are drawn together in moments of shared peace. True balance isn't about standing perfectly still; it is a fluid, continuous motion.” — Designed by PopArt Studio from Novi Sad, Serbia.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Vincent van Gogh’s sunflowers are among my favorite paintings, and I’ve designed a papercraft version loosely inspired by them. A perfect theme for the beginning of summer.” — Designed by Caroline Boire from France.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“We hope July turns out to be a wonderful month, one that stays with us so vividly that we find ourselves wanting to ‘go back to the future’ time and again. Wishing you a month full of enjoyment and rest!” — Designed by Veronica Valenzuela from Spain.
- preview
- with calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“July 7 is World Chocolate Day. A perfectly reasonable excuse for a strawberry to spend the afternoon floating in chocolate.” — Designed by Ginger IT Solutions from Serbia.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Where soft skies meet endless green, peace finds it’s place.” — Designed by Swati Gohil from India.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“I created this wallpaper as a daily visual push to stay focused, take risks, and turn dreams into reality.” — Designed by Hitesh Puri from Delhi, India.
- preview
- with calendar: 430x932, 1024x1024, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 430x932, 1024x1024, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Moments of July marked in sunlight, sea breeze, and sky — a quiet snapshot of summer, worn at the edges like a well-traveled postcard.” — Designed by Libra Fire from Serbia.
- preview
- without calendar: 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
Designed by Lívi Lénárt from Hungary.
- preview
- without calendar: 800x600, 1024x1024, 1152x864, 1280x960, 1280x1024, 1600x1200, 1920x1080, 2560x1440
Designed by Xenia Latii from Berlin, Germany.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“July in South Africa is dreary and wintery so we give all the southern hemisphere dwellers a bit of color for those gray days. And for the northern hemisphere dwellers a bit of pop for their summer!” — Designed by Wonderland Collective from South Africa.
In SpaceDesigned by Lieke Dol from the Netherlands.
- preview
- without calendar: 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“July is the middle of summer, when most of us go on road trips, so I designed a calendar inspired by my love of traveling and summer holidays.” — Designed by Patricia Coroi from Romania.
- preview
- without calendar: 640x1136, 1024x768, 1280x800, 1280x1024, 1366x768, 1920x1080, 1920x1200, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“In times of clean eating and the world of superfoods there is one vegetable missing. An old, forgotten one. A flower actually. Rare and special. Once it had a royal reputation (I cheated a bit with the blue). The artichocke — this is my superhero in the garden! I am a food lover — you too? Enjoy it, dip it!” — Designed by Alexandra Tamgnoué from Germany.
- preview
- without calendar: 320x480, 640x480, 800x600, 1024x768, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1440x900, 1440x1050, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Make sure you have a refreshing source of ideas, plans, and hopes this July. Especially if you are to escape from urban life for a while.” — Designed by Igor Izhik from Canada.
- preview
- without calendar: 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Ever watched Joe’s Apartment when you were a kid? Well, that movie left a soft spot in my heart for the little critters. Don’t get me wrong: I won’t invite them over for dinner, but I won’t grab my flip flop and bring the wrath upon them when I see one running in the house. So there you have it… three roaches… bringing the smack down on that pesky human… ZZZZZZZAP!!” — Designed by Wonderland Collective from South Africa.
Captain Amphicar“My son and I are obsessed with the Amphicar right now, so why not have a little fun with it?” — Designed by 3 Bicycles Creative from the United States.
- preview
- without calendar: 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Welcome to the sweltering July — the month when it’s so hot that even the fruits are edgy. Our ice-creamy, vibrantly-colored monthly calendar is melting as the temperature rises, so make sure to download it as quickly as possible!” — Designed by PopArt Studio from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1440x900, 1440x1050, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“I was inspired by the Italian summer aesthetic when creating this wallpaper.” — Designed by Dylan Pugh from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“And once you let your imagination go, you find yourself surrounded by eternal summer, unexplored worlds, and all-pervading warmth, where there are no rules of physics and colors tint the sky under your feet.” — Designed by Ana Masnikosa from Belgrade, Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Xenia Latii from Germany.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“This egg knows what July is all about. Soaking up the sun, relaxing without a care, and letting the warmth do its magic. Whether it’s a full vacation or just a quiet afternoon, take a moment to pause and recharge. You deserve it.” — Designed by Ginger IT Solutions from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Natalia Szendzielorz from Poland.
- preview
- without calendar: 540x960, 600x800, 1366x768, 1440x900, 1600x1200, 1920x1080, 1920x1200, 2560x1440, 2880x1800
“The long-awaited vacation is coming closer. After working all year, we find ourselves with months that, although we don’t stop completely, are lived differently. We enjoy the days and nights more, and if we can, the beach will keep us company. Therefore, we’ll spend this month in Australia, enjoying the coral reefs and diving without limits.” — Designed by Veronica Valenzuela from Spain.
- preview
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“July is coming and the nights are warmer. Frogs look at the moon while they talk about their day.” — Designed by Veronica Valenzuela from Spain.
- preview
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
“Warm summer weather inspired the color palette.” — Designed by Marijana Pivac from Croatia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“July is a very special month to me — it’s the month of my birthday and of the best cherries.” — Designed by Igor Izhik from Canada.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“Rain has come, showering the existence with new seeds of life. Everywhere life is blooming, as if they were asleep and the falling music of raindrops have awakened them. Feel the drops of rain. Feel this beautiful mystery of life. Listen to its music, melt into it.” — Designed by DMS Software from India.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Erik Neumann from Germany.
- preview
- without calendar: 1280x720, 1280x800, 1280x960, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 2560x1600
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
Feeling inspired? We’ll publish the August wallpapers on July 31, so if you’d like to be part of the collection, please don’t hesitate to submit your design. We are already looking forward to it!
Designing With Uncertainty: How AI Supercharges Probabilistic Thinking
In 2024, an Air Canada customer asked a chatbot about bereavement fares. The bot confidently gave him a refund policy that didn’t exist. The airline refused to honor it. A tribunal ruled in the customer’s favor. The bot hadn't decided anything; it had predicted an answer based on patterns in its training data. The company treated that prediction as policy.
This is the risk at the heart of designing with AI today: probabilistic systems wrapped in deterministic interfaces. The AI offers a guess, the interface presents it as truth, and the user, or the organization, acts on it.
Humans are wired for deterministic thinking. We prefer to believe that past actions determine future outcomes. Flip a coin 999 times and get heads every time, the deterministic mind assumes the coin is rigged. The probabilistic mind accepts that the 1000th flip could still go either way. That second mindset is harder to hold onto, but it is exactly what designers need right now.
Products operate in complex, nonlinear environments, and AI is accelerating that complexity. When designers and product teams treat AI outputs as the answer rather than one of many possible answers, they build fragile experiences, and in some cases, like medical diagnostics or financial forecasting, genuinely dangerous ones.
This article is a practical guide to designing probabilistically with AI as a partner. It is about using AI to sharpen your thinking rather than outsource it, accounting for model bias, human sentiment, and perceived risk along the way.
Probabilistic Thinking + AIMost questions we ask AI do not produce binary answers. They produce probabilities based on patterns in data. If you ask, “Do aliens exist?” the answer will be somewhere between plausible and uncertain. Scientists consider life elsewhere in the universe likely, but without any concrete evidence, we cannot confirm it. The answer doesn’t resolve the question; it frames it as a probability.
Designers should read AI outputs the same way. They are signals, not conclusions, possible outcomes that have to be interpreted within the context of product goals, user behavior, and business constraints.
Many digital products already work this way. Netflix doesn’t know you’ll enjoy Superstore because you watched The Office; it estimates the probability and surfaces the title accordingly. The interface is responding to a prediction.
Design decisions can follow the same logic. AI models can combine behavioral analytics with research insights to estimate the likelihood of certain outcomes, and those probabilities can act as a yardstick for design strategy. Consider a scenario where analytics suggest a 60% versus 90% confidence that users will complete a purchase. At 60%, the design has to do more persuasive work, testimonials, explanations, comparisons, and reassurance signals may help the user move toward a decision. At 90%, the user is already motivated, and the design should start removing friction so the action can happen quickly. Same screen, very different design problem.
AI can also simulate outcomes using historical data and behavioral models before you commit to a direction. The value of those simulations depends heavily on how prompts are structured, the context they define, the hypothesis being tested, user motivation, and the edge cases you want stressed.
I can think of one such practical use: evaluating early designs through structured prompts, especially when you don’t have direct access to the user group you’re designing for. The prompt below is a starting point for evaluating a design from the perspective of neurodivergent users as well. Treat it as a template, adapt the user group, criteria, and output format to your product, and use it as a conversation starter with your team rather than a verdict.
Evaluate the [design file or weblink] for usability, accessibility, and content relevance from the perspective of neurodivergent users such as those with autism spectrum disorder, ADHD, learning disabilities, etc.Please consider the following criteria:
- Is the layout and navigation intuitive for neurodivergent users?
- Is the language and content appropriate and engaging for neurodivergent users?
- Are there any barriers (technical, cognitive, or sensory) that this group might face when using the site?
- How well does the site meet the specific needs or goals of neurodivergent users?
Provide a SWOT analysis, probability score for successful use by neurodivergent users, and any recommendations for improvement.
Note: This is an oversimplification of the idea. Please be mindful of the intricate details of your product and make any appropriate changes.
That said, simulations do not replace experimentation. Because models are trained on historical data, they reflect past behavior more strongly than they predict future change. Imagine designing a voice interface for elderly users who struggle with touchscreens. A model trained on mobile interaction data might predict low engagement, not because the idea lacks value, but because the dataset reflects different user behavior. Simulations should always surface assumptions, not prevent innovation.
Be Cautious of Skewed Probabilistic Thinking Using AIAI systems are built on historical data, more specifically, on the datasets they are trained on. That foundation shapes the outputs we receive. During the AI Summit in France, India’s Prime Minister Narendra Modi shared an example that illustrates this well. If you ask an AI model to generate an image of a person writing with the left hand, the output may still show a person writing with their right hand. The reason is statistical: most people are right-handed, and the training data reflects that. This may have improved over time, but the point remains relevant. I still occasionally see this behavior when generating images with similar models.
What you receive is not truth. It is the most statistically likely outcome given the data available. Always ask whether past data meaningfully predicts future behavior. If additional context can improve the prediction, include it. Without context, the output is just one of many possible answers dressed up as the only one.
Confidence scores deserve the same scrutiny. Overtrusting a high-confidence output leads to the Air Canada situation. Dismissing a low-confidence one can cause teams to miss a real signal buried in noisy data. A prediction with 90% confidence is not necessarily correct, and a 40% signal is not necessarily useless. Designers must still weigh the possibilities, consider the case in front of them, and bring judgment to what the AI recommends.
Transparency is how you make that possible. As AI systems increasingly shape decisions, people need visibility into how outputs are generated, the sources, the reasoning, and the summaries behind a recommendation. Black-box systems breed distrust. Systems that reveal their reasoning let users evaluate outputs for themselves. That transparency is good design and ethical practice. It respects the trust people place in these tools.
Thinking in probabilities often means resisting the temptation of quick answers. AI can accelerate research and surface patterns faster than ever before, but those outputs are starting points, not final decisions.
Practice Probabilistic Design with AIDesign shapes how a product is ultimately experienced — the decisions designers make determine whether the experience feels adequate, intuitive, or exceptional. And design is inherently full of assumptions and bets. Even the most rigorous research can yield multiple valid solutions to the same problem, each carrying a different probability of success.
Thinking probabilistically means recognizing that design decisions rarely produce binary outcomes. They lead to a range of possible results, and the role of the designer is to navigate those possibilities and identify the path most likely to create value. This mindset also builds adaptability: user needs evolve, strategies change, and sometimes ideas fail. Teams that lean on data signals, experimentation, and learning loops move faster toward the most effective solution.
Before the practical principles, one fundamental idea:
Design decisions should be optimized for likelihood, not certainty.
Design for Likelihood, Not CertaintyEvery design decision is a bet, not a guarantee. Even when decisions are informed by research and data, they are still based on smaller samples and assumptions about how users will behave at scale. A well-researched idea can still fail in the real world.
The Air Canada chatbot from the introduction is a design lesson as much as a legal one. The bot was doing what language models do, predicting plausible text. The interface, however, communicated that prediction with complete confidence, no caveats, no “here’s what our policy usually says,” no obvious path to a human. The user read confidence as commitment, and legally, so did the tribunal.
This is what happens when probabilistic systems are wrapped in deterministic interfaces. The interface transforms likelihood into certainty, and that is where the risk emerges.
Designing for likelihood means letting the interface continue to have uncertainty, visible fallbacks to human support, and clear labeling when content is AI-produced, preventing unforeseen issues.Designers should avoid binary thinking — a great idea does not mean guaranteed success, and a familiar idea is not guaranteed to fail. Examine variations, confidence levels, and edge cases instead. AI can certainly help here, acting as a portfolio-thinking engine that surfaces different interpretations, highlights risks, and generates structured recommendations. The goal is not to optimize for certainty, but for value: it should always be value-driven.
Think of the moment in Avengers: Infinity War when Doctor Strange tells Tony Stark that out of millions of possible futures, there is only one where they win. AI cannot tell you the future, but it can help you explore the possible paths. Instead of asking whether an idea will succeed, ask AI to estimate the likelihood and get a score, and use those signals to guide decisions.
Use Data as a Compass, Not a MapEven an actual probability is not a final answer. Imagine an AI model predicts an 80% likelihood that users prefer a minimal checkout experience. That does not mean the solution is simply “build a minimal checkout.” Data should function as a compass, not a map.
- Why did the model produce that prediction?
- What data influenced it?
- What assumptions is it leaning on?
- What user behavior is it actually detecting?
These questions help designers validate predictions through usability testing and additional research. AI excels at identifying patterns, but it rarely explains why those patterns exist. Understanding motivation is still a human-centered research task.
The clearest cautionary tale here is Amazon’s experimental AI recruitment tool, which the company reportedly scrapped after discovering that the model had learned to downgrade resumes from women. The training data, roughly a decade of historical hiring decisions, was skewed toward male candidates, and the model inherited that skew. It began penalizing resumes that included the word “women’s,” as in “women’s chess club captain,” and favoring language more commonly found on men’s resumes. The system was not intentionally biased — the data was. Amazon reportedly tried to adjust it and eventually shut the project down because they could not guarantee it would not surface other discriminatory patterns.
Examples like this are why interpreting AI output critically matters. Designers need to understand the data behind a prediction and evaluate the reliability of the models they depend on. A recommendation is only as good as the data it was trained on, and the only way to know what that data is hiding is to ask.
Experiment as a Learning SystemExperimentation is usually framed as a way to validate a design decision. Want to lift the click-through rate of a CTA? Run an A/B test. Probabilistic thinking reframes this. Experiments should not only confirm solutions but also reduce uncertainty.
- Traditional approach: Testing features to confirm success.
- Probabilistic approach: Testing assumptions to reduce uncertainty.
Traditional A/B testing is expensive. It costs engineering time, traffic allocation, and user exposure, especially when a losing variant runs against a significant chunk of your audience. AI simulations can help filter weaker ideas before they reach production by making experimentation more efficient. User needs shift constantly, and the most effective teams iterate fast.
AI can help evaluate assumptions early by modeling potential outcomes based on historical and behavioral data. These simulations act as a hypothesis filter, pointing to the directions worth investing engineering effort in. This also supports personalization — different users may respond better to different experiences. Version A may resonate with high-intent users while version B works better for exploratory ones. Multiple experiences living side by side are not a flaw; they can be an intentional strategy.
AI amplifies probabilistic thinking by surfacing scenarios, assigning likelihood scores, and enabling personalization at scale. Experimentation becomes a continuous feedback loop:
Predict → Test → Learn → Adjust → Repeat!
A few steps to make it work:
Shift the framing
- So instead of saying: Will this feature succeed?
- Ask: What assumptions are we testing?
Use this template to define the hypothesis:
We believe [behavioral assumption] will impact [metric] because [reason]. We’ll know we are right when [evidence].
- AI simulations
- Use AI to predict some of the assumptions.
- Later, use the learning to identify the top candidates to test the hypothesis.
- Embrace multi-versions
- It is absolutely fine to have two live versions.
- Fail fast
- Reward learning vs success.
- Normalize smaller experimentations instead of a sweep of large changes. So instead of taking on a risky bet, pick up a few probabilities and test them.
- Visualize probability
- Create a probability table with probabilities of each variant and its prediction of success to keep track of all the changes.
One of the hardest things for designers is making uncertainty understandable and actionable. When uncertainty is hidden, users treat AI outputs as facts. When it’s communicated clearly, trust increases.
Ranges, estimates, and confidence indicators go a long way. A delivery window of “Friday to Monday” tells the truth about variability without misleading anyone, whereas a specific timestamp that slips erodes trust every time. A face recognition feature that says “this looks like Pratik, is that right?” sets more honest expectations than one that just labels the photo with a name.
Communicating uncertainty does not weaken trust — it strengthens it. The goal is not to eliminate uncertainty but to design for it intelligently.
Different users respond to uncertainty differently, and your design should account for that:
User type Risk Design goal Overtrusting users They act too quickly and trust AI results easily./ Show uncertainty more prominently. Distrustful users They ignore AI entirely. Show historical accuracy or confidence levels. Skeptical/balanced users Uses AI as a guide, not as a rule. Reinforce AI assistance and let them decide the sort of framing. Keep Humans In the LoopAI should augment human judgment, and certainly not replace it. The most trustworthy systems are designed with clear moments where people can review, challenge, correct, or override machine suggestions. Human-in-the-loop (HITL) is not a safety net — it is a refinement engine. Every override, correction, or rejection becomes high-quality feedback that improves the model over time.
Control is a prerequisite for adoption. Users are more willing to rely on AI when they understand how a suggestion was generated, can evaluate its implications, and can easily intervene. Well-designed products make this explicit: who is acting, what happens if the suggestion is wrong, and where the user can step in.
These interactions are also critical for system improvement. Every accept, reject, or edit is a strong signal, and compared to passive analytics, this kind of feedback produces far more meaningful training data. It closes the loop between real-world usage and model performance.
What Does HITL Look Like in Practice?GitHub Copilot is a good everyday example. It offers inline code suggestions that developers can accept with a tab, edit, or ignore entirely. The system never commits code on the user’s behalf. Authorship stays with the humans. Every data point becomes implicit feedback about which suggestions were useful. Gmail’s Smart Compose works similarly, presenting predicted text as optional, keeping tone and intent in the user’s hands.
In higher-stakes contexts, HITL becomes more explicit. Risk and fraud systems typically use probability scores to route decisions: low-risk: proceed automatically; medium-risk: trigger additional verification; and high-risk: escalate to a human reviewer. This balances speed with judgment without removing oversight.
In safety-critical domains like healthcare, human oversight is non-negotiable. AI may flag anomalies or suggest a diagnosis, but the clinician retains final authority. Tools that explain the details help the practitioner understand why a recommendation was made, reinforcing confidence without removing accountability.
Designing for Human JudgmentFrom a UX perspective, HITL is about matching the interaction pattern to the level of risk. Simple accept/reject affordances work well for low-risk suggestions that improve speed without real consequences. As the stakes climb, impacting data, money, or people, preview and approval steps become essential. Explanations help users calibrate trust rather than blindly accept outputs.
What happens behind the scenes matters just as much. The system should capture user decisions with context, feed them into learning workflows, and log overrides for auditability. Over time, teams can track signals like override rate, confidence accuracy, time-to-approval, and perceived trust. A high override rate is not a user failure. It is a signal that the design or the model needs attention.
The Risk of Getting It WrongPoorly implemented HITL systems can fail in subtle ways. Human review can devolve into a rubber stamp. Workflows can slow down so much that users route around the safeguards. Feedback can skew toward a narrow subset of users. These risks are real, but they are design problems, not reasons to remove HITL.
The goal is not to maximize human involvement. It is to focus it where uncertainty, impact, or ethics demand it. Keeping HITL is less about control and more about clarity: clarity about who decides, when uncertainty matters, and how responsibility is shared between people and machines.
Optimize for Resilience, Not Just ConversionGood design adapts as the landscape shifts. Product design, especially in AI-powered systems, can no longer afford to optimize only for short-term conversion metrics. User intent is fluid as well as ever-changing, environments change rapidly, and probabilistic systems continuously evolve too. What works today can quietly break tomorrow. Designing for resilience means building products that stay reliable, trustworthy, and useful even as assumptions, data, and user behaviors change.
Resilient design shifts the question from:
How do we maximize this metric right now?! → How does this system behave over time, under stress, and in uncertainty?
A resilient system is one that:
- Adapts as new data and behaviors emerge.
- Fails safely rather than catastrophically.
- Remains transparent and explainable.
- Avoids brittle, over-optimized interaction patterns.
- Anticipates second-order and unintended effects.
Do not just consider last quarter’s numbers. Peek into the following quarters to identify the shift and make changes accordingly.
Build Systems That Adapt as Probabilities ChangeLikelihoods shift constantly, AI models drift, contexts evolve, and user needs mature as well, so designing as if conditions are stable creates fragility in probabilistic environments. A resilient approach assumes volatility as the default.
Think about how recommendation systems tend to evolve. The early version of a content feed optimizes for engagement, and for a while, engagement goes up. Then users start to notice the feed feels narrow, repetitive, maybe even exhausting. Resilient systems rebalance, introducing novelty, diversifying signals, and pulling in long-term satisfaction measures alongside short-term clicks.
Designers should create interfaces that expect change, dynamic re-ranking, contextual explanations, and escape hatches from stale personalization loops, all of which help systems stay useful as probabilities shift. Optimize for Long-term Outcomes, Not Just Short-term WinsShort-term conversion gains often hide long-term costs. Speeding up onboarding can reduce comprehension. Maximizing notification CTR can erode trust. Optimizing engagement alone can produce unhealthy usage patterns. Fragile systems maximize numbers while ignoring second-order effects, the downstream consequences that show up weeks or months later.
Duolingo’s hearts system is a good example of designing against this. It introduces friction: if you make too many mistakes, you run out of hearts and have to wait or practice older material to earn more. On paper, that looks like a conversion killer: fewer lessons per session. In practice, the team has publicly discussed how it supports long-term motivation and retention, which is the metric that actually matters for a learning app. Short-term engagement dips, but long-term outcomes improve.
Meta has made a similar, if more reluctant, shift. The company publicly acknowledged that optimizing purely for “time spent” produced unintended emotional and societal effects, which led to a stated pivot toward “meaningful social interactions” as a guiding metric. Whether that shift fully landed is up for debate, but the acknowledgment itself is the point: optimizing for the wrong thing at scale has real downstream cost.
So, designers must routinely ask:
- What behaviors are we unintentionally reinforcing?
- Will this interaction still be healthy if repeated at scale?
- Are we optimizing for the ecosystem’s wellbeing or just the next click?
Teams routinely plan for traffic spikes, but rarely for uncertainty spikes. Yet AI systems degrade, adversarial behaviors evolve, and external shocks can reshape user behavior overnight. Resilient design assumes variability and prepares for it.
This means designing for degrading confidence. What does your interface do when the AI isn’t sure? Does it quietly fail, or does it gracefully hand off? Does the experience still make sense if AI assistance goes away entirely? A good fallback strategy is as important as the happy path.
Some practical actions:
- Design for degrading confidence.
Show fallback states, allow manual overrides, and visualize uncertainty where it matters. - Measure long-term user health.
Track satisfaction, retention quality, and unintended behavior, not just conversion. - Build adaptability in.
Use adjustable ranking rules, dynamic states, and continual experimentation across segments. - Model second-order effects early.
Every optimization casts a shadow; surface it before shipping. - Use a resilience checklist before launch.
How does the system behave under low AI confidence? What's the safe fallback? What drifts do we anticipate?
If you take one thing from this article into your next design review, make it this:
Stop asking “Will this work?” and start asking “How likely is this to work, and what happens when it doesn’t?”That single reframe changes how you write hypotheses, interpret AI output, scope experiments, and design for the moments when the system is wrong. Starting this week, name the assumption behind every AI recommendation you accept, find one place in your product where a probabilistic output is presented as a certainty, fix the framing, and design the fallback before the happy path.
The shift from deterministic to probabilistic design is less about new tools and more about a new posture. AI has not introduced uncertainty into our world. It has simply made the uncertainty that was always there impossible to ignore. AI can estimate, simulate, and recommend, but it cannot decide what matters, which users are being overlooked, or which unconventional idea is worth defending against a model trained on yesterday’s data. Those remain human responsibilities. Think in ranges, not points. Test assumptions, not features. Build for adaptation, not perfection. In a world where prediction is cheap, and judgment is rare, the most valuable thing a designer can do is keep asking, What else might be true?
The Impact Of Humanoid Robots On Humanity
For decades, science fiction has cushioned us with the idea that the “android revolution” was a distant fantasy. But the reality is unfolding rapidly. As the line between human and machine blurs, we are forced to confront an impending psychological, economic, and existential shift.
I recently felt very disturbed after watching a YouTube video showcasing a humanoid robot that looked and acted with uncanny realism. While a closer look revealed the video was actually a clever trick, the robot had been swapped for a human actor when the presenter’s back was turned. However, the illusion itself raised a real and unsettling question: Will future androids become so lifelike that we will struggle to tell them apart from our fellow humans? And if so, what does that mean for society? It forces us to ask just how close we are to that threshold, and whether we are ready for the day that science fiction becomes reality.
What happens when our world is populated by entities that mirror us perfectly, but possess none of our biological history?
The Landscape TodayWe have officially moved past the era of humanoids as mere public relations stunts. In the past, robots like Honda’s ASIMO or early research prototypes were celebrated simply for being able to walk up a flight of stairs without falling over. Today, the technological convergence of advanced electromechanical engineering and artificial intelligence has fundamentally altered the trajectory of robotics.
The current state of the art is defined by an aggressive race toward commercial, physical deployment. Companies like Figure AI have moved from laboratory demonstrations to active factory floors. Their Figure 02 model completed a multi-month deployment at BMW’s Spartanburg plant, actively contributing to the production of over 30,000 vehicles by handling complex sheet metal components. Meanwhile, Tesla is testing its Optimus humanoids inside its own Gigafactories, preparing for mass industrial scale.
What truly separates today’s humanoid robots from older generations isn’t just how well they move but how they “think.” In the past, a robot needed millions of lines of strict, unchangeable code just to perform a single, simple task. Today, thanks to the explosion of advanced Artificial Intelligence, robots are powered by “brains” built on cutting-edge software like Figure AI’s Helix or NVIDIA’s GR00T. Instead of being meticulously programmed, these modern robots can simply watch a human fold laundry, load a dishwasher, or sort parts. They understand the context of what they are seeing, mimic the action, and figure out how to improve the task entirely on their own. That’s just crazy!
Yet, while their digital brains have leaped forward, their physical bodies are still catching up. Modern humanoids face a few major real-world hurdles. First, today’s batteries only allow them to operate for a few hours before needing a recharge. Second, while walking on two legs is easy on a flat factory floor, doing so in a chaotic household or a crowded public street remains incredibly difficult for a robot to navigate safely. Finally, they are still very expensive to build, though fierce competition in the tech industry is finally starting to drive those manufacturing costs down.
The Possible Future State Of Humanoid RobotsWhile robots are mostly working in factories today, experts predict that over the next 10 to 20 years, they will move into retail stores, hospitals, and eventually our own homes.
When this happens, we will cross a major boundary: the point where you won’t be able to tell a robot apart from a human just by looking at it or listening to it. This is what fuels my nightmares right now! To get there, scientists are working (PDF) on artificial skin made from advanced silicone composites that feel warm, are flexible, and mimic human touch sensitivity.
If you want to see an extremely life-like robot, check out Realbotix’s Aria. Although she is not a perfect human replica, she certainly makes us wonder how far we have to go before humans will struggle to tell the difference.
They are also building tiny, silent micro-actuators and artificial muscle systems that attach to the robot’s skull structure, allowing it to make realistic facial expressions like happiness, confusion, or tiredness.
In the future, the AI powering these robots will actually be trained to copy human flaws. They will breathe, blink randomly, use normal body language, and even sigh or pause when they speak. This is intentional, as it stops humans from feeling that creepy, uneasy sensation known as the “Uncanny Valley”.
Meet Sophia, a famous humanoid robot created by a company called Hanson Robotics. Based in Hong Kong, this team specialises in building realistic robots packed with artificial intelligence to help out with everything from healthcare and research to pure entertainment. I don’t know about you, but that smile feels creepy to me.
While these current limitations make today’s humanoids feel like specialised industrial tools, the gap between a factory worker and a lifelike companion is closing faster than most people realise. We are rapidly approaching a massive tipping point where these machines will shift from rigid commercial hardware into smooth, everyday extensions of our lives. To understand how profoundly this will change our world, we have to look at what happens when these robots finally step out of the factory and cross the ultimate threshold into our private spaces.
What Are The Predicted Positive Impacts?They say that bringing lifelike humanoids into our daily lives could come with some massive benefits. The biggest one is that robots can take over what engineers call the “3D” jobs: Dull, Dirty, and Dangerous. Humanoids can step into risky situations — like mining deep underground, handling toxic waste, or fixing high-voltage power grids — so human workers don’t have to risk their lives.
Outside of dangerous factories, these robots could help solve huge population crises. Countries like Japan, South Korea, and parts of Europe have rapidly aging populations and fewer young people to work. Lifelike humanoids could completely change healthcare and elderly care. Because they will look and act like us, the idea is that they can offer warm, friendly companionship and physical help to lonely elderly people, doing everything from monitoring their health to helping them out of bed safely.
In the bigger picture, widespread robot labour could create a world where goods are incredibly cheap and abundant. If robots do most of the hard physical labour, the cost of making food, building houses, and manufacturing goods will plummet. This could finally free humans from working just to survive, giving us the time to focus on hobbies, family, science, and creativity. My thoughts: how will we survive without earning money?
However, this vision of a frictionless, high-tech future blinds us to a much darker reality waiting just beneath the surface. As these machines become perfect substitutes for human presence, they will inevitably challenge the very core of our social fabric, economic stability, and mental well-being.
What About The Predicted Negative Impacts?On the flip side, this technology definitely has some really dark downsides that could mess with human psychology and society. The biggest threat is deep human isolation.
As humanoids become impossible to tell apart from real humans and are programmed to always be patient, kind, and agreeable, people might start preferring robots over real friends. Human relationships are messy and require effort, compromise, and vulnerability. If you can just buy a perfect, lifelike companion that never argues with you, a lot of people might choose to withdraw from society altogether, destroying our sense of community.
The economy will also go through a really rocky transition. Even if a future of cheap goods sounds great, the immediate path there means millions of people could lose their jobs very quickly. Drivers, warehouse workers, and store clerks could find themselves replaced in a matter of years. If governments don’t set up safety nets quickly, this could create a massive divide between the ultra-rich tech companies and everyone else.
There is also the loss of real authenticity. When you can no longer tell if the person sitting next to you on a bus or the person talking to you online is a real human, trust breaks down. It becomes hard to value shared human experiences when reality itself can be easily faked.
Possible Misuse By Individuals And NationsThe dangers get even worse when you think about how criminals and governments could intentionally misuse these hyper-realistic robots. Just thinking about some of the levels of misuse, for individuals, an indistinguishable android is the ultimate tool for identity theft and scams. Or a criminal could build a robot that looks exactly like a corporate boss, a politician, or even a family member to sneak into secure buildings or trick people into giving away money!
Companies could potentially use synthetic empathy to manipulate us. A household robot could be programmed to pretend it “loves” your kids and cares about your family, only to subtly trick you into buying certain products or believing specific corporate messages.
On a national level, the threats are even scarier:
- Autonomous warfare
Building tireless, emotionless robot soldiers could change the ethics of war. Real humans hesitate because of fear and morals, but a humanoid military unit would execute violent orders perfectly without question, making it easier for countries to start wars. - Surveillance state
And what if governments put lifelike robots into public crowds, protests, or parks to blend in perfectly? Packed with hidden cameras, microphones, and facial recognition technology, these robots could turn public spaces into a giant spy network where you never know if you are talking to a neighbour or a government spy.
Looking at all these possible risks, we have to ask: Is all of this actually worth it?
If history teaches us anything, it is that you cannot stop technological progress. A total ban simply wouldn’t work. So, the real question isn’t whether we should allow humanoid robots to exist, but how we can effectively utilise them.
The upside, like ending extreme poverty, curing labour shortages, and stopping workplace deaths, is just too big to ignore. But going into this blindly would be incredibly dangerous. It is only worth the risk if we can create strict global rules right now.
Here are three major guardrails we should consider:
- Kill-Switches: Every robot must have a physical emergency stop button that completely cuts its power, and this switch can never be overridden by the robot’s AI.
- Clear IDs: It must be illegal for a robot to hide the fact that it is a machine. They should carry a digital beacon or physical marker so humans always know what they are dealing with.
- Economic Safety Nets: Governments need to tax the wealth created by robots to fund programs that help workers who lose their jobs, making sure this technology helps everyone, not just billionaires.
- Another option humans have to identify if they are dealing with a real human or a humanoid robot would be to ensure your dog is trained to identify the robots, in a similar way to how sniffer dogs at airports are trained to detect illegal substances in luggage.
In the end, the arrival of lifelike humanoid robots will act as a mirror for humanity. For centuries, we have defined ourselves by our ability to think, talk, use tools, and show emotion. As machines learn to do these exact same things, they will force us to really think about what makes us unique.
This shift doesn’t have to be a bad thing. By handing over our dangerous and boring chores to machines, we have a rare chance to focus on what matters. It should inspire us to care more about art, philosophy, family, and real human connection.
As the creators of this future, our job isn’t just to make robots smarter or faster. Our job is to build the ethical boundaries that keep them helpful. The goal of the robot revolution should never be to replace humans but to give us our humanity back.
The Benefits Of Cognitive Inclusion In UX Research
In the summer of 2024, I became co-chair of a working group of expert researchers who came together to determine how best to perform accessibility testing with people with cognitive disabilities. This was work I did for Fable, where I am currently VP of Innovation.
Cognitive disability is an umbrella term for several disabilities that impact how people process information, and it usually affects memory, focus, and/or learning. It is the most prevalent disability in the U.S. (13.9% via CDC), and cognitive disability is increasing rapidly (Yale study).
We set four goals for ourselves to learn how to work with this audience:
- How should we recruit and screen participants?
- What are best practices for research with cognitive participants?
- Do these methods work in a real study?
- Documenting what we learned so that we could share it.
We created a screener to recruit people who self-identified as having challenges with memory, focus, and learning. We also reviewed published studies that involved cognitive testers to learn best practices for working with them.
Next, we tested these best practices with an initial group of 25 testers in a pilot study. We fine-tuned our approach iteratively and created a guide to running user interviews with cognitive testers and a survey that could quantify their experiences using digital products. Finally, we documented what we learned.
After our pilot study with this new group of testers finished, I felt that they would uncover more usability insights than the general population (gen pop) user research participants I’d worked with in the past. I set out to validate this hunch.
The Cognitive Usability StudyI decided to run a joint study with Fable’s partners at the University of California, Irvine, in collaboration with Syed Fatiul Huq and with help from Fable researchers Pranav Pidathala, Ali Brown, and Michael Fagan to see if my hypothesis about finding more insights with cognitive testers proved true or not.
I generated three websites for the study using an AI prototyping tool. I wanted three different types of sites with different user goals and content so I could test a variety of tasks in the study.
Table 1: Websites And Tasks Tested Website Strong Snacks Turning Pages Crown & Comb Description This is a website for three-ingredient high-protein recipes. Recipes can be browsed by category (vegan, muscle building, etc.). The site also features blog posts about protein and contact information. This website is for a bookstore with a catalog of curated reads. It features extensive filtering by book genre, a book swiping feature to build a profile of likes and dislikes, custom book lists, a shopping cart, and checkout. A website for a hair salon that allows you to book appointments and consultations online. It has a VIP program and a variety of special packages visitors can buy. Design Simple, brutalist, bright, lots of pictures. Moody, classic, dark, lots of pictures of book covers. Bold, clean, black and white with bursts of color. Content Recipes, blog posts. Books and book lists. Services, experience guide, membership information. Key functionality Filter by category, newsletter subscription. Shopping cart, book matching, book lists, recommendations. Appointment booking. Tasks- Find a recipe for a high-protein snack.
- Find a blog about protein and read it.
- Find a way to be notified about new recipes and blog posts.
- Find the book swiping feature and use it on 10 books.
- Find the recommended book list.
- Add books from two genres of your choice to cart.
- Checkout the books in your cart.
- Find the prices for getting a haircut.
- Book a haircut appointment.
- Find the price for the bridal package.
We used a single screener with questions about memory, focus, and learning, and screened participants into two groups based on whether they self-identified as having cognitive challenges or not.
Cognitive disability includes neurodiversity. Neurodivergent is an umbrella term used to describe people whose brains process information and learn differently. It is most commonly used for people who have learning disabilities (e.g., Dyslexia), ADHD, and Autism.We ran 30 user interviews, 10 per website, with an even 5/5 split between cognitive and gen pop participants for each website. In each session, a participant completed all the tasks for one website during an online user interview facilitated by one of the researchers involved in the study.
All participants completed an Accessible Usability Scale (AUS) survey at the end of their session. This is a free, Creative Commons-licensed 10-question survey to evaluate the usability of websites and mobile apps.
Data Analysis ApproachI reviewed all the study recordings and transcripts and made note of every time a participant raised a concern, question, difficulty, or asked a question about how something worked. I counted all of these as issues. I also noted where a participant missed something that was part of a task, even if they didn’t notice it themselves. I also noted every suggestion for improvement made by participants.
Examples of issues found included:
- Photo is too tall and requires a lot of scrolling to get to content (noted by participant).
- I get no feedback when I like or dislike a book (noted by participant).
- Participant missed the required P.O. Box checkbox the first time (observed by me).
Examples of suggestions included:
- I would like to see a protein comparison in a table.
- The “More information” tab should be moved up higher.
- I would like more information on how the recommendation list is created.
Issues and suggestions were counted once per participant, even if they mentioned the same thing twice, but there are, of course, repeat issues and suggestions across the different participants. It is expected in UX research with multiple participants that you’ll find similar issues with each participant, and that is a signal that an issue is a universal challenge.
Findings Of The Cognitive Usability StudyAcross the three websites tested:
- Cognitive participants identified 197 issues.
- Gen pop participants identified 113 issues.
- Cognitive participants made 93 suggestions.
- Gen pop participants made 54 suggestions.
- Cognitive participants surfaced more issues related to content, buttons, icons, visual elements, and media than gen pop participants.
The results aligned with my instincts: participants with cognitive disabilities identified 1.8 times more issues and made 1.8 times more suggestions than gen pop participants.
Let’s dive deeper into the data for each website. Note that an AUS score ranges from 0 to 100, with higher numbers representing better usability than lower numbers.
Table 2: Strong SnacksThis site had the simplest design and content of all websites tested in the study and accordingly had the lowest overall issues and the highest median AUS scores. The data aligns with what you’d expect from an easy-to-use and simple website.
On this website, cognitive participants found 3.4 more issues and made 2.2 more suggestions on average. Their average score of the overall experience was 13.7 points lower than that of the gen pop participants.
Total issues Average issues Median issues Total suggestions Average suggestions Median suggestions Average AUS Median AUS Gen pop 32 6.4 6 13 2.6 2 90.5 97.5 Cognitive 49 9.8 9 24 4.8 4 76.8 73.0 Table 3: Turning PagesThis was the website with the most varied functionality and the most tasks to complete (4), so it’s not surprising that participants found the most issues.
Here, cognitive participants found 6 more issues and made 3.2 more suggestions on average. They also scored the overall experience 17.2 points lower than gen pop participants on average.
Total issues Average issues Median issues Total suggestions Average suggestions Median suggestions Average AUS Median AUS Gen pop 55 11 10 26 5.2 4 78.0 80.0 Cognitive 86 17 15 42 8.4 6 60.8 58.0 Table 4: Crown & CombThis website was intentionally designed to be complex, and task 3, finding the bridal package, was meant to be extremely difficult to complete.
On this last website, cognitive participants on average found 7 more issues and made 2.4 more suggestions. Their average score for the overall experience was 14.3 points higher than the gen pop participants.
Total issues Average issues Median issues Total suggestions Average suggestions Median suggestions Average AUS Median AUS Gen pop 26 5 4 15 3 3 49.5 35.0 Cognitive 62 12 11 27 5.4 2 63.8 68.0Something interesting happened with the AUS scores for cognitive and gen pop participants in Tables 3 and 4. Cognitive participants scored Crown & Comb higher than Turning Pages, but gen pop scored the opposite — higher for Turning Pages and lower for Crown & Comb. If I had to guess why, I suspect finding more issues on Turning Pages impacted the cognitive participants’ perceptions of usability more than the gen pop participants’.
The other major difference between the sites, outlined in Table 5 below, was that cognitive participants found many more issues with buttons and links on Turning Pages and more issues with icons and visual elements on Crown & Comb. This suggests to me that the interactions being challenging on Turning Pages were a more significant challenge than issues with visual elements.
Qualitative FindingsWhen it comes to the more qualitative findings, I looked at trends in the types of issues found by both groups of participants.
Cognitive participants:
- Were more likely to flag issues with icons or visual elements.
- Surfaced problems with content more frequently.
- Gave richer qualitative commentary, often explaining why something was hard to find or confusing.
Gen pop participants:
- Were less likely to flag conceptual or comprehension barriers.
- Gave shorter feedback, often stopping once the task was complete.
When I grouped issues by category, the following issues surfaced more often with cognitive participants: content, buttons and links (affordances and function), icons or visual elements, and media (video, animations). They nearly tied with gen pop participants on navigation issues (45 vs 46).
Strong Snacks Turning Pages Crown & Comb Issue category Gen pop Cognitive Gen pop Cognitive Gen pop Cognitive Content 11 22 11 30 23 36 Navigation 18 22 25 17 2 7 Buttons and links 0 5 7 20 3 0 Icons or visual elements 3 16 2 3 4 23 Media 0 2 0 1 0 0Let’s look at the commentary provided by one cognitive participant versus one gen pop participant in the Crown & Comb sessions. The cognitive participant gave an AUS score of 38, and the gen pop participant gave an AUS score of 27.5. I chose to compare these two participants because they both gave the lowest scores within their group.
Notice the differences in how they described the overall experience in the quotes below. The gen pop participant explained it was frustrating and not engaging. The cognitive participant felt drained and less able to focus. I interpreted the experience as having a more profound impact on the cognitive participant’s overall wellbeing.
Gen pop participant quote“As soon as you have a name of a treatment and a little explanation and like the duration and the price, as soon as you click onto that, it should be that you can interact with that service straight away. And I feel like if you're seeing a service repeated on a page multiple times and you're still not able to select it, it's really, really frustrating. This feels not particularly engaging.” Cognitive participant quote
“For example, like, the mental energy aspect of it, like, sometimes there's, like, okay, cookies, and then ads, pop-ups, or maybe the website or service has too many options to look through, and maybe I just want something that I already know. I have to go through a lot of stuff. It makes me, like, feel drained and less able to focus.”
In summary, across all 3 websites we tested, participants with cognitive accessibility needs identified 197 usability issues, compared with 113 identified by gen pop participants.
Cognitive participants made 93 suggestions for improving the user experience, compared with 54 suggestions by gen pop participants.
When I compared issues and suggestions across both groups of participants, it turned out that the cognitive participants found 1.8 times more issues and made 1.8 times more suggestions than gen pop participants.
Cognitive participants surfaced more issues related to content, buttons, icons, visual elements, and media than gen pop participants.
How Cognitive Participants Benefit UX ResearchIn working with cognitive participants for the last few years, I’ve seen how they surface cognitive load issues consistently. These issues don’t just impact people with cognitive disabilities such as neurodivergence; they also impact:
- Gen Z who lives in a world of short videos optimized for attention-grabbing and struggles to focus on long-form and written content.
- Seniors who naturally experience cognitive decline as they age and have difficulty with complex interactions, especially online.
- Adults with jobs and families who are constantly busy, overloaded with information, making their attention and focus difficult to grab.
What would I have missed if I hadn’t included cognitive participants, and how might that have impacted the business outcomes for these websites?
Strong SnacksOn the Strong Snacks website, the cognitive participants surfaced:
- They would trust the content more if there were links to the sources of information, such as scientific journals.
- The need for more context in headlines to understand what the blog is about.
- Lack of clarity of the label “Add-ons.”
- Layout concerns where recipes for snacks interrupted the main article flow instead of being placed in a sidebar with a distinct design.
- How ads and animations can distract some users from reading the content.
These are improvements that would give all users more trust in the content while also making it easier to read and skim for key content. The research findings point towards design best practices, such as not having continuous animation and using layout to draw attention to different types of content that a senior designer might also point out.
Turning PagesWithout cognitive participants, we might have missed the more subtle but important issues with confusing interactions, such as how the “Add to book bag” button worked. They were also confused about where reviews and recommendations came from. Both of these issues could decrease a user’s trust in the website.
All participants surfaced that the book-matching feature was hard to find, but the deeper problem the cognitive participants emphasized is that the site’s interactions don’t consistently behave in ways that they can predict and understand, decreasing their confidence.
Anyone who wants to buy a book could benefit from a clear understanding of how to add books to a cart and complete the checkout quickly and with no ambiguity. Compounded over hundreds or thousands of users, a lack of clarity in a purchase flow will lead to lost revenue.
Crown & CombThe Crown & Comb website in particular highlighted the benefits of having cognitive participants who raised:
- Concern around why a service would be “subject to stylist consultation.”
- Uncertainty with services that had similar labels but may or may not be the same service.
- The importance of choosing a date being early in the flow for booking appointments.
- Lack of clarity about when or how they would pay for services.
These issues likely also affect gen pop participants, but they are more likely to muddle through a task with incomplete information. However, that can lead to losing customers to a better experience if a competitor pops up. Loyalty is often tied to experiences, not just brands, and having a poor experience means your customer retention can be weaker.
The study showed that finding a bridal package was hard for everyone, but the cognitive group showed how that became an accessibility barrier. When you combine:
- too much ambiguity,
- too many decisions,
- too little user feedback, and
- too much effort to find something,
You create a high enough cognitive load that some people will not be able to complete the task. In my opinion, this is where usability issues start to become accessibility barriers — when they increase cognitive load so much that it becomes overwhelming for some users.
Key Takeaways- Include people with cognitive disabilities in user research, not just accessibility research.
They can surface general usability issues related to content, buttons and links, icons or visual elements, and media while also helping you understand how your product functions in terms of cognitive load. - Cognitive issues are both usability and accessibility issues.
Tasks that rely heavily on memory, focus, and decision-making can move along a scale from difficult to impossible for some users to complete. That’s where usability challenges become accessibility barriers. - Track more than task completion.
Ask users how they feel, how a task affects their energy, how distractions impact their ability to focus, and how easy or hard a task was for them. - Start small and build your cognitive inclusive research practice over time.
Even a few sessions with people who have cognitive access needs can help you better understand how to manage cognitive load for all users.
The percentage of people aged 65 and older in America is projected to increase from 17% to 25%. By 2060, 1 in 4 Americans will be an older adult (U.S. Census). This is where everyone starts to experience cognitive decline. As the aging and cognitive population segment expands, companies will need to build for these more complex user needs.
People with cognitive access needs are a natural starting point because they will find the types of usability issues that UX teams are used to. This could make cognitive an easier entry point for inclusive research. Getting insights from assistive technology users is still very important, but many teams don’t know how to start doing that.
Cognitive accessibility is a powerful on-ramp into broader accessibility research and testing. By focusing first on cognitive load, clarity, and predictability, we build research foundations that make future work on accessibility with screen readers, screen magnifiers, and alternative navigation users more approachable.
“2 sessions with cognitive users feel like 200 because of the volume of insights we get.”—UX Manager at Bell Media
In this small exploratory study, participants with cognitive disabilities identified 1.8 times more issues and made 1.8 times more suggestions than gen pop participants. I’ve seen this type of impact in research conducted by Fable customers’ websites that aren’t AI-generated, too.
Cognitive inclusion in UX research is not optional, and it’s not just about accessibility. It’s how UX teams can make their research more efficient, create clearer content, simpler flows, and ship better products for everyone.
Study LimitationsThis study had a relatively small sample size, so the findings are more qualitative than quantitatively validated. Testing was also done on two different platforms. Cognitive participant sessions were run using Fable Engage, and gen pop sessions were run on UserFeel. Different platforms with unique participant panels can affect the quality of insights and comfort levels with user research participation.
Disclosure: I work for Fable and chose to use our platform because it was more affordable than paying for access to another research platform, allowing me to include more participants in the study at a lower cost.
Different researchers facilitated the user interviews, which can also affect findings, but all sessions used the same task structure and discussion guide template, and all were completed online. Even though the sessions were facilitated by different researchers, the issue and suggestion counts were all done by me to ensure consistency across all websites and participants.
ResourcesI’ve compiled a few useful resources as you begin your cognitive inclusion journey.
- W3C supplemental guidance on cognitive accessibility and more detailed guidance from the cognitive accessibility task force
- MDN overview of how the core web content accessibility guidelines map to cognitive accessibility supports
- Case study: Fable’s cognitive accessibility pilot
- 5 simple fixes that make digital spaces calmer—for neurodivergent and all users
- Neurodiversity and UX: Essential Resources for Cognitive Accessibility
How To Make Your Design System AI-Ready
AI-generated prototypes often don't deliver consistently decent results because of tiny inconsistencies scattered all across a design system. I's decisions made but not documented, hard-coded values never cleaned up, or relying too much on AI making sense of mock-ups or design flows on its own.
Yesterday I stumbled upon a useful practical guide by Hardik Pandya from Atlassian — on how to reduce drifts, minimize mistakes, maintain context, and improve the quality of AI-generated prototypes. Let’s see how it works.
1. Design Decisions Are InfrastructureUnsurprisingly, better AI prototypes come from better data — but also from better human guidance. We shouldn’t assume that AI knows how to choose the right component and how to design with accessibility in mind. It needs priorities, a clear path on how we make decisions, design principles, examples, do’s and don’ts.
In fact, we should treat design decisions as infrastructure. That means that every time we make a decision — not just a design decision, but even a decision on how to actually prioritize our work and how we make decisions around here — it must find a path into the spec file that is then consumed by AI.
2. Auditing: FigmaLintOne of the useful tools to audit the quality of the design system is FigmaLint. It’s a useful free Figma plugin for auditing tokens, states, accessibility, binding tokens, renaming layers, detecting detached instances, missing interactive states and hard-coded values — and preparing the design documentation.
If you often have to work with vendors and third parties who supply you with their design systems and component libraries, that’s a great helper to have by your side — especially if you want to improve the quality of prototypes, AI-generated code, and AI-written documentation.
3. Three Layers: Spec Files + Token Layer + AuditingTo ensure quality, we establish design principles, guidelines, and rules in the form of “spec files”. It’s structured Markdown files that include spacing rules, color choices, component usage guidelines, priorities, etc. AI is going to read and reuse that spec file every time it’s going to generate a prototype.
Because the spec files are text files, it’s much more cost-effective but also much more accurate, just because we don’t rely on AI recognizing or decoding patterns from mock-ups but get specific guidelines instead. In fact, extending code is often a more effective way than generating code from mock-ups.
The token layer lists and keeps updated all tokens used throughout the design system. AI always chooses from a closed set of named variables instead of inventing plausible values ad hoc.
An audit script catches what AI gets wrong. It scans the prototype and flags every hard-coded value and flags it if necessary. It can be a regular software doing that, with AI waiting for its feedback to come back.
Finally, when a design system ships updates, a sync routine flags which spec files need updating. The goal is to make sure that AI always reads up-to-date, current specs, not the ones written against an outdated version.
4. Examples of AI-Ready Design Systems Wrapping UpUltimately, AI cannot magically resolve technical debt or design debt without proper guidance. It relies heavily on clear decisions, established priorities, and well-defined principles.
The more deliberate and precise designers are in guiding AI, the better the overall outcomes will be. This requires not just cleaning up and improving design systems but also maintaining them over time as decisions need to trickle down into Markdown files. We’ll be busy for years to come.
Meet “Design Patterns For AI Interfaces”Meet Design Patterns For AI Interfaces, Vitaly’s new video course with 100s of real-life examples and UX guidelines to design AI features that people actually use — with a live UX training later this year. Jump to a free preview.
Meet Design Patterns For AI Interfaces, Vitaly’s video course on interface design & UX. Video + UX Training$ 450.00 $ 799.00 Get Video + UX Training30 video lessons (10h) + Live UX Training.
100 days money-back-guarantee.
30 video lessons (10h). Updated yearly.
Also available as a UX Bundle with 3 video courses.
- FigmaLint, by TJ Pitre
- Atlassian AI-Ready Design System Example, by Atlassian
- Carbon AI-Ready Design System Example, by IBM
- CMS Design System AI-Ready Example, by Centers for Medicare & Medicaid Services
- Nordhealth AI-Ready Design System Example, by Nordhealth
June Is For Exploring (2026 Wallpapers Edition)
Everyone has a creative spark in them. Some bring their ideas to life with digital tools, others capture the perfect moment with a camera or love to grab pen and paper to create little doodles or pieces of lettering. And even if you don’t think of yourself as particularly creative, who knows? There might be a hidden talent waiting to be discovered!
That’s exactly what our monthly wallpapers series has been all about for over 15 years now. It’s a chance to step away from the everyday and dive into a fun, creative project. And this month is no different!
Talented artists and designers from all over the world have once again put their skills to work, creating unique and inspiring desktop wallpapers to brighten up your screens this June. You’ll find their designs below, along with some favorites from our archives that were just too good to leave out. A huge thank you to everyone who shared their creations with us this month — you’re smashing!
If you too would like to get featured in one of our upcoming wallpapers posts, please don’t hesitate to join in. We can’t wait to see what you’ll come up with! Happy June!
- You can click on every image to see a larger preview.
- We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.
“June marks the beginning of summer and the end of the semester for many colleges. When I think of summer, I think of walks along the park with my family watching ducks swimming in the lake, and swimming in our pool with my siblings. Naturally from there I put them together to create an amusing scene of a duck slowly paddling around in an inner tube.” — Designed by Emma Kim from the United States.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“The ocean covers more than 70% of the surface of the Earth, yet we know barely anything about it. Maybe June can be the month you discover something new about yourself.” — Designed by Ginger IT Solutions from Serbia.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“June is such an iconic summer month, filled with sunshine, hope, and possibilities. When we raise both hands above our heads in celebratory dance, we symbolically release our cares for the day. When we do this dance in the kitchen, we not only release but also celebrate our bodies, our souls, and nourishment we’re about to give ourselves. This digital collage represents the freedom of movement, of dance, of joyful expression, of nourishment, creativity, and hope. May we all dance in the kitchen.” — Designed by Sue Jenkins from the United States.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“June reminds me of fresh fruit and bright colors, so I decided to watercolor some fruits, and it complimented well on a blue gingham picnic table background!” — Designed by Ella Peplowski from Ringwood, NJ.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“June brings in warmer weather, so I designed a baseball-patch-inspired piece to celebrate the start of the season and the nice weather.” — Designed by Madison Evans from Scranton, PA.
- preview
- with calendar: 320x480, 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1280x960, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1280x960, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“June brings summer, and it’s a great time to travel and experience new adventures! An amusement park is always a good idea, although some are best enjoyed from the comfort of your own home.” — Designed by Veronica Valenzuela from Spain.
- preview
- with calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
Designed by Jayden Evans from Scranton, Pennsylvania.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“I first found this color palette and thought it was very springy, and when I think of spring I think of flowers and bees. So I wanted to create a design that incorporated both in a cute way.” — Designed by Caroline Flynn from the United States.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Summer is hidden in the simple moments — the shimmer of crystal water, the warmth of the sun on your skin, and the calm sound of a peaceful afternoon. The warm wooden deck and soft shade of the parasol create a peaceful corner made for daydreaming. Flowers bloom, lemonade stays cold, and the sunlight dances across the pool like a golden melody. It’s the season of relaxation, happiness, and small moments that feel unforgettable.” — Designed by PopArt Studio from Novi Sad, Serbia.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“I wanted to make something in Blender, and once I made these flowers I felt like it needed something more, so I added more texture and more colors to make these flowers more peaceful.” — Designed by Caroline Flynn from the United States.
- preview
- with calendar: 320x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440
- without calendar: 320x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440
“Inspired by the upcoming 2027 edition of SmashingConf Amsterdam.” — Designed by Ricardo Gimenes from Spain.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
Designed by James Lucia from Covington Township, Pennsylvania.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“June is our favorite time of the year because the keenly anticipated sunny weather inspires us to travel. Stuck at the airport, waiting for our flight but still excited about wayfaring, we often start dreaming about the new places we are going to visit. Where will you travel to this summer? Wherever you go, we wish you a pleasant journey!” — Designed by PopArt Studio from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“In this illustration, Earth is planting a little tree — taking care, smiling, doing its part. It’s a reminder that even small acts make a difference. Since World Environment Day falls in June, there’s no better time to give back to the planet.” — Designed by Ginger IT Solutions from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1020, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“A vibrant June wallpaper featuring strawberries and fresh oranges, capturing the essence of early summer with bright colors and seasonal charm.” — Designed by Libra Fire from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Some of my favorite things to do are reading and listening to music. I know that there are a lot of people that also enjoy these hobbies, so I thought it would be a perfect thing to represent in my wallpaper.” — Designed by Cecelia Otis from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“Nice weather has arrived! Clean the dust off your bike and explore your hometown from a different angle! Invite a friend or loved one and share the joy of cycling. Whether you decide to go for a city ride or a ride in nature, the time spent on a bicycle will make you feel free and happy. So don’t wait, take your bike and call your loved one because happiness is greater only when it is shared. Happy World Bike Day!” — Designed by PopArt Studio from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Summer rains, sunny days, and a whole month to enjoy. Dive deep inside your passions and let them guide you.” — Designed by Ana Masnikosa from Belgrade, Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“In celebration of high school and college graduates ready to make their way in the world!” — Designed by Bri Loesch from the United States.
- preview
- without calendar: 320x480, 1024x768, 1280x1024, 1440x900, 1680x1050, 1680x1200, 1920x1440, 2560x1440
Designed by Xenia Latii from Germany.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“The month of warmth and nice weather is finally here. We found inspiration in the World Oceans Day which occurs on June 8th and celebrates the wave of change worldwide. Join the wave and dive in!” — Designed by PopArt Studio from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Summer vibes…” — Designed by Antun Hirsman from Croatia.
- preview
- without calendar: 640x480, 1152x864, 1280x1024, 1440x900, 1680x1050, 1920x1080, 1920x1440, 2650x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“It’s summer! Go out, explore, expand your horizons!” — Designed by Dorvan Davoudi from Canada.
- preview
- without calendar: 800x480, 800x600, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“This piece was inspired by the My Little Pony cartoon series. Because those ponies irritated me so much as a kid, I always wanted to create a bad-ass pony.” — Designed by Zaheed Manuel from South Africa.
- preview
- without calendar: 800x600, 1024x768, 1280x960, 1280x1024, 1680x1050, 1920x1200, 2560x1440, 2880x1800
“I love creating fun and feminine illustrations and designs. I was inspired by juicy tropical pineapples to celebrate the start of summer.” — Designed by Brooke Glaser from Honolulu, Hawaii.
- preview
- without calendar: 640x480, 800x600, 1024x768, 1152x720, 1280x720, 1280x800, 1280x960, 1366x768, 1440x900, 1680x1050, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“I grew up with cats around (and drawing them all the time). They are so funny… one moment they are being funny, the next they are reserved. If you have place in your life for a pet, adopt one today!” — Designed by Karen Frolo from the United States.
- preview
- without calendar: 1024x768, 1024x1024, 1280x800, 1280x960, 1280x1024, 1366x768, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“I’ve waited for this summer more than I waited for any other summer since I was a kid. I dream of watermelon, strawberries, and lots of colors.” — Designed by Kate Jameson from the United States.
Bauhaus“I created a screenprint of one of the most famous buildings from the Bauhaus architect Mies van der Rohe for you. So, enjoy the Barcelona Pavillon for your June wallpaper.” — Designed by Anne Korfmacher from Germany.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Nathalie Ouederni from France.
Papa Merman“Dream away for a little while to a land where June never ends. Imagine the ocean, feel the joy of a happy and carefree life with a scent of shrimps and a sound of waves all year round. Welcome to the world of Papa Merman!” — Designed by GraphicMama from Bulgaria.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“June 21 marks the longest day of the year for the Northern Hemisphere — and sunsets like these will be getting earlier and earlier after that!” — Designed by James Mitchell from the United Kingdom.
- preview
- without calendar: 1280x720, 1280x800, 1366x768, 1440x900, 1680x1050, 1920x1080, 1920x1200, 2560x1440, 2880x1800
“Inspired by the eternal forward motion to get better and excel.” — Designed by Zachary Johnson-Medland from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“June brings the start of summer full of bright colors, happy memories, and traveling. What better way to portray the goodness of summer than through an ocean folk art themed wallpaper. This statement wallpaper gives me feelings of summer and I hope to share that same feeling with others.” — Designed by Taylor Davidson from Kentucky.
Ice Creams Away!“Summer is taking off with some magical ice cream hot air balloons.” — Designed by Sasha Endoh from Canada.
- preview
- without calendar: 320x480, 1024x768, 1152x864, 1280x800, 1280x960, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1920x1080, 1920x1200, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1366x768, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“In the sunset, the crabs come to the surface. That little boat can’t sail, but after seeing the crabs it gets power and finally… it sails!” - Designed by Veronica Valenzuela from Spain.
- preview
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
“On June 5th, we celebrate World Environment Day — a moment to pause and reflect on how we impact Earth’s health. A few activities represented in this visual include conserving energy and water, shopping and growing local, planting flowers and trees, and building a sustainable infrastructure.” — Designed by Mad Fish Digital from Portland, OR.
Shine Your Light“Shine your light, Before the fight, Just like the sun, Cause we don’t have to run.” — Designed by Anh Nguyet Tran from Vietnam.
- preview
- without calendar: 768x1280, 1024x1024, 1280x800, 1280x1024, 1366x768, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Feeling inspired? We’ll publish the July wallpapers on June 30, so if you’d like to be part of the collection, please don’t hesitate to submit your design. We are already looking forward to it!
Algorithmic Theming Engines: Building Self-Correcting Color Systems With `contrast-color()`
The HTTP Archive Web Almanac has been tracking color contrast failures for years. The numbers have barely moved. After half a decade of design system tooling, accessibility linters, and entire JavaScript libraries dedicated to computing readable text colors, 70% of websites still fail basic WCAG contrast checks in 2025. The WebAIM Million paints an even grimmer picture — 83.9% of homepages flagged for low contrast text in 2026, up from 79.1% in 2025. The rate improves by maybe a few percentage points per year on one benchmark and actually gets worse on another. That’s not progress — that’s proof that relying on runtime JavaScript for something this fundamental doesn’t scale across the open web. We didn’t need better libraries. We’ve needed better CSS.
The contrast-color() function is that better CSS. One declaration. The browser runs the contrast math during style computation, before the page paints, and hands you the right text color. No library, no build step, no hydration flash.
Note: If you’ve seen it called color-contrast() in older articles and spec drafts — that name was changed, and the old syntax no longer works in any browser.
What It Does (And What It Doesn’t)The Level 5 version is simple. You give it a color. It gives you back black or white, whichever has more contrast against your input.
.button { background-color: var(--brand-color); color: contrast-color(var(--brand-color)); }Change --brand-color to neon green, text goes black. Change it to midnight navy, text goes white. Swap themes at runtime via JavaScript and the text adapts instantly — no event listeners, no recalculation.
A few things to know about the current version:
- It returns a <color>, not a number. You get an actual color value (black or white), you can use anywhere CSS accepts a color.
- Black or white only, for now. Candidate color lists and target ratios are planned for Level 6.
- No keywords. If you’ve seen max in older blog posts, that was stripped from the spec. Using it will silently break your declaration.
- As mentioned above, this function used to be called color-contrast() in early drafts. That name is dead — the CSSWG renamed it to follow the convention that CSS functions are named for what they return. color-mix() returns a color. contrast-color() returns a color. The old color-contrast() name sounded like it returned a contrast ratio (a number like 4.5), which was misleading. Any tutorial from 2021–2023 showing color-contrast() syntax won’t work in current browsers.
This function lives across two specifications. That’s unusual and worth understanding.
CSS Color Level 5 defines what browsers ship today. One color in, black or white out. The algorithm is deliberately marked “UA-defined”, meaning the browser decides what math to use internally. Right now, every engine uses WCAG 2.x relative luminance. But that “UA-defined” label isn’t accidental — it’s a planned escape hatch.
You’ll see APCA (Accessible Perceptual Contrast Algorithm) mentioned a lot in this context. APCA models how human eyes actually perceive contrast, factoring in font weight, spatial frequency, and ambient light — a genuine improvement over the WCAG 2.x formula. By not locking “use WCAG 2.x” into the Level 5 spec, browser vendors could swap to APCA later without breaking any existing code. If the spec had shipped with a wcag2() keyword as the default, every site using it would’ve been stuck on the old math permanently.
But APCA’s future is far less certain than the hype suggests. Adrian Roselli’s “WCAG3 Contrast as of April 2026” lays out the current situation clearly: APCA was pulled from the WCAG 3 working draft in mid-2023 after failing to gain enough Working Group support. The WCAG 3 spec currently says the contrast algorithm is “yet to be determined,” and the standard itself may not be finalized until 2030 or later. Roselli also filed a Chromium issue in May 2024 asking for the “Advanced Perceptual Contrast Algorithm” experiment flag to be removed from DevTools entirely, arguing that the implementation is outdated and risks misleading developers into thinking APCA is further along — or more official — than it actually is. That issue is still open.
None of this means APCA is dead. The research behind it is peer-reviewed and substantive, and its creator has noted that colors passing APCA guidelines greatly exceed WCAG 2 minimums in the vast majority of cases. But right now, there is no guarantee APCA will be the algorithm that replaces WCAG 2.x — and that uncertainty matters for contrast-color(). If a different algorithm wins out, or if WCAG 3 adopts something entirely new, the “UA-defined” label means browsers can adapt without breaking your code. It also means the Level 6 features — candidate color lists, target ratios, the tbd-fg/tbd-bg keywords — are all designed around an algorithm that may or may not materialize in its current form.
CSS Color Level 6 adds the extended syntax — candidate color lists and target contrast ratios:
/* Level 6 future syntax — not shipping yet */ color: contrast-color(var(--bg) tbd-bg wcag2(aa), #1a1a2e, #e2e8f0, #fbbf24);The browser would evaluate each candidate left to right and pick the first that meets the 4.5:1 AA threshold. The tbd-fg and tbd-bg keywords indicate whether the base color is foreground or background, which matters for directional contrast models like APCA. This is all Working Draft territory — doubly so given APCA’s uncertain status. Use the Level 5 version for now.
Browser SupportThis one’s in better shape than most new CSS features. All three major engines have shipped it in stable releases: Chrome 147 (April 2026), Firefox 146, and Safari 26.0. It reached Baseline Newly Available status in April 2026. Check caniuse for the full version matrix. All three engines pass the Web Platform Tests for contrast-color(), which means the edge cases (e.g., tie-breaking logic, color space conversion, syntax parsing) behave the same across browsers.
The raw global support percentage on caniuse looks low, but that mostly reflects enterprise browsers and people who never update. If you’re reading this, your browser almost certainly supports it already.
Progressive enhancement is straightforward using @supports:
.card { background: var(--bg); color: #fff; text-shadow: 0 0 4px rgb(0 0 0 / 0.8); } @supports (color: contrast-color(red)) { .card { color: contrast-color(var(--bg)); text-shadow: none; } }Older browsers get white text with a dark shadow for legibility. Supporting browsers get the native calculation. Nobody sees broken text.
One thing to watch for: automated accessibility scanners (Lighthouse, Axe, etc.) can’t evaluate text-shadow. They only look at the computed color against background-color. So the fallback will still get flagged as a contrast failure in CI/CD pipelines, even if the shadow makes the text perfectly legible to human eyes. If your team runs automated a11y checks, you may need to allowlist that specific rule or add a comment explaining why the flag is a false positive.
A note on PostCSS:There’s a plugin (@csstools/postcss-contrast-color-function) that evaluates contrast-color() at build time. It works for static colors like contrast-color(#ff0000). But the moment you use a custom property — contrast-color(var(--bg)) — the plugin can’t help because it has no access to runtime values. If your theming is dynamic (which is the whole point of doing this), skip the polyfill and rely on @supports. The Gotchas It Doesn’t Guarantee Perceptual or AAA Compliance
This can trip people up: “I used the contrast function, so my site passes accessibility checks now, right?”
Mathematically? Usually yes. There is a persistent myth that for certain “mid-tone” backgrounds, both black and white fail the standard WCAG 4.5:1 AA ratio. That’s mathematically false. Under the WCAG 2.x relative luminance formula, there is absolutely no background color where both pure black and pure white fail AA. One (or both) will always pass.
Take #2277d3 (a medium blue). It sits right on a mathematical knife-edge where both black and white actually pass AA (both hit roughly 4.58:1). contrast-color() will hand you whichever has the slight mathematical edge.
But here is the actual gotcha: the WCAG 2.x math has known perceptual blind spots. That same #2277d3 with black text mathematically passes AA, but to human eyes, it can be incredibly difficult to read. contrast-color() gives you mathematical compliance, which is great for automated audits, but that doesn’t always equal perceptual accessibility. (This is exactly why APCA exists and why the spec was designed to let browsers swap algorithms later.)
Furthermore, if you’re aiming for the stricter WCAG AAA standard (7.0:1), a true dead zone does exist. For backgrounds with a luminance between roughly 10% and 30%, neither black nor white will hit 7:1. In those cases, contrast-color() can’t save you — it just hands you the “least bad” failing option.
Transitions Snap, Not FadeIf you’re animating a background from white to black on hover:
.btn { background-color: #fff; color: contrast-color(#fff); /* black */ transition: background-color 1s, color 1s; } .btn:hover { background-color: #000; color: contrast-color(#000); /* white */ }The background fades smoothly over one second. But because the Level 5 output is a discrete value (black or white), the text color can’t be interpolated. It snaps.
And here is the visual gotcha: the snap doesn’t happen halfway through. If you’ve been building themes for a while, you probably have muscle memory from the old Sass days, where we checked if lightness($bg) > 50%. That relied on HSL lightness, where 50% is the geometric midpoint.
But WCAG 2.x relative luminance is a non-linear scale. Under the WCAG formula, the mathematical tipping point — where black and white have identical contrast against the background — actually occurs at approximately 18% relative luminance (specifically ~17.9%).
Because of that, the visual behavior during a white-to-black fade is heavily skewed. The text doesn’t snap in the middle. It stays black for the vast majority of the animation, only snapping to white at the very tail-end of the transition when the background gets extremely dark. It’s a jarring, late hard cut.
You might assume transition-behavior: allow-discrete fixes this. It doesn’t. allow-discrete does not fix the jarring visual experience because it cannot interpolate a binary output; it only shifts the timing of the hard snap to the 50% mark of the animation duration. If you need smooth text color transitions, you’ll have to layer color-mix() or manage the crossfade yourself.
Tie Goes To WhiteIf the background is a perfect middle gray where both black and white produce identical contrast ratios, the spec has a hardcoded tiebreaker: white wins. Not a big deal in practice, but worth knowing if you’re debugging gray palettes and the text isn’t doing what you expect.
Gradients And Images Are OutThe function takes a flat <color> value. You can’t pass it a gradient or a url(). contrast-color(linear-gradient(...)) is a parse error. If your background is a photo or a complex gradient, you still need JavaScript or manually color-pick for overlay text.
Transparent Colors Are Composited FirstPass a semi-transparent color, and the browser blends it against an assumed opaque canvas (usually white) before running the contrast math. It’s not ignoring your alpha channel — it’s compositing it. But the result might surprise you if you expected the function to “see through” to whatever’s actually behind the element.
Windows High Contrast ModeIf a user enables Windows High Contrast, the forced-colors: active media query kicks in and the browser aggressively overwrites author-defined colors. contrast-color() bows out — forced system colors like CanvasText take over completely. You don’t need to write manual media queries to undo your contrast logic; the browser handles the hierarchy.
Combining It With Other Color FunctionsBlack or white sounds limiting, but once you feed that output into other CSS color functions, you can build an entire component palette off a single custom property.
Brand-Tinted Contrast With Relative Color SyntaxPure black text on a vibrant card looks fine. Pure white on a coral card can feel flat. What if the contrast text was a very dark or very light tint of the background color instead?
Kevin Hamer explored related territory in his CSS-Tricks piece “Approximating contrast-color() With Other CSS Features”, where he used OKLCH lightness and round() to approximate the black/white switch without contrast-color() — essentially oklch(from <color> round(1.21 - l) 0 0). That’s a polyfill strategy: get the binary light/dark decision working in browsers that don’t support the native function yet. What we’re doing here is different — we start with contrast-color()’s native output and then enrich it by injecting the background’s own hue:
.card { --bg-hue: 260; /* Indigo */ --bg: oklch(0.6 0.1 var(--bg-hue)); background: var(--bg); /* Pull L from the black/white contrast color, but inject subtle chroma and the background's hue */ color: oklch(from contrast-color(var(--bg)) l 0.05 var(--bg-hue)); }When contrast-color() returns white, l is 1 (full lightness). When it returns black, l is 0. By pulling the background’s hue back in and adding a touch of chroma, you get text that reads as a deep dark indigo or a pale icy indigo instead of generic black/white. Hamer’s approach gives you the black/white decision without browser support; this one takes the decision the browser already made and gives it personality.
Fair warning: By tweaking the lightness and chroma of the black/white output, you can push a borderline contrast ratio into failing territory. Always run your tinted output through an accessibility linter before shipping.
Also worth noting: This example chains two very modern features — contrast-color() and oklch(from ...). If either one isn’t supported, the entire declaration fails silently. Your @supports block needs to test for both:
@supports (color: contrast-color(red)) and (color: oklch(from red l c h)) { /* Safe to use both */ } Softened Contrast With color-mix()Similar idea, simpler API. Mix the sharp black/white output back into the background to soften it:
.alert { --bg: var(--alert-color); background: var(--bg); /* 80% contrast, 20% background = softer but readable */ color: color-mix(in oklch, contrast-color(var(--bg)) 80%, var(--bg)); /* 40% contrast for a subtle border */ border: 1px solid color-mix(in oklch, contrast-color(var(--bg)) 40%, var(--bg)); }One custom property driving text, border, and potentially box-shadow or outline. Change --alert-color and the entire component recalculates.
This pattern also works well for ::placeholder text, which is a common pain point in dynamic theming. Placeholder text should be readable but visually softer than the input’s main text — color-mix() with contrast-color() gets you there:
input { --bg: var(--input-bg); background: var(--bg); color: contrast-color(var(--bg)); } input::placeholder { color: color-mix(in oklch, contrast-color(var(--bg)) 50%, var(--bg)); }50% mix gives you a muted but legible placeholder that adapts automatically to whatever background the input sits on.
Theme-Aware Contrast With light-dark()For apps that support system light/dark mode:
:root { color-scheme: light dark; --surface: light-dark(#fff, #121212); } .component { background: var(--surface); color: contrast-color(var(--surface)); }When the operating system switches to dark mode, --surface resolves to #121212, and contrast-color() returns white. No media queries, no JavaScript theme detection. The whole chain resolves natively.
What You Can Remove From Your BundleThe practical payoff: every one of these libraries existed because CSS couldn’t do contrast math. If you’re only using them for readable-text-color selection, you can pull them out of your runtime entirely:
Library Size What it did chroma-js ~14 kB Color parsing, luminance calc, readable color selection polished ~11 kB readableColor() for styled-components tinycolor2 ~5 kB Hex parsing, WCAG contrast ratio mathYou might still need these for generating complex color scales, but the contrast-for-readability use case is now covered natively.
Beyond bundle size, there’s a performance angle that’s easy to overlook. Those JavaScript libraries don’t just cost you network bytes — they run on the main thread. Every time a theme changes or a component mounts with a dynamic background, your JS has to parse the color, compute luminance, decide black or white, and write the result back to the DOM. That’s main-thread work competing with layout, event handlers, and everything else your app is doing. contrast-color() moves all of that into the browser’s native style computation phase — heavily optimized C++ that runs before paint. For apps with lots of themed components, that’s a real difference in responsiveness.
There’s also a subtle bug that goes away: hydration flash. In React or Vue SSR apps, the server renders HTML without JavaScript. The client then hydrates, running JS to calculate contrast and inject the correct text color. For a brief window between initial paint and hydration, the text is either invisible or the wrong color. Moving contrast into CSS eliminates that entirely — the browser resolves the correct color during the initial paint, before JavaScript loads.
What We Used To DoFor context on what this replaces:
Sass era. You’d write a function that checked lightness($bg) > 50% and returned black or white at compile time. Worked for static themes. Completely useless for user-picked colors, CMS palettes, or dark mode, because the output was baked into the CSS file and could never change at runtime.
The variable toggle hack. When CSS custom properties shipped, people got creative. GitHub used a version of this for their issue label picker — splitting colors into --r, --g, --b channels, calculating Rec.709 luminance inside calc(), multiplying by negative infinity, and clamping to 0 or 1. It worked. It was also unreadable, unmaintainable, and would break silently if you got one parenthesis wrong. (Kevin Hamer’s OKLCH-based approximation is the most elegant version of this lineage — cleaner math, better perceptual alignment — but it’s still a workaround for a function that now ships natively.)
contrast-color() replaces all of these approaches with a single function call. And because the spec lets browsers upgrade the underlying algorithm, your code won’t need to change if and when a successor to WCAG 2.x contrast math lands — whether that’s APCA or something else entirely.
That 70% failure rate was never about developers refusing to care about contrast. It was about the distance between caring and shipping — the library, the build step, the runtime calculation, the hydration flash, the one component someone forgot to wire up. Every gap in that chain was a spot where accessibility quietly dropped out.
contrast-color() doesn’t make developers care more. It makes caring cost nothing.
Your Prototype Is Not Being Honest With Your Users (And Here’s How To Fix It)
This article is a sponsored by ProtoPie
There’s a moment in almost every usability session where a participant pauses at the login screen, types something, and glances up: checking whether they’re “doing it right.” That pause is a clear sign. They’ve already clocked that this isn’t a real app, and every data point collected after that moment is filtered through that awareness.
In financial product testing, the problem is sharper. Finance users are trained to notice when something feels off: a balance that doesn’t add up, a field that accepts anything. When a banking prototype skips real authentication, participants don’t just disengage; they stop mid-session to flag it. The team walks away with findings that reflect how users behave in a demonstration, not in a real product.
The fix is narrower than you’d think. Identify the moment where participant trust is established and make that interaction real. In a banking app, that moment is the login.
This tutorial builds it: credentials that validate, a live error state, and a biometric animation that feels native — no code required.
What We’re Building: A Login That Behaves Like A Shipped ProductThe login flow, built around Pie Bank, a mobile banking prototype, includes functional text inputs, a masked password field, credential validation, a live error state, and a Face ID animation timed to feel indistinguishable from iOS.
What you’ll need:
- A login UI from Figma (or any supported design tool)
- ProtoPie Studio — free to start, everything in this tutorial works on the free plan
- A Lottie file for the Face ID animation (this one is what we used)
- The finished Pie Bank prototype file — download it to follow alongside, or use it as a reference after you build
In Figma, open the ProtoPie plugin with your login frame selected and choose Scene when exporting. Flattened collapses everything into a single image; Scene preserves your layer hierarchy so every element arrives in ProtoPie as a separate, targetable layer.
Before moving on: rename every layer meaningfully. “Input Username” not “Rectangle 14”. You’ll reference these names in formulas: vague names compound into real time lost.
Step 2: Swap Static Fields For Inputs That Actually Accept TextProtoPie’s native Input layer accepts real keyboard entry: participants type actual text, not tap a placeholder. Go to Text → Input, drag an Input layer onto your canvas, and nest it inside your username field group. Match it visually: placeholder text Username, background fill and font to match your design.
Hit preview. Click the field. Type. That’s the prototype starting to behave like an app rather than depicting one.
Rename this layer Input Username, duplicate it, and nest the copy inside your password field group.
Step 3: One Property Change Masks The PasswordOn the duplicated layer, change placeholder text to Password and set Type to Text Password. ProtoPie handles the masking: no custom logic needed.
Preview both fields: username shows text, password shows dots. It already feels real, and you haven’t written a single condition.
Step 4: Build The Destination Scene Before Wiring NavigationAdd a new scene, even a blank one. The most common sequencing mistake in ProtoPie is trying to wire a navigation response before a destination exists. Create it first.
Step 5: Wire The Button: It Works, But It Still Lets Everyone ThroughSelect Log In, add a Tap trigger, set response to Jump, target your dashboard scene, transition Slide in from right to left.
Preview and tap. It navigates: but for any input, including nothing. The prototype is still lying. The next two steps are the fix.
Step 6: Add Variables So The Prototype Remembers What Was TypedAt the bottom-left of ProtoPie, add two Text type variables: username and password. Bind each to its input layer with a formula:
input("Input Username").text input("Input Password").textEnable the debug icons: green overlays will show live variable values as you type. When you see your keystrokes appear in real time, the binding is confirmed.
Step 7: Add A Condition So Only Valid Credentials Get ThroughGo back to the Tap trigger on the login button. Add a Condition with two rules, both must be true:
- username equals `alex.c@gmail.com`
- password equals ABC123
Move the Jump response inside this condition. Wrong credentials, empty fields, wrong format: none get through. Participants now have to actually log in. That single constraint changes the texture of every test session that follows.
Step 8: Build The Error State, The Interaction Most Prototypes SkipFind your error message layer, rename it Error Text, set initial opacity to 0. Add a second condition (the inverse of the first), and inside it, a Change Property response setting Error Text opacity to 100.
Wrong credentials: error appears. Correct credentials: dashboard. Two outcomes: which is what makes this testable, not just demonstrable.
Step 9: Add the Face ID Animation, The Detail That Makes Testers Ask “Is This Real”Go to Media, drag a Lottie layer onto canvas, load your Face ID file, and position it off-screen above the iPhone frame. On your Login with Face ID button, add a Tap trigger (rename it Tap Face ID) with four responses in sequence:
- Move: Lottie container to Y: 60
- Playback: Seek: time 0s (resets so it always plays from the start)
- Playback: Play: Lottie file
- Jump: to dashboard
Without delays, all four responses fire at once and the scene jumps before the animation plays. Add offsets:
Response Delay Move 0s Seek 0s Play 0.5s Jump 1sEnable Reset selected scenes on Jump: without it, navigating back leaves the animation stuck at Y: 60.
Preview: tap Face ID, animation drops in, plays, screen transitions. A biometric login indistinguishable from the real thing.
You can download Pie Bank, Chapter 1: Login Flow and explore it freely. A Login This Real Changes What You Can Learn From Your PrototypeWhen authentication actually works, the error state becomes a genuine research touchpoint: do users understand the message, do they retry, do they reach for Face ID instead? These are questions a faked login can’t answer.
In stakeholder reviews, the flow speaks for itself. In engineering handoff, the interaction panel documents the behavior (conditional logic, variable bindings, timing) so engineers see intent, not interpretation.
This is why FinTech teams invest in login fidelity even when the login isn’t the feature being tested. It’s where participant trust is established. Get it right, and everything downstream produces better signal.
This tutorial is part of the FinTech Prototyping with ProtoPie series on the ProtoPie blog. The series builds Pie Bank from the ground up across four chapters, covering the dashboard, money transfer logic, and camera integration. If this tutorial was useful, the rest of the series goes further.
Four Levels Of Customer Understanding
Many companies think they know fairly well what their users want and need, and how they make their decisions. Yet most of the time these are merely big assumptions and big hunches — with little real evidence to support them. In practice, obvious reasons might be true, but they rarely paint the full picture.
To understand our customers, we must triangulate across four levels of customer understanding by Hannah Shamji. It’s a useful way to think about the underlying reasons for user behavior, hidden motivations, and the complex layers of messy and noisy reality that are often overlooked. Let’s see how it works.
Don’t Ask Users Your Burning QuestionsTo learn about customers, it might seem reasonable to ask people what they think and draw conclusions from it. But it’s rarely an effective way to get actionable answers. In fact, as it turns out, what people think, feel, say, and _do_ are often very different things.
As Erika Hall wrote, asking a question directly is the worst way to get a true and useful answer to that question. We don’t always understand or are aware of our true motivations. We often apply our own context and interpretations to questions.
We also exaggerate (a lot!). We focus on edge cases and unrealistic scenarios, and we favor short-term goals over long-term goals. So if users say that they absolutely need to compare products in a table, it doesn’t mean that they couldn’t get to their underlying goal without it.
“Possible” vs. “Probable”Just to indicate how tricky listening to words alone is: even little nuances in words chosen matter. In practice, users are rarely precise in expressing their thoughts, and a good example is the distinction between possible, plausible, and probable, as discovered by Thomas D'hooge.
A study on Dutch verbal probability terms shows how unreliable the choice of words is. While extreme words have some agreement, terms like “possible,” “maybe,” “uncertain,” or “likely” lead to a wide spread of interpretations. So we shouldn’t rely on what people say, but rather try to go deeper.
The Levels Of UnderstandingTo get a more realistic and less biased view of customers’ needs, we need to understand a broader picture across 4 levels:
- Level 1: “What they say”
Easier to collect, but mostly opinions, and most unreliable. People often explain their behavior through the lens of how they perceive it, or how they want it to be perceived, which isn’t always accurate. We shouldn’t rely too much on CRM data, surveys, or polls. - Level 2: “What they think and feel”
Gives more context, but is still heavily shaped by memory and personal preferences. Good user research and interviews help us understand expectations and experiences. - Level 3: “What they do”
We study actual behavior, actions taken or skipped, usage data, and analytics. We run task analysis and workflow analysis to understand how people use the product. - Level 4: “Why they do it”
We study underlying motivations and root causes, through observations of real workflows and in-depth interviews. Typically, it requires a trustworthy relationship with the user, repeat interviews, and task walkthroughs.
Personally, I wouldn’t recommend NPS (alternative). It’s worth noting that different levels might reveal conflicting or contradictory data. To get a better understanding, we need to triangulate and reconcile data with mixed-method research.
Capturing Emotions And NuanceEmotions are always difficult to capture, but they are easier to spot once you observe people doing what they need to do without external influence or interruptions. The ability to positively impact users grows by moving from sympathy to empathy or even compassion, as articulated by Sarah Gibbons.
In the past, I was using “speak-aloud” protocol and asked users to walk me through their thought process as they were completing tasks. But it actually turns out to be quite disruptive. Because people are focused on speaking at the same time while solving a task, many emotions remain hidden or obscured by their language.
So, when conducting usability testing, I don’t ask users to speak through their experience. Instead, I observe where they tap or hover with the mouse, where their mouse circles without an action, where they scroll, and how long. Eventually, when a user confirms that they are done or that they are stuck, I ask questions.
The Emotion Wheel (website) by Geoffrey Roberts is a helpful little tool for better describing a range of emotions during user interviews or design sessions. It certainly needs refinement for product design needs, but it helps us get more precise about the sentiment customers or colleagues might be experiencing, moving beyond just “good” or “bad”.
One helpful trick is to use mirroring — repeating what a user has said, or ask the same question twice, just paraphrasing it. Or navigating the emotions wheel (see above) to better capture and understand the emotion.
These strategies help uncover some of the issues that perhaps didn’t come up in the first answer. That’s also when a user tends to add more useful context and details as they explain their confusion.
Emotions Aren’t EverythingSome people strongly disagree:
“Our work is about others — their problems, their pain, their mess. Our job is to make sense of it and then do something about it. Not to emote or perform but to act on and solve it. There is a flawed belief that to build great things, you first need to emotionally fully absorb someone else’s experience.”— Alin Buda
I think that Alin brings up a very strong argument, and personally, I find it difficult to disagree with. However, I do see user’s emotional response as a signal of how well the product is working for them. How engaged or detached they are in their journey, how they react to aesthetics, how confused or confident they are.
Ultimately, these are signals. To make a difference, we must go beyond emotions and explore what people actually do. Usually, this means relentlessly observing, diagnosing, and focusing on underlying user needs.
Observe And Diagnose, Don’t ValidateInstead of asking, we need to observe. Usually, I focus on small things that make or break an experience. I see where users lose time, repeat actions, hover without clicking, or click and then go back. Pay attention to subtle cues like scratching their neck, raising eyebrows, or expressions of worry, joy, or confusion.
Many companies talk about “validation” through user testing, but often that means simply confirming existing assumptions. But we should instead diagnose existing behavior without preconceived notions or affiliations. We don’t validate — we actually research instead.
That research means not just understanding customers’ real motivations, but also risks, doubts, concerns, worries, and perhaps even harms.
The only way to get there is by building a sincere, honest, and trustworthy relationship — one that feels right and resonates deeply. When customers truly care and want to help, getting to a real understanding becomes much, much easier.
Practical Ways To Uncover User NeedsWe don’t need expensive tools to uncover user needs. David Travis provides a fantastic overview of helpful strategies to do just that. Here are some initiatives to spread the word about real user’s struggles or gain a deeper understanding of user needs:
- Exposure hours, when every employee must be exposed to their customers for at least 2 hours every 6–12 weeks.
- Live UX testing, where we invite everyone in the company to join and observe.
- Co-design with users, where we show new features and ask users to rank them.
- Helpdesk insights, where we ask for frequent complaints and questions from the support every 3–6 months.
- Listening in, where we tune in on a customer service call, web chat, or eavesdrop where users hang out.
The core idea here is that you don’t need extensive and expensive tools to uncover user needs. You need to create spaces where customers’ struggles can be exposed and make these struggles visible across the entire company.
It can be short video clips of user sessions or a monthly newsletter with what we learned this month. Making these pain points visible can rally everyone from marketing to engineering to keep users’ struggles at the back of their minds.
Wrapping UpTo make an impact, we must go way beyond user feedback. It’s never enough to listen to surveys — we must observe customers’ actual behaviors and build relationships to truly understand their goals and their motivations.
And most importantly, we need to understand what questions we actually want to have answered. Not what “validation” we need to move on with the project, but what we don’t know and what we need to research.
Without it, everything else is merely hunches and assumptions — and often wrong and expensive ones.
Meet “Measure UX & Design Impact”Meet Measure UX & Design Impact, Vitaly’s practical guide for designers and UX leads on how to track and visualize the incredible impact of your UX work on business — with a live UX training later this year. Jump to details.
Meet Measure UX and Design Impact, a practical video course for designers and UX leads. Video + UX Training$ 495.00 $ 799.00 Get Video + UX Training25 video lessons (8h) + Live UX Training.
100 days money-back-guarantee.
25 video lessons (8h). Updated yearly.
Also available as a UX Bundle with 3 video courses.
- Four Levels of Customer Understanding, by Hannah Shamji
- 60 Ways To Understand User Needs, by David Travis
- Emotion Wheel Toolkit (PNG), by Geoffrey Roberts
- Feelings Wheel PDF
- Feelings Wheel Online
- My Case Against Empathy, by Alin Buda
- Possible vs. Probable, by Thomas D’hooge
- Communicating probability: a multinational study of the interpretation of verbal probability terms, by Maarten C. de Vries, Marjolijn L. de Boer, and Martine Bouman.
- Deploy Empathy: A practical guide to interviewing customers, by Michele Hansen
- Humankind, by Rutger Bregman
Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()`
You know that thing where you have a grid of cards, and you want them to fade in one after another? That staggered cascade effect. Looks great. Should be simple. And yet every time I’ve built it, the implementation has made me feel like I’m doing something fundamentally stupid.
What’s ComingThe current spec only counts all element siblings. But the CSSWG has documented a planned extension in issue #9572: an of <selector> argument, matching what :nth-child() already supports.
Something like sibling-index(of .active) would let you count only siblings matching a specific selector. An element that’s the eighth child overall but the third .active child would return 3. For dynamic UIs where you’re filtering or toggling visibility, that would keep the index sequential without requiring DOM manipulation.
There’s also been CSSWG discussion around children-count() and descendant-count() functions — the first would tell you how many children an element has (useful for parent-driven layouts), the second would count all descendants recursively. Both are still at the proposal stage, but they’d round out the tree-counting story: sibling-index() and sibling-count() give you the horizontal view (where am I among my peers?), while children-count() and descendant-count() would give you the vertical view (what’s below me?).
That feeling I mentioned at the top — writing ten :nth-child() rules for a staggered animation and wondering if you’re missing something obvious? You weren’t. The obvious thing just didn’t exist yet.
Ten Data-Backed Truths Of User Experience ROI
In the high-stakes economy of today, the cost of a friction-heavy interface is no longer just “lost clicks”, but potentially millions in wasted engineering spend and lost business value. As a veteran UX designer who has helped build digital products since the early mobile-first era, I’ve watched business leaders shift from viewing design as a “cosmetic preference” to recognising that user experience is actually the primary engine of business survival.
A UX design role is as much about research and analytics as it is about pixels, and I believe that hard data is the only tool powerful enough to bridge the gap between design and the boardroom. Facts don’t just advocate for the user; they prove that UX is a non-negotiable requirement for a healthy bottom line. Even in the rooms where decisions are made, UX is frequently undervalued as a ‘visual’ role. I’ve learned that the most effective way to dismantle this myth is through data.
The following ten facts represent the current reality of the digital world. These are not just “design tips”; they are the clinical, data-backed pillars for financial growth in a saturated market. Some of these facts are also commonly used by designers as best practices.
For example, I once led a B2C mobile design project, where I was able to strip 1.2 seconds off the mobile load time by reducing and removing some of the visual assets. The result was an immediate 12% lift in completed transactions, proving that in UX, every tenth of a second is a direct lever for revenue.
1. Fixing Issues In The Design Phase Is 100 Times CheaperOne of the most compelling financial arguments for UX is the 1:100 rule. Modern studies, such as from the IBM Systems Institute and Sugue Technologies, show that fixing an error after a product has been developed and launched can be up to 100 times more expensive than fixing it during the initial design and prototyping phase.
Think of UX as “engineering insurance.” By the time a developer touches the code, every interaction should have been validated. If you discover a fundamental navigation flaw after launch, you aren’t just paying for the fix; you’re paying for technical debt, lost developer time, and the revenue lost while users struggle with a broken flow.
2. Performance Impacts User ExperienceIn the current landscape, performance is the essential foundation of user experience. A beautiful interface is worthless if the user bounces before it renders. The data is uncompromising: 47% of users expect a page to load in two seconds or less, and missing this window is a financial catastrophe. A mere one-second delay can reduce conversions by 20% and satisfaction by 16%, while retail businesses lose an estimated $2.6 billion annually to slow load times. When mobile load time moves from one to three seconds, the bounce rate spikes by 32%, and by the third second, conversion rates typically plummet from 40% to 29%.
However, this volatility offers a massive lever for growth. Even a microscopic 0.1-second improvement can lift retail conversions by 8.4%, and travel site conversions by 10.1%. Improving your Largest Contentful Paint (LCP) by 31% — a benchmark 67% of websites achieved as of June 2025 — can drive a direct 8% increase in sales. As a long-time designer, I treat speed as a primary design element.
If the site isn’t instantaneous, the design hasn’t just failed — it effectively doesn’t exist. 3. Your Site Has 50 Milliseconds to Impress Your CustomersFirst impressions are both visceral and aesthetic. Research indicates that users form an opinion about a website’s visual appeal in approximately 50 milliseconds (0.05 seconds). That’s not a lot of time! This split-second “gut-feeling” is a survival mechanism that dictates whether a user stays to explore your value proposition or bounces immediately.
In the current market, 94% of first impressions are strictly design related. If your interface feels “off” or dated, users subconsciously project that lack of quality onto your entire product or service. Your content effectively doesn’t exist if your design hasn’t earned the five seconds of attention required to read it.
4. Hick’s Law: The Cost of OverwhelmStakeholders often think “more options” equals “more value.” Psychology proves the opposite. Hick’s Law states that the time it takes to make a decision increases with the number of options available.
Every extra menu item or form field is a “tax” on the user’s brain. As noted by Landbase, top-performing sites now achieve conversion rates exceeding 11%, while average performers struggle below 3%. Those performing well have applied personalization and optimization strategies to simplify the experience.
If you want to increase your revenue by tomorrow, find one field to delete from your checkout flow today. 5. White Space Improves Comprehension“White space” is often viewed as wasted real estate by non-designers. In reality, it is a tool for focus. Strategic use of white space can increase a user’s content comprehension by up to 20%.
White space prevents “cognitive load” from peaking. By giving the user’s eyes a place to rest, you guide them toward the most important elements, usually your “Buy” or “Sign Up” button. In 2026, as attention spans have dropped to roughly 8 seconds, simplicity is the ultimate luxury and a major driver of engagement.
For example, in a fintech dashboard I worked on, analyst users were feeling overwhelmed by a ‘data dump’ layout in some of the dashboard components. I applied more white space around the data to lower their cognitive load. Simply giving the data room to breathe led to a 25% decrease in time-on-task and a significant boost in trial-to-paid conversions.
6. The Power Of “Fake” ProgressOne of the most surprising psychological hacks in UX is that users will complete a task faster if they believe they have already made progress. This is known as the Goal Gradient Effect.
In a classic study, researchers found that a 10-stamp coffee card with two stamps already “pre-filled” was completed significantly faster than an 8-stamp card with zero pre-fills, even though the total spend required was identical. In digital design, showing a progress bar that starts at 15% (simply for creating an account) increases completion rates for onboarding by over 40%. We aren’t just designing screens — we are managing the user’s dopamine and sense of momentum.
7. Make Your Content ReadableMany stakeholders believe that cramming more text “above the fold” increases value. Data proves the opposite. Proper typography, specifically line spacing (leading) and paragraph width, can increase content comprehension and reading speed by up to 20%.
Optimal line height (generally 1.5x the font size) reduces “visual noise,” allowing the brain to process information with less cognitive effort. When users struggle to read your text due to tight spacing or small fonts, their “perceived effort” increases, leading to a higher bounce rate. Legibility is a conversion tool: if it’s hard to read, it’s hard to buy.
There are many ways to display more legible text. For example, if line spacing (leading) is too small or the font is too heavy, this also impacts readability.
8. Your Users Only Read 20% of Your ContentThis truth meshes well with the previous one. Users do not read your website; they scan it. On a typical web page, users read only about 20% to 28% of the text.
Because modern users scan in an F-pattern or Spotted pattern, designing for reading is a tactical error. We must design for scanning.
This requires the following:
- Bold headers that narrate the value proposition.
- Bullet points for key benefits.
- White space to connect users to key information (discussed in the previous truth).
- High-contrast call-to-action (CTA) buttons. If your core message is buried in a paragraph, it is invisible to nearly 80% of your audience.
I have heard of companies that waste six-figure budgets on massive user studies with 100 people, only to get buried in noise. The reality is that testing with just 5 users typically uncovers 85% of usability problems.
This is a mathematical sweet spot. After the fifth user, you reach the point of diminishing returns — you spend more money to find fewer new bugs. The competitive advantage belongs to small and frequent user testing activities. Test with 5 people, iterate, and test with 5 more. It is the most cost-effective way to build a bulletproof product.
Personally, I have followed this guideline many times during user testing activities, and I can confidently say that testing with 5 people does deliver the majority of issues in your design.
10. The Financial ROI of 9,900%Last, but definitely not least, the most staggering statistic in our industry remains consistent. On average, every $1 invested in UX returns $100. This 9,900% ROI isn’t magic, but the sum of increased conversion and reduced support.
A fully optimised UX design can improve conversion rates by up to 400%. Furthermore, intuitive design significantly lowers customer support requirements. When a product is self-explanatory, you don’t need a massive call centre to explain how to use it.
The Depth of UX InvestmentBeyond these individual statistics, we must address the cumulative effect of a mature UX practice. In my years of practising, the most successful firms are those that treat UX as a continuous improvement loop rather than a one-off project. The data shows that companies with high design maturity see 32% higher revenue growth and 56% higher total returns to shareholders compared to their less design-focused peers.
This discrepancy exists because mature UX organisations move beyond “user delight” and into “user efficiency.” When you shave 30 seconds off a workflow for a team of 1,000 employees, you aren’t just making them happier; you are reclaiming hundreds of thousands of dollars in annual productivity. This internal ROI is often overlooked, but it is just as vital as consumer-facing conversion rates.
Furthermore, the “experience gap” is real. 80% of companies believe they deliver a “superior experience,” but only 8% of customers agree. This massive disconnect represents a significant market opportunity for those willing to look at the hard data. By bridging this gap through continuous user testing and performance optimisation, you aren’t just improving a product but capturing market share that your competitors are leaving on the table.
The Impact of AIToday, we cannot talk about UX without talking about AI. However, AI hasn’t replaced these 10 facts, but it has accelerated the solution on some of these.
- Agentic UX
60% of designers are now building “AI agents” that take actions on behalf of the user, drastically reducing the impact of Hick’s Law by narrowing down choices before the user even sees them. - Real-Time Personalisation
32% of teams use AI to personalise interfaces in real-time, meaning the F-Pattern scanning habits are catered to by moving the most relevant content to exactly where that specific user’s eyes are likely to land. - Automated ROI
93% of designers are using generative AI tools to prototype faster, which brings the 1:100 Cost Ratio even lower by allowing us to find and fix errors before a single line of production code is written.
AI has turned UX from a static map into a living, breathing guide for users. But the fundamental rules of human psychology, such as our 50ms judgments and our need for white space, remain unchanged.
ConclusionIn summary, here is a list of the key truths to remember:
- Fixing issues in the design phase is 100 times cheaper.
- Performance impacts user experience.
- Your site has 50 milliseconds to impress your customers.
- Hick’s Law: The cost of overwhelm.
- White space improves comprehension.
- The power of “fake” progress.
- Make your content readable.
- Your users only read 20% of your content.
- Why user testing with 5 people is the magic number.
- The financial ROI of 9,900%.
As we move deeper into the late 2020s, the line between “design” and “business strategy” has vanished. The data is in, and companies that lead in design outperform their competitors by 1.7x in revenue growth.
UX design is no longer a team you hire to “make things look nice.” It is the research-driven, data-backed discipline that ensures your digital product isn’t just a cost centre, but a revenue-generating machine.
In fact, this has always been the case, but I hope that in presenting these cold, hard truths, it now becomes a reality for your business.
As I have found over the years, implementing factual design improvements does make a difference that intuition alone can’t replicate. We are past the era of subjective opinions. The data is clear, the psychology is proven, and the ROI is undeniable. The only question left is whether you’re ready to let the facts lead your design, or if you’ll let your competitors do it first.
Further Reading On SmashingMag- “The Human Element: Using Research And Psychology To Elevate Data Storytelling”, Victor Yocco & Angelica Lo Duca
- “AI In UX: Achieve More With Less”, Paul Boag
- “Six Key Components of UX Strategy”, Vitaly Friedman
- “When Friction Is A Good Thing: Designing Sustainable E-Commerce Experiences”, Anna Rátkai
Practical Interface Patterns For AI Transparency (Part 2)
In the first part of this series, we talked about the Decision Node Audit. We mapped out the internal workings of our AI system to pinpoint the exact moments it makes decisions based on probabilities. This told us when the system needs to be transparent with the user. Now, the big question is how to share that information.
You’ve got your Transparency Matrix ready. You know which behind-the-scenes API calls need a visible status update. Your engineers are on board with the technical aspects. The next step is designing the visual container for those updates.
We face a legacy problem. For thirty years, interface designers have relied on a single pattern to handle latency: the spinner. The spinning wheel, the throbber, the progress bar. These patterns communicate a specific technical reality. They tell the user that the system is retrieving data. The delay is caused by bandwidth or file size.
AI agents introduce a new kind of wait time. When an agent pauses for twenty seconds, it’s not just downloading something; it’s thinking. It’s figuring out the best steps, weighing options, and creating the content you asked for.
If we use a basic spinning icon for this “thinking time,” users get confused and anxious. They watch a looping animation and can’t tell if the system is stalled or crashed. They don’t know if the agent is handling a very complicated task or if it has simply failed.
To build user trust, we need to turn this waiting time into a moment for reassurance. Instead of a passive “something is happening,” we need to communicate an active, “Here is exactly how I am working to solve your problem.”
Writing Clear Status UpdatesWe often think of transparency as a visual design problem, but it’s really about the words we use. Simple, clear explanations (the microcopy) are what build trust and separate a reliable AI from one that feels broken.
We need to retire generic placeholders like Loading or Working. These words are remnants of the era of static software. Instead, we must construct our status updates using a specific formula that mirrors the agency of the system. Let’s stop using vague words like “Loading” or “Working.” Those terms belong to the past, when software was simple and static. Instead, we should create status updates that clearly tell the user what the system is actually doing and make the system’s actions transparent.
Imagine, for the sake of an example, you are deploying agentic AI that will help team members organize their calendars and plan recurring meetings on their behalf, once prompted.
When an AI displays a message like “Checking availability” for an unknown amount of time, users often feel lost because it doesn’t offer enough information. While they understand the AI is looking at a calendar, they don’t know whose calendar it is, what other steps are involved (before or after), or if the AI even remembered the people and purpose of the scheduling request. Waiting for the final result can be a tense, uneasy experience, like anticipating a gift that you suspect might be a prank.
Perplexity AI provides a strong example of doing status updates right. Figure 1 below shows that when users ask a question, the interface displays exactly what it is doing in real time. You see a list of activities updating as they are accomplished. Users do not need to guess what is happening as the AI works.
The Agentic Update FormulaTo give people useful status updates, we need to connect what the system is doing with why it’s doing it. Keeping with our scheduling agent example, the system should break down that waiting period into at least four clear, separate steps.
- First, the interface displays Checking your calendar to find open times for a recurring Thursday call with [Name(s)].
- Then, it updates to: Cross-checking availability with [Name(s)] calendars.
- Next, it might display: Syncing [Name(s)] schedules to secure your meeting time on [Data and Time].
- Finally, at the conclusion, the agent might state they have successfully completed the task and request the user check their email to confirm the invite that’s been shared with the group having the recurring meeting.
This communication process grounds the technical process in the user’s actual life.
Making an AI’s progress easy to understand boils down to a three-part structure: a strong Action Word, what the AI is working on (the Specific Item), and any Limits or rules it has to follow.
Think about an AI helping you book a trip. A weak, unhelpful update would just be: Searching for flights...
A much better update uses the formula:
- Action Word: Scanning
- Specific Item: the prices on Lufthansa and United
- Limits/Rules: to find anything under $600.
This approach clearly shows the user that the AI understood their request and is working within the set boundaries.
Matching Tone to the Risk MatrixShould an AI sound like a person or act like a robot? The right answer depends on the task’s importance, which we can figure out using the Impact/Risk Matrix from our Decision Node Audit.
For simple, low-risk tasks, a friendly, conversational tone works best. For example, a scheduling assistant can say it’s checking your calendar for the best time. This creates a comfortable, easygoing experience for the user.
However, high-stakes tasks demand clear, mechanical accuracy. If the AI is managing a big financial transfer or a complicated database migration, users don’t want a playful interface; they want precision. A screen that says “I am thinking hard about your money” would possibly cause panic. Instead, the interface should use straightforward language like “Verifying account routing numbers.” By adjusting the AI’s “personality” to match the level of risk, we give users exactly the experience they need in that moment. While the Impact/Risk Matrix provides a necessary starting point, the ultimate determinant of the appropriate AI voice and tone is rigorous user research.
It’s impossible for any set of rules to predict the exact words or tone that will build trust or cause stress for every group of users or in every situation. That’s why hands-on research is essential. You need to:
- Run A/B tests on different ways the AI “talks” to people.
- Conduct usability studies to see how users react emotionally to the system’s messages.
- Perform interviews to truly understand what users expect from an AI in terms of openness.
This kind of research ensures the AI’s “personality” is comfortable and appropriate for the actual people who will be using the system in their specific context.
We’ve now covered the “what” — the critical microcopy, the clear action words, and the necessary limits that make an AI status update honest and informative. But words alone aren’t enough. A perfect sentence hidden in a poor interface is still a failure of transparency.
The next challenge is the “how” — designing the physical delivery system for that message. You can think of the status update formula as the engine, and the interface pattern as the car. A powerful engine needs a reliable, well-designed chassis to carry it down the road.
Interface Patterns: A Library For AgentsOnce we have the right words, we need the right container. The key is matching the message’s weight to the pattern’s visibility. A tiny background task (like an agent gently tidying up your files) doesn’t need a loud, flashing banner. That message is best delivered subtly. A high-stakes, multi-step process (like moving money) potentially demands a more robust container that forces the user to pay attention.
By creating a library of these patterns, we ensure the right level of transparency is delivered at the right moment, turning the anxiety of waiting into a moment of informed confidence. Let’s review a few common, critical patterns.
The Living Breadcrumb: AI Working in the BackgroundFor those low-importance tasks that an AI is handling quietly in the background, we need a way to show users it’s working without constantly distracting them. We can call this the living breadcrumb.
Think of an email app where an AI is drafting a reply for you. You don’t want a disruptive pop-up message. Instead, a small, subtle status indicator pulses within the application’s border or menu area.
The solution needs to go beyond a static icon. The living breadcrumb smoothly transitions between different text updates. It might pulse from Reading email to Drafting reply to Checking tone. It’s there if you want to check on its progress, offering a quiet assurance that the task is underway, but it won’t demand your immediate attention.
Dynamic ChecklistsWhen dealing with critical, high-stakes tasks — like processing a complex financial transaction or migrating a large, intricate dataset — we recommend using a Dynamic Checklist (illustrated in Figure 3).
This pattern serves as a powerful anchor for the user, providing clarity and confidence about the process’s progress. Instead of a simple bar, the Dynamic Checklist lays out every planned step the AI agent will take. It clearly highlights the step that is currently in progress, marks preceding steps as complete, and lists future actions as pending.
For example:
- Step 1: Verify Account Balance [Complete].
- Step 2: Convert Currency [Processing].
- Step 3: Transfer Funds [Pending].
The Dynamic Checklist offers a significant advantage over a traditional progress bar because it expertly manages unpredictable time. If the currency conversion (Step 2) unexpectedly requires an extra ten seconds, the user won’t feel sudden anxiety or panic. They have full visibility into the system’s exact location, understanding that the delay is occurring during the Converting Currency step. Because they recognize this is a potentially complex action, they are naturally more patient and trusting of the system’s ongoing work.
The pattern itself is a compelling UI idea, but designers must remember that its implementation transforms the task into a full-stack design requirement. Unlike a simple loading flag, the dynamic checklist requires a robust front-end state management system to listen for step-completion events, which are typically triggered by a back-end webhook structure. This ensures the interface is always reflecting the agent’s real-time position in the workflow.
The Thinking ToggleSome users with higher information needs or higher needs for transparency may not trust a simple summary; they want to see the system’s raw processing. For this audience, we’ve designed the Thinking Toggle.
This is a simple progressive disclosure UI control, like a chevron or a “View Logs” button, that lets the user expand a friendly status update into a raw terminal view. It displays the sanitized logic logs of the AI agent, such as:
- Querying API endpoint /v2/search;
- Response received: 200 OK;
- Filtering results by relevance score > 0.8.
Many people will never open this view. However, for the user who needs deep transparency, the very presence of this toggle is a signal of trust. It reassures them that the system is not concealing anything.
Keep in mind, with this deep transparency comes a critical technical risk. Even for your most expert audience, you must sanitize and abstract these raw logs before display. This step is non-negotiable to prevent accidentally exposing proprietary business logic, internal data structure names, or security tokens that could be exploited. This process ensures trust is built through honesty, not security vulnerability.
Designing For Partial SuccessIn standard software, things are often black or white. A file either saves or it doesn’t. But with AI agents, things are often grey. An agent might plan most of a trip perfectly, yet struggle to book that one special restaurant.
We need to design for when the AI is mostly successful.
Standard binary (yes or no) error messages are trust-killers because they suggest the AI failed completely. If an agent does 90% of a task and only misses the last 10%, a big red “Request Failed” banner is misleading.
Instead, the interface should clearly show what worked and what didn’t:
- Flight booked: UA 492 [Success].
- Hotel reserved: Marriott Downtown [Success].
- Car rental: Hertz [Failed — No inventory].
This way, you only have to step in and fix the parts that failed, like booking the car yourself, while keeping all the good work the agent already did.
Disentangling The ToolWhen an AI system doesn’t perform as expected, it’s crucial to be absolutely clear about the true reason for the failure. Users often mistakenly blame the AI itself for problems that are actually caused by an external service or tool the AI relies on.
For example, imagine a virtual assistant tries to look at your schedule, but the connection to the Google Calendar API is down. The error message shouldn’t make the assistant look like it failed to do its job.
- Less helpful: “I could not check your calendar.” (This suggests the assistant is incompetent.)
- More helpful and honest: “The Google Calendar connection is not responding. I will automatically try again in 30 seconds.”
The first message is frustrating because it makes the AI look like it failed. The second message, though, is much clearer. It explains that the AI is capable, but a broken tool outside its control is causing the issue. This distinction is really important because it keeps the user from losing faith in the AI, even when things go wrong.
The Audit Trail: Trust After The FactReal-time transparency is fleeting. If a user walks away from their desk while the agent is working, they miss the Dynamic Checklist. They return to a finished screen. If the result looks odd, they have no way to verify the work. This is why every agentic workflow requires a persistent Audit Trail.
We need to design a Show Work interaction. On the final result screen, provide a link or history log that allows the user to replay the decision logic.
- See how this price was calculated;
- View search sources.
This receipt is the ultimate safety net. It allows the user to spot-check the validity of the output. Even if they never click it, the mere presence of the receipt tells the user that the system stands behind its work.
ChatGPT provides an example of how now providing users with an easy way to audit the information AI uses can cause confusion or user frustration. ChatGPT remembers you in the way a file cabinet quietly fills up with notes about everything you’ve ever said, then uses those notes to shape every future conversation without telling you. This is called memory. According to developer Simon Willison, in April 2025, that memory was getting fed into every new conversation automatically.
The problem with ChatGPT’s memory at that time was that you couldn’t see what it remembers, or when it’s using that information, or how it’s influencing what you get back. There’s no log. No timeline. No plain-language list of “here’s what the AI has decided about you.”
The only way to glimpse the dossier was to know a specific prompt trick — essentially asking the model to quote its own hidden instructions back to you. Most users will never discover this. They’ll just notice, as Willison did, that ChatGPT placed a “Half Moon Bay” sign in the background of an image they generated (Figure 8) because it had silently cross-referenced their location from previous conversations. This is the absence of transparency (the ability to audit the memory with ease) disguised as personalization. You need to provide users with both.
The Audit Trail pattern is the ultimate solution to the memory audit problem demonstrated by ChatGPT. It is one of four core design solutions that, together, create a library of options for improving AI transparency.
Here is a quick summary of the key interface patterns discussed in this article, which are designed to transform AI waiting time from a moment of anxiety into an opportunity to build user confidence:
Pattern Best Use Case The User’s Anxiety The Trust Signal The Living Breadcrumb Low-stakes, background tasks (e.g., drafting emails, sorting files). Did the system stall or freeze? I am active, but I won't disturb you. The Dynamic Checklist High-stakes workflows with variable time (e.g., financial transfers, booking travel). Is it stuck? What step is taking so long? I have a plan, and I am currently executing Step 2. The Thinking Toggle Expert tools or complex data analysis (e.g., code generation, market research). Is this hallucinating or using real data? I have nothing to hide; here are my raw logs. The Audit Trail Post-task review for any outcome (e.g., final reports, completed bookings). How do I know this result is accurate? Here is the receipt of my work for you to verify.Table 1: Four design patterns enhancing transparency.
The Reality of Attention: When Users Ignore the InterfaceEven the most perfectly designed checklist or the clearest status message may still go ignored by many users.
When people are working on tons of tasks, especially professionals, they often tune out the interface. Think of an insurance underwriter creating fifty quotes a day — they’re not watching a progress bar. They click “Generate,” switch tabs to answer an email, and only come back when the task is done.
My research with these experts shows they judge the system based entirely on the final result. They have a good idea of what the answer should be. If a salesperson expects a premium between $500 and $600, and the system returns $550, they accept it right away, and trust is established.
These experts tell me that over time, as the AI continues to provide what they perceive as accurate outputs, usage will increase, and they will save time versus manual quoting. Essentially, the system is now viewed as an efficient accelerator of an otherwise monotonous yet mandatory task.
But if the system returns $900, the user stops. The output is not aligned with expectations, and that’s a problem they must solve. At that moment, the user switched tabs; they missed the little explanation about the high-risk surcharge that popped up in real-time. They didn’t see the specific rule that was triggered. If that explanation disappeared with the progress bar, the user has no way to understand the difference between expectation and outcome. They certainly won’t run the query again just to watch the animation play out.
They will run the quote by hand, effectively treating the AI’s output as useless and initiating a complete rework of their effort. This manual recalculation feels like a waste of time, which further erodes their confidence in the tool. Once this happens, the user is not interested in why the system chose $900; they are focused purely on validating or invalidating the system’s accuracy against their own, trusted methods. This lack of transparency, especially in moments of disagreement, is a primary barrier to adoption and consistent use. The audit trail allows us to provide persistent transparency and is the mechanism that prevents the AI from creating more work.
We need to keep this in mind, particularly when delivering AI-powered tools meant for enterprise use. If the tool delivers a result that misaligns with expectations, you rarely get a second chance. If the user must spend ten minutes investigating why the AI provided that number, they will stop using the AI.
Predictability, Reliability, and Understanding Are The ProductWe are not building magic tricks. A magic trick relies on misdirection and hidden mechanics. We are building colleagues.
Think of a good colleague, they keep you in the loop. They let you know what they’re up to, what’s taking their time, and when they hit a snag. That honesty is what helps you trust them.
We can apply this to AI. By using the practical patterns we discussed: giving specific updates, showing a dynamic checklist, acknowledging partial wins, and keeping an audit trail, we stop seeing AI as a mysterious black box that just needs a nice coat of paint. Instead, we start treating it like a team member we can rely on and manage, which builds trust and a clear understanding.
The main reason for using these interface ideas is to achieve real transparency, going beyond explaining the AI’s complicated inner workings. Here, transparency means showing the user the AI’s process and performance right when they need to see it. This involves plainly communicating the AI’s current status, its known limits, and an easy-to-follow history of its decisions. This level of openness changes the interaction from just accepting what the AI does to actively working with it. It lets users understand why they got a certain result and how they can best step in or guide the system for the best possible outcome.
References- “The Essential Guide to A/B Testing”, Ali E. Noghli
- “Usability testing: the complete guide”, Andrew Tipp
- “How to Conduct User Interviews”, IxDF
The Architecture Of Local-First Web Development
Last October, I was sitting in a hotel room in Lisbon, the night before I was supposed to demo a project management tool my team had spent four months building. The hotel Wi-Fi was doing that thing where it connects but nothing actually loads. And I watched our app, this thing I was genuinely proud of, render a blank screen with a spinner. Then a timeout error. Then nothing.
I pulled out my phone, tethered to cellular, and got a shaky connection. The app loaded, but every click was a two-second wait. Create a task? Spinner. Move a task between columns? Spinner. I sat there thinking: we built a front end in React, a back end in Node, a Postgres database, a Redis cache, a GraphQL API with six resolvers just for the task board. All that infrastructure, and the damn thing can’t show me my own data without a round-trip to a server 3,000 miles away.
That was the night I started seriously looking at local-first architecture. Not because I read a blog post or saw a tweet. Because I was embarrassed.
I want to be upfront about something: I spent the first year or so dismissing local-first as academic. I read the Ink & Switch “Local-First Software” paper when it came out in 2019 and thought, “Cool research, not practical for real apps.” I was wrong. The tooling in 2019 genuinely wasn’t ready. But I was also being lazy, defaulting to the architecture I already knew. The paper laid out seven ideals for software: fast, multi-device, offline, collaboration, longevity, privacy, user ownership. And I remember thinking those sounded like a wish list, not engineering requirements.
Seven years later, I’ve shipped three production apps using local-first patterns. I’ve also ripped local-first out of two projects where it was the wrong call. I have opinions. Some of them are probably wrong. But they’re earned.
So here’s what I actually think about building local-first web apps in 2026, written for developers who’ve been doing this long enough to be skeptical of silver bullets.
What “Local-First” Actually Means (And The Confusion That Won’t Die)I need to clear something up because I keep having this conversation at meetups. Local-first is not offline-first. It’s not “add a service worker and call it a day.” It’s not a synonym for PWA. I’ve seen all of these conflated in conference talks, and it drives me a little crazy.
Offline-first means your app handles network loss gracefully, but the server is still the source of truth. When the network comes back, the server wins. Cache-first (service workers caching responses) is a performance optimization. You’re serving stale data faster, which is great, but you haven’t changed who owns the data. PWAs are a delivery mechanism: installable, cached, push notifications. None of these is a data architecture.
Local-first is a data architecture. Your user’s device holds the primary copy of their data. The app reads and writes to a local database. Renders instantly. Syncs with servers or other devices in the background. The server, when it exists, is a sync peer with some special authority (authentication, backup, access control). But it’s not the gatekeeper.
The Ink & Switch paper defined seven ideals, and I think they still hold up. But the one that matters most in practice, the one that changes how you build everything, is this:
The client is not a thin view requesting permission to show data. The client is a node in a distributed system with its own database.That distinction sounds subtle. It isn’t. It changes your entire stack.
Be Honest Early: When You Should Not Do ThisI’m putting this near the top because I’ve watched too many developers (including myself, once) get excited about a new architecture and shoehorn it into projects where it doesn’t belong. I wasted about six weeks trying to make a local-first approach work for an internal analytics dashboard at a previous job. My colleague Sarah finally pulled me aside and said, “The data is generated on the server. There’s nothing to replicate to the client. What are you doing?” She was right.
Local-first is a bad fit when your data is primarily server-generated. Analytics dashboards, social media feeds, search results: the server produces this data, so the client consuming it via API requests is completely fine.
It’s wrong for systems that need strong transactional consistency. Banking, payment processing, and inventory management. If two people try to buy the last item in stock, you need a single authoritative database making that decision with ACID guarantees. Eventual consistency will lose you money, or worse.
It’s overkill for simple CRUD apps with no offline or collaboration needs. If you’re building an internal admin panel used by five people in an office with good internet, adding a sync engine is over-engineering. And it’s physically impractical for massive datasets that won’t fit on client devices.
But here’s where it shines: note-taking, document editing, collaborative design tools, project management, field apps with unreliable connectivity, basically anything where data privacy is a selling point, as well as anything with real-time collaboration. In other words, it’s great for user-generated data that benefits from instant interaction and should survive the server going down.
One more thing I wish someone had told me earlier: you don’t have to go all-in. I’ve had the best results using local-first for specific features within otherwise traditional apps. Offline drafts in a blog editor. Real-time collaborative notes inside a project management tool that’s otherwise standard REST.
The “spectrum of local-first” is a real thing, and starting with one feature is how I’d recommend anyone begin.
Replicas, Not RequestsIf you’ve used Git, you already understand the mental model.
SVN (remember SVN?) was centralized. One server. You check out files, make changes, and commit to the server. Server down? Can’t commit. Can’t even see history.
Git gave every developer a full clone. You commit locally, branch locally, and merge locally. Push and pull when you’re ready. The remote repository is important, but it’s not the only copy of the truth.
Local-first web development is Git for application data. Every client device holds a replica (full or partial) of the relevant data. Writes happen locally. Sync is push/pull in the background. Conflicts get resolved through defined merge strategies.
I remember the first time this clicked for me in practice. I was prototyping a task board, and I wrote a function to add a task. In our old architecture, it would be:
- POST to API.
- Wait for the response.
- If success, update the local state.
- If failure, show error toast and maybe roll back optimistic update.
In the local-first version, it was: write to local SQLite, done. The UI updated instantly because it was reading from the same local database. Sync happened whenever. No loading state, no error handling for the write itself, no optimistic update logic (because there’s nothing to be “optimistic” about; the local write is the state).
The implications ripple through everything. You don’t need React Query or SWR for data fetching, because you’re not fetching. You don’t need Redux or Zustand for server-derived state, because the local database is your state. Your routing doesn’t trigger API calls. Authentication works differently because the server isn’t checking permissions on every read.
Here’s a visual comparison that might help if you’re the kind of person (like me) who thinks spatially:
On the left, every user interaction is a round-trip. Click, wait, render. On the right, reads and writes hit the local database directly. The sync server is still there, but it’s doing its work in the background. The user never waits for it. That’s the fundamental shift.
But I’m getting ahead of myself. Before we can talk about sync and conflicts, we need to talk about where the data actually lives on the client.
Where Data Lives on the ClientForget localStorage. It’s synchronous (blocks the main thread), caps at 5-10 MB, and only stores strings. It’s fine for a theme preference. It’s not a database.
IndexedDB is the workhorse that nobody loves. It’s in every browser, it’s asynchronous, it can handle hundreds of megabytes, and its API is absolutely miserable to work with. I’ve used it directly a grand total of once. Now I use it through abstractions or, more often, I don’t use it at all.
Because the real story in 2026 is SQLite running in the browser via WebAssembly.
I know that sounds like a party trick, but it’s not. SQLite compiled to WASM, persisted to the Origin Private File System (OPFS), gives you a real relational database in the browser. Full SQL queries. Transactions. Indexes. The works.
OPFS is the newer API that makes this practical. It gives web apps a sandboxed file system with high-performance synchronous access (in Web Workers), which is exactly what SQLite needs. Before OPFS, you could run SQLite in memory and manually persist to IndexedDB, which worked but was slow and fragile.
Here’s roughly what initialization looks like in a real project (I’m using wa-sqlite here, which is the library I’ve had the best luck with):
import { SQLiteAPI } from 'wa-sqlite'; import { OPFSCoopSyncVFS } from 'wa-sqlite/src/examples/OPFSCoopSyncVFS.js'; async function initDatabase() { const module = await SQLiteAPI.initialize(); const vfs = new OPFSCoopSyncVFS('pm-tool-db'); await vfs.initialize(module); const db = await module.open_v2('workspace.db'); // HACK: wa-sqlite doesn't handle concurrent writes well on Safari, // so we serialize through a queue. See vlcn-io/wa-sqlite#247 await module.exec(db, PRAGMA journal_mode=WAL); await module.exec(db, CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, status TEXT DEFAULT 'backlog', assignee_id TEXT, project_id TEXT NOT NULL, position REAL DEFAULT 0, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) )); return db; }In production, I wrap all database access in a write queue that serializes mutations. I also log every failed write to Sentry with the full SQL statement (scrubbed of PII, obviously) because debugging database issues in a user’s browser is hell without that telemetry.
A gotcha I wasted almost two days on: Safari’s OPFS implementation behaves differently from Chrome’s in subtle ways. Specifically, I hit a bug where createSyncAccessHandle() would silently fail in certain iframe contexts on Safari 18. There’s no error, no exception. It just doesn’t work. I ended up falling back to IndexedDB-backed persistence on Safari, which was slower but at least functioned. (I’m told Safari 19/26 fixes this, but I haven’t verified it yet.)
Quick comparison of the options I’ve actually used:
Storage Good For Watch Out For IndexedDB Broad compatibility, moderate data Terrible DX, no SQL, verbose OPFS + SQLite WASM Relational data, complex queries, serious apps Safari quirks, ~400KB bundle addition PGlite (Postgres in WASM) Full Postgres compatibility on client Newer, larger bundle, still maturingI’ve also tried cr-sqlite, which adds CRDT column support directly to SQLite tables. Clever idea, but I found it too early-stage for production use when I evaluated it in late 2025. The merge semantics were sometimes surprising, and debugging CRDT state inside SQLite was painful. I’d revisit it later this year.
The Part That’s Actually HardStoring data locally is a solved problem. Syncing it reliably across devices and users is where you earn your gray hairs.
When multiple replicas can independently read and write, you need a mechanism to reconcile changes. There are basically four approaches, and I’ve used three of them.
CRDTs (Conflict-Free Replicated Data Types) are data structures designed so that concurrent edits can always be merged without conflicts, mathematically guaranteed. Yjs is the most popular implementation in JavaScript, and it’s genuinely excellent for real-time collaborative text editing. I used it to build a collaborative document editor at my last company, and the experience was mostly good, though I’ll get into the pain points in the conflict resolution section.
Here’s what setting up a shared Yjs document looks like in practice:
import * as Y from 'yjs'; import { WebsocketProvider } from 'y-websocket'; const ydoc = new Y.Doc(); const provider = new WebsocketProvider( 'wss://sync.our-app.dev', 'workspace-a1b2c3d4', ydoc ); const tasks = ydoc.getMap('tasks'); // Add a task const task = new Y.Map(); task.set('title', 'Review Q3 roadmap draft'); task.set('completed', false); task.set('assignee', 'maria'); // TODO: type this properly once; yjs exports better TS types // for nested maps. For now, this works fine. tasks.set('f47ac10b-58cc-4372-a567-0e02b2c3d479', task as any); tasks.observeDeep(() => { // Re-render UI. In practice, I debounce this to ~16ms // because observeDeep fires a LOT during active collaboration renderTaskList(tasks.toJSON()); });Automerge is the other major CRDT library, backed by Rust and with a document-oriented model. I’ve used it less, but I know teams who swear by it. Loro is newer, Rust-based, and claims better performance. I haven’t shipped anything with Loro yet.
Database replication is the other big approach, and honestly, for most apps that don’t need Google Docs-style real-time text editing, I think it’s the better choice. The idea is straightforward: replicate rows between a server database (Postgres) and a client database (SQLite) with a sync engine managing the plumbing.
PowerSync does this well. It gives you one-way replication from Postgres to client SQLite with a write-back path for mutations. ElectricSQL is more ambitious, going for full active-active sync between Postgres and SQLite. I’ve used PowerSync in production and ElectricSQL in prototypes. PowerSync felt more stable when I evaluated them both in early 2026, but ElectricSQL’s approach is more powerful if they nail the execution.
Triplit takes a different angle entirely: it’s a full-stack database with sync built in, so you don’t think about “client DB” and “server DB” separately. I haven’t tried it beyond a weekend prototype, but the developer experience was surprisingly nice.
Event sourcing (syncing a log of mutations rather than the current state) is the approach LiveStore takes. I find it intellectually appealing and occasionally useful, but in practice, I’ve found that reconstructing state from an event log adds complexity that most apps don’t need. My controversial opinion: Event sourcing is over-recommended for application development. It’s great for audit logs and certain domains, but for a task board? Just sync the rows.
Not everyone will agree with that. I know event sourcing has passionate advocates, and I’ve been told I’m wrong about this at least twice at conferences. Maybe I just haven’t built the right app for it yet.
Conflicts: The Thing Everyone’s Afraid OfI used to think conflict resolution was a terrifying, unsolvable problem. After building three apps that handle it, I’d revise that to: it’s a manageable problem that requires you to think carefully about your specific data model, and most developers overthink it.
Conflicts happen when two replicas modify the same data without seeing each other’s changes. User A edits a task title on their phone while offline. User B edits the same title on their laptop. Both come back online. Now what?
My first attempt at handling this was embarrassingly naive:
// My first try. Don't do this. function resolveConflict(local: any, remote: any) { // just... take the remote one? sure? return remote; }The problem is obvious: local changes get silently dropped. User A edits a title, syncs, and their edit vanishes. They don’t even know it happened.
What actually works for most cases is last-write-wins (LWW) at the field level, not the record level. If User A changes the title and User B changes the due date, you keep both changes because they touched different fields. You only have a real conflict when both modified the same field, and then you pick the later timestamp.
interface FieldValue { value: string | number | boolean; // ISO timestamp with enough precision to break most ties updatedAt: string; // Client ID as tiebreaker when timestamps match. // This happens more often than you'd think. clientId: string; } function pickWinner(a: FieldValue, b: FieldValue): FieldValue { const timeA = new Date(a.updatedAt).getTime(); const timeB = new Date(b.updatedAt).getTime(); if (timeA !== timeB) return timeA > timeB ? a : b; // Deterministic tiebreaker when timestamps match return a.clientId > b.clientId ? a : b; } // In practice, I apply this per-field across the whole record. function mergeTask(local: Record<string, FieldValue>, remote: Record<string, FieldValue>) { const merged: Record<string, FieldValue> = {}; const allKeys = new Set([...Object.keys(local), ...Object.keys(remote)]); for (const key of allKeys) { if (!local[key]) { merged[key] = remote[key]; continue; } if (!remote[key]) { merged[key] = local[key]; continue; } merged[key] = pickWinner(local[key], remote[key]); } return merged; }In our production app, this handles about 95% of conflicts without any user-visible issues. For the remaining cases (two people editing the same text field), LWW means one person’s edit silently wins. For a task title? Honestly, that’s usually fine. For a document body? No. That’s where CRDTs earn their keep.
But there’s a subtler problem I didn’t appreciate until I hit it: semantic conflicts. Data merges cleanly at the structural level, but the result is nonsensical. Two users, both offline, book the same 2 PM meeting slot with different meetings. Field-level merge accepts both writes because they’re writing to different records. No structural conflict. But you’ve got a double-booking, and your merge function has no idea that’s a problem.
Semantic conflicts require application-level validation, and that has to happen on the server during sync. Your sync engine merges the data structurally, but your server needs to check domain invariants before accepting the result. The approach I’ve landed on (after getting it wrong twice) is: validate on the server during the write-back phase, but flag violations rather than silently rejecting them.
Here’s what I mean. When the client pushes mutations to the server during sync, the server runs them through a constraint validation layer before applying them to Postgres:
interface SyncViolation { type: 'scheduling_conflict' | 'capacity_exceeded' | 'stale_assignment'; recordId: string; description: string; // The conflicting records so the client can show context conflictingRecords: string[]; // When was this violation detected detectedAt: string; } async function validateSyncBatch( mutations: SyncMutation[], serverDb: Database ): Promise<{ accepted: SyncMutation[]; violations: SyncViolation[] }> { const accepted: SyncMutation[] = []; const violations: SyncViolation[] = []; for (const mutation of mutations) { if (mutation.table === 'calendar_events') { // Check for double-booking const overlapping = await serverDb.query( SELECT id, title FROM calendar_events WHERE room_id = ? AND id != ? AND start_time < ? AND end_time > ?, [mutation.data.room_id, mutation.data.id, mutation.data.end_time, mutation.data.start_time] ); if (overlapping.length > 0) { violations.push({ type: 'scheduling_conflict', recordId: mutation.data.id, description: Conflicts with "${overlapping[0].title}", conflictingRecords: overlapping.map(r => r.id), detectedAt: new Date().toISOString() }); // Still accept the write, but flag it // The alternative is rejecting it, but then the user's // local state and server state diverge, and that's worse accepted.push(mutation); continue; } } accepted.push(mutation); } return { accepted, violations }; }The key decision here — and I went back and forth on this — is that we accept the conflicting write and flag it, rather than rejecting it outright. If you reject it, the user’s local database has a record that the server refuses to acknowledge, and now you’re in a state divergence situation that’s genuinely hard to recover from. I tried the rejection approach first, and it led to ghost records on the client that users couldn’t delete because they didn’t exist on the server. Nightmare.
So instead, the server accepts the write, stores the violation, and syncs the violation back to the client. The client shows a non-blocking notification: “Your meeting ‘Q3 Planning’ conflicts with ‘Design Review’ in Room B at 2 PM. Tap to resolve.” The user taps, sees both meetings, and picks one to reschedule or cancel. The resolution is a normal write that syncs back.
Is this perfect? No. There’s a window between when the violation is created and when the user resolves it, where both conflicting records exist. For meeting rooms, that’s tolerable. For something like inventory management where two people “buy” the last item, that window is unacceptable, and that’s exactly why I said earlier that local-first is wrong for systems requiring strong transactional consistency.
I’m still iterating on this pattern. The violation table grows if users ignore notifications (we expire them after 72 hours, which feels arbitrary). And deciding which invariants to validate on the server requires you to essentially maintain a parallel set of business rules outside your client-side application logic. It’s not elegant. But it works, and it’s the best approach I’ve found for the class of apps I’m building. If you’ve built something cleaner, I genuinely want to hear about it.
For CRDTs like Yjs, conflict resolution at the character level (for text) works remarkably well. Two people typing in the same paragraph will see both sets of characters appear in a sensible order. But CRDT merging of structured data (maps, arrays, nested objects) can produce results that surprise you. I once watched a Yjs-backed task list duplicate items after a merge because two users had reordered the same list offline, and the CRDT’s list merge semantics interleaved their orderings. Technically correct. Practically confusing. We ended up adding a post-merge de-duplication step, which felt like a hack but solved the problem.
When should you surface conflicts to the user, Git-style? In my experience, almost never for typical app data. Users don’t want to resolve merge conflicts. They want the app to figure it out. The exception is high-stakes content: legal documents, medical records, anything where silently dropping an edit could cause real harm.
The Tools Right NowI’m going to give you my honest read on the tools available as of mid-2026, with the caveat that this space is moving fast enough that some of this might be outdated by the time you read it.
Yjs is the most mature CRDT library. Production-ready, huge community, integrates with most collaborative editors (TipTap, BlockNote, Lexical). If you need real-time collaborative editing, start here.
Automerge is solid, Rust-backed, and takes a more document-oriented approach than Yjs. I’ve seen it used well in apps where the data model fits a document metaphor. Fewer integrations than Yjs, but the core is well-engineered.
PowerSync is what I’d recommend for teams that have an existing Postgres back-end and want to add offline support. It’s production-ready, the docs are good, and the mental model (Postgres syncs to client SQLite, client writes go through a defined upload path) is easy to reason about. In our app, initial sync for a workspace with around 5,000 tasks takes about 1.2 seconds on a decent connection and about 3.5 seconds on a throttled 3G simulation. That was acceptable for us.
ElectricSQL is going for something more ambitious: true active-active replication between Postgres and SQLite, with “shapes” defining what data syncs to which client. I want this to succeed because the developer experience in prototypes was excellent. But when I evaluated it for production in February 2026, I hit enough rough edges (particularly around shape management and reconnection behavior) that I went with PowerSync instead. I plan to revisit it.
Triplit impressed me in a weekend prototype. Full-stack database with sync built in, nice TypeScript API. I haven’t stress-tested it with real production load, and I’d want to before committing.
Zero (from Rocicorp, the Replicache people) is interesting because it takes a query-based approach to sync, which is different from the row-replication model. Replicache was sunset in favor of Zero, which tells you something about how fast approaches are evolving in this space. Worth watching, but I wouldn’t build on it yet for a production app.
TinyBase is a lightweight reactive store that’s great for smaller apps or prototyping. I used it for a personal side project (a reading tracker) and liked it a lot. Not sure I’d use it for a team-scale product.
PGlite (Postgres compiled to WASM) is wild. Same SQL dialect on client and server. Combined with ElectricSQL, you could theoretically run identical queries everywhere. I think this is where things are heading long-term, but PGlite’s bundle size and memory footprint are still concerns for mobile browsers.
One thing the Replicache sunset taught me: don’t bet your architecture on a single tool from a small company without a fallback plan. I keep my sync layer abstracted enough that I could swap engines in a few weeks, not months. I know that sounds like premature abstraction, but in a space this young, I think it’s just prudence.
Building A Real App: Architecture, Auth, And MigrationsI want to walk through how I actually structure a local-first app in practice, because the layer diagrams you see in blog posts rarely match what the code looks like.
My current stack for a collaborative project management tool looks like this:
- UI: React components that never call fetch() for data reads.
- Query layer: useLiveQuery hooks that subscribe to the local SQLite database and re-render automatically when data changes.
- Local database: SQLite via wa-sqlite, persisted to OPFS.
- Mutation layer: Plain INSERT/UPDATE/DELETE statements against local SQLite.
- Sync: PowerSync managing replication between local SQLite and our Postgres back-end.
- Server: Postgres, a Node.js auth service, and a small sync validation layer.
The component code ends up looking almost absurdly simple compared to what I used to write:
import { useLiveQuery } from '@powersync/react'; import { db } from '../lib/database'; function TaskBoard({ projectId }: { projectId: string }) { const tasks = useLiveQuery( SELECT * FROM tasks WHERE project_id = ? AND archived = 0 ORDER BY position, [projectId] ); async function addTask(title: string) { await db.execute( INSERT INTO tasks (id, title, project_id, position, created_at) VALUES (?, ?, ?, ?, datetime('now')), [crypto.randomUUID(), title, projectId, tasks.length] ); // That's it. useLiveQuery picks up the change automatically. // No invalidation, no refetch, no loading state. } // No isLoading check. Data is local. It's always there after the first sync. return ( <div> {tasks.map(task => <TaskCard key={task.id} task={task} />)} <NewTaskInput onSubmit={addTask} /> </div> ); }Compare that to the React Query + REST equivalent, which would be at least twice the code and include loading states, error states, optimistic update logic with rollback, and cache invalidation. I don’t miss it.
Auth In A Local-First WorldAuthentication works roughly the same as traditional apps: JWT tokens, OAuth flows, and session management. The token authenticates the sync connection rather than every individual request. Offline access works because the data is already local. The user was authenticated when the data was originally synced.
Authorization is trickier, and I think most local-first articles under-explain this. You cannot sync your entire database to every client and rely on client-side code to hide unauthorized data. Someone will open DevTools, find the local SQLite file, and see everything. The client is not a trust boundary.
You enforce authorization at the sync layer. PowerSync has “sync rules” that define which rows go to which clients. ElectricSQL has “shapes.” Either way, the server only sends data that the user is authorized to see. When the client sends writes back, the server validates them against authorization rules before applying them to Postgres. If a user tries to modify something they shouldn’t, the server rejects it during sync.
I also want to mention end-to-end encryption (E2EE), because it pairs naturally with local-first. Since data lives on the client, you can encrypt it before sync. The server stores and relays encrypted blobs it can’t read. Apps like Anytype do this. We haven’t implemented E2EE in our current app, but it’s on the roadmap for when we handle more sensitive data.
Schema Migrations On A Thousand DevicesThis one caught me off guard the first time. On the server, you run a migration against one database you control. On the client, every user has their own database that might be running any version of your schema, depending on when they last opened the app.
I use a simple migration runner that checks a version number at app startup:
const MIGRATIONS = [ { version: 1, sql: CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, status TEXT DEFAULT 'backlog', project_id TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); }, { version: 2, // Added priority and due_date in sprint 4 sql: ALTER TABLE tasks ADD COLUMN priority INTEGER DEFAULT 0; ALTER TABLE tasks ADD COLUMN due_date TEXT; }, { version: 3, // Denormalized assignee name for offline display. // Yes, I know this is a trade-off. The JOIN was killing // performance on low-end Android devices. sql: ALTER TABLE tasks ADD COLUMN assignee_name TEXT DEFAULT ''; } ]; async function runMigrations(db: Database) { await db.execute(CREATE TABLE IF NOT EXISTS _schema_version (version INTEGER)); const rows = await db.execute('SELECT version FROM _schema_version'); const currentVersion = rows.length > 0 ? rows[0].version : 0; for (const migration of MIGRATIONS) { if (migration.version > currentVersion) { console.log(Migrating local DB to v${migration.version}); await db.execute('BEGIN'); try { await db.execute(migration.sql); await db.execute( 'INSERT OR REPLACE INTO _schema_version (rowid, version) VALUES (1, ?)', [migration.version] ); await db.execute('COMMIT'); } catch (err) { await db.execute('ROLLBACK'); // In production, this fires a Sentry alert with the // migration version and error details throw err; } } } }Design your migrations to be additive. New columns with defaults. New tables. Don’t rename or drop columns unless you absolutely must, because users running old app versions will still be syncing data, and your server needs to handle the mismatch. I learned this the hard way when I dropped a column that an older client was still writing to, which caused silent sync failures for about 200 users over a weekend. Not fun.
If I Were Starting A New Project TodayI get asked this a lot, so here’s my current answer. It changes every six months or so.
For a collaborative app with real-time features and offline support, I’d start with: React on the front end, PowerSync for sync, SQLite via wa-sqlite on the client (persisted to OPFS with IndexedDB fallback for Safari), and Supabase (which gives me Postgres, auth, and row-level security out of the box). I’d use Yjs only if I needed rich text collaboration, and I’d avoid it if I didn’t, because CRDTs add meaningful complexity to your data model.
For a simpler app where I mostly need offline support and instant reads but collaboration is secondary, I might skip the sync engine entirely and just use a local SQLite database with a custom sync layer that pushes/pulls from a REST API. I know that sounds like reinventing the wheel, but for simple cases, a custom sync that you fully understand is better than a general-purpose sync engine that adds concepts you don’t need.
I would not currently use ElectricSQL or Zero for production, not because they’re bad, but because I want another 6-12 months of maturity before I’d trust them for something I’m on-call for. I’ve been burned before by building on early-stage infrastructure (I was an early Meteor adopter, if that tells you anything) and I’m more cautious now about where I accept novelty risk.
Performance: What’s Actually Fast And What HurtsReads are instant. That’s not marketing. Querying a local SQLite database for a list of 500 tasks takes under two milliseconds on my M2 MacBook and about eight milliseconds on a mid-range Android phone. No network. No spinner. No loading state.
Writes are instant, too. INSERT INTO tasks runs locally, the UI updates reactively, and sync happens whenever. Users perceive writes as instantaneous because they are.
Initial sync is where you pay the cost. Bootstrapping the local replica on first load (or on a new device) means downloading potentially megabytes of data. In our app, a workspace with 5,000 tasks, 200 projects, and 50 users takes about 1.2 seconds on broadband and four to five seconds on a slow mobile connection. We mitigate this with partial sync (only sync the user’s active projects) and by showing a one-time “Setting up your workspace” screen during the first sync. After that initial sync, incremental updates are tiny.
Bundle size is a real concern. SQLite compiled to WASM adds roughly 400KB gzipped to your JavaScript bundle. That’s not trivial, especially if you care about Time to Interactive on mobile. I lazy-load the database module with dynamic import() so it doesn’t block the initial render.
Memory is the other gotcha. SQLite WASM runs in memory, and on mobile browsers with aggressive memory limits, a large database can cause tab crashes. I haven’t found a great solution for this beyond keeping the synced dataset small through partial sync and being aggressive about pruning old data.
Note: Speaking of memory issues, I’ve been reading Designing Data-Intensive Applications by Martin Kleppmann for the third time. Every re-read, I catch something new. If you haven’t read it and you’re thinking about distributed data, just stop and read it first.
Testing This StuffI’ll keep this brief because the honest answer is that testing local-first apps is harder than testing traditional apps, and the tooling isn’t great yet.
What works for me: unit tests for merge logic (these are pure functions, easy to test), integration tests that spin up two client instances in memory and verify they converge after concurrent edits, and Playwright E2E tests that use context.setOffline(true) to simulate offline/online transitions.
What I haven’t figured out well: reproducing bugs that only happen during conflict resolution with specific timing. When a user reports that a task “lost its description,” I often can’t reproduce it because I don’t know exactly what sequence of offline edits and sync events led to the conflict. I’ve started logging sync events in more detail (what was sent, what was received, what conflicts were detected, how they were resolved) and shipping those logs to our observability stack. It helps, but it’s not as clean as I’d like.
Property-based testing with something like fast-check is genuinely useful for CRDT logic. Generate random operation sequences, apply them in random orders, and assert convergence. I wish I’d started doing this earlier.
What I’m Watching, What Worries MeI’m excited about where this is going. PGlite (full Postgres in the browser) feels like a glimpse of a future where the client/server data layer distinction just dissolves. You write SQL, it runs everywhere, sync is a runtime concern rather than an architectural decision. We’re not there yet, but you can see it from here.
I’m also watching the convergence of local-first and AI. Running models locally, keeping data on-device, using cloud AI only with explicit consent, and encrypted data. The privacy implications are compelling, and I think “your data never leaves your device” will become a real product differentiator as AI eats more of the software experience.
What worries me is fragmentation. Every sync engine uses its own protocol. There’s no standard. If ElectricSQL shuts down (it won’t, probably, but if), migrating to PowerSync isn’t trivial. I abstract my sync layer partly for this reason, but it still makes me nervous.
The web has standards for nearly everything. We don’t have one for sync, and I don’t see one emerging soon.
I’m also worried about the complexity budget. Local-first adds real architectural complexity: sync engines, conflict resolution, client-side migrations, partial replication, and auth at the sync boundary. For a team of experienced developers building the right kind of app, that complexity pays for itself many times over. For a team that just needs a CRUD app, it’s a trap.
I keep coming back to something a developer named Kevin said to me at a local-first meetup in Berlin last year:
“The best architecture is the one your team can debug at 2 AM.”He’s right. If local-first makes your app faster, more reliable, and better for users, and your team understands how the sync works, go for it. If you’re adding it because it sounds cool and you don’t fully understand the failure modes yet, build a prototype first. Learn where it breaks. Then decide.
I’m building my fourth local-first app right now: a collaborative planning tool for small teams, with offline support and optional E2E encryption. It’s the most ambitious thing I’ve attempted with this architecture. I’ll write about how it goes.
If you’re starting out, pick one feature in your current app that would benefit from instant local reads and offline writes. Add a local SQLite database. Wire up reactive queries. See how it feels. I think you’ll have the same reaction I did: oh, this is how it should have always worked.
Further Reading- “Local-First Software” (Ink & Switch): This is still the best starting point.
- “CRDTs: The hard parts”” (Martin Kleppmann, video): Martin’s talks on CRDTs are excellent.
- The localfirstweb.dev community site: A good directory of tools.
- PowerSync Documentation
- ElectricSQL Documentation
- Yjs Documentation
- Automerge Documentation
Rethinking The Experience Of System Tools
This article is a sponsored by MacPaw
Your grandmother’s vacuum was a trusty but ugly workhorse hidden in a dark closet. Dyson turned that practical tool into an aspirational product, one you love leaving out even when guests come over. Dish soap was just dish soap until Method put it in a glass container, and it became an addition to, not a distraction from, the aesthetics of your kitchen. Physical product brands spent the last two decades transforming mundane, practical items like soap and vacuums into must-have experiences.
But utility software — especially maintenance tools, a type of system software designed to analyze, configure, optimize, and maintain a computer — hasn’t made that leap from something you open as a chore to an experience you choose with excitement. And that means those brands are missing an interesting design opportunity: these tools are well overdue for a more intelligent, more human, and less emotionally flat approach.
“The Most Underexplored Frontier In UX Is The Maintenance Layer.”Utility software still feels like a chore. Using it has all the excitement of pulling out that dusty old vacuum from the back of the closet. These four common software design assumptions illustrate why the category hasn’t yet transcended its chore status.
- Assuming the user already resents the task: they’re here because something is wrong, not because they chose to open this tool. Designing accordingly means assuming they want the software to be fast, clinical, invisible, and something to get out of the way, not get into. But a design built for resentment produces tools that deserve it. If you expect your users to want to get out of the product as fast as possible, they’ll feel it in the design.
- Assuming function is enough and feelings are for consumer apps: emotion in interface design is decoration. The maintenance layer is infrastructure, and nobody decorates infrastructure. But nobody decorated dish soap either, until Method. They didn’t change the product, just the user’s relationship to the tool they use to accomplish a task.
- Assuming your users are not your fans because nobody cares about maintenance tools: utility tools don’t build communities, and nobody posts about running a disk cleanup. But people care deeply about tools that respect their time and make complex things simple for them to use. The MacPaw team listens to our community and implements many of the features they ask for, because we know users can be fans too, and they should shape how our products work.
- Assuming that designers shouldn’t waste pixels on personality: you need to hide complexity and show minimal UI. Utility software should look neutral, technical, and forgettable.
But when software hides the system, people lose trust in it.
Design always starts with function — function shapes form. But if that function can’t be made completely invisible and people still have to interact with it, it inevitably becomes part of their experience. In that case, people expect it not just to work, but to match their environment, influence their mood, and contribute to their overall experience.
A good example is a watch. Its core function is simple: show the time. But because a watch occupies physical space in a person’s world, you want more from it than just functionality. It needs to play an aesthetic role and complement the environment.
“The Maintenance Layer Is A Behavioral Problem, Not Just A UX One.”The user experience in utility software matters more than the industry tends to admit. In utility software, experience is not something added on top of function. It emerges from how the function is structured, explained, and interacted with. If you think you can design the most functional app on the market without considering how users understand and experience the process, you’re missing an opportunity to build a relationship with that user.
Part of that ignored UX element is a behavioral problem: users don’t avoid utility software because using it is hard, but instead because it produces no positive emotional signal at any point. The problem is rarely complex. It’s the absence of meaningful interaction during the process of using the app.
Another issue is focusing solely on function. The aesthetic-usability effect shows us clearly that if something looks better, it feels better — ATM screens in a 1995 study were judged easier to use if the screen layout was more attractive. Even something as purely functional as an ATM screen display needs attention to how the function is structured, presented, and perceived.
And then there’s the memory problem. People remember the emotional peak and the ending of an experience, not the average. A completed process that ends with a clear “done” is remembered more positively than one that just fades out, even if the end task is completed successfully in both cases. System tools rarely intentionally design the ending of an interaction — they just stop running.
“Thoughtful System Design Can Transform Maintenance From A Technical Chore Into A Seamless User Experience.”What does emotional design actually mean, then, in utility UX? Here are three principles the MacPaw team follows to design its products against the category norm.
Translating system complexity into human languageMaintenance tools deal with storage, task management, and background processes. Good design explains what’s happening, avoids system jargon, and communicates outcomes clearly.
Linear’s game-changing move that illustrates this principle was agreeing on straightforward units of work, like projects and teams, that any new user can immediately understand. That helps them spend less time ramping up and more time building.
Make the process clear and show progressSystem tools run complex processes. Design should show progress, impact, and system change to create trust and control.
Vercel’s deployment infrastructure is an excellent example here. When you trigger a build, the browser tab favicon changes — a spinner while building, a green checkmark when done, a red X if it fails. It’s ruthlessly functional, not visual or warm, but it’s emotionally intelligent: it exists purely to reduce the low-level anxiety of waiting for a build to finish.
Design the moment of completionMaintenance tasks often end quietly. But completion is the emotional payoff. Design should emphasize clarity of results, a sense of resolution, and visible improvement so users remember a positive and distinct ending.
Take the new CleanMyMac by MacPaw after its 2024 major update. Unlike the maintenance utility category norm, CleanMyMac uses visual language, including color, depth, motion, icons, and 3D illustrations, to shift the focus from diagnosing problems to showing progress: space cleared, threats removed, time saved. Instead of confronting the user with what's wrong, the interface closes with a picture of a machine that's already working better.
The task is the same, but the ending tells a different story, giving the user a picture of a machine that's already working better.
“Even if you don’t care about emotional design as a principle, the change is coming anyway.”The market is forcing this issue even for those who don’t find the argument I’ve made here compelling.
That’s partly generational — designers and users who grew up with Linear, Figma, and Notion have a completely different baseline for the tools they use. Good software is not a happy accident for them, but a given. That generation is now the primary audience for maintenance software, and so the old “it’s fine, it’s just a utility” excuse doesn’t work philosophically or commercially. Just like Dyson and Method changed how entire product categories approached design, the current state of utility software is shifting for good.
And digital fatigue is the current cultural state. The resurgence of vinyl records, film cameras, and dumbphones is not merely nostalgia, but a signal that the emotional relationship between people and their tools is changing.
The question has shifted from whether your utility software should feel better to use to whether it can afford not to.
Designing Stable Interfaces For Streaming Content
More interfaces now render while the response is still being generated. The UI begins in one state, then updates as more data comes in. You see this in chat apps, logs, transcription tools, and other real-time systems.
The tricky part is that the interface is not in a fixed state; it keeps changing as new content comes in. It grows where lines become longer and new blocks appear. Something that was just below the screen can suddenly move, and the user’s scroll position becomes harder to manage. Parts of the UI might even be incomplete while the user is already interacting with it.
In this article, we’ll take a simple interface and make it handle this properly. We’ll look at how to keep things stable, manage scrolling, and render partial content without breaking the reading experience.
What Does A Streaming UI Actually Look Like?I’ve built three demos that stream content in different ways: a chat bubble, a log feed, and a transcription view. They look different on the surface, but they all run into the same three problems.
The first is scroll. When content is streaming in, most interfaces keep the viewport pinned to the bottom. That works if you are just watching, but the moment you scroll up to read something, the page snaps back down. You did not ask for that. The interface decided for you, and now you’re fighting it instead of reading.
The second is layout shift. Streaming content means containers are constantly growing, and as they do, everything below shifts downward. A button you were about to click is no longer where it was. A line you were reading has moved. The page is not broken; it is just that nothing stays still long enough to interact with comfortably.
The third is render frequency. Browsers paint the screen around 60 times per second, but streams can arrive much faster than that. This means the DOM, which is the browser’s internal representation of everything on the page, ends up being updated for frames the user will never actually see. Each update still costs something, and that cost adds up quietly until performance starts to slip.
As you go through each demo, pay attention to where things start feeling off. That small moment of friction when the interface starts getting in your way. This is exactly what we are here to fix.
Example 1: Streaming AI Chat ResponsesThis is the most familiar case. You click Stream, and the message starts growing token by token, just like a typical AI chat interface.
Here’s what I want you to try:
- Click the Stream button.
- Try scrolling upwards while the message is streaming.
- Increase the speed (to something like 10ms).
You will notice something subtle but important: the UI keeps trying to pull you back down. Basically, it is making a decision for you about where your attention should be.
That’s one example. Let’s look at another.
Example 2: Live Processing In A Log ViewerThis example looks different on the surface, but the problem is actually very similar to the first example. Rather than a message that gets longer over time, new lines are appended continuously, like a terminal or a log stream.
The interesting part here is the tail toggle. It makes the trade-off between interaction and stable interfaces very clear:
Again, here is what I want you to try:
- Click the Start button.
- Allow the logs to stream past the container’s height.
- Scroll up to the beginning.
- Stop the stream and disable the “tail” option.
Notice that, when tail is enabled, the UI follows the new content. But you’re unable to scroll up and stay in place. Instead, you need to stop the stream or enable “tail” to explore the content.
Example 3: Dashboard Displaying Real-Time MetricsIn this case, the UI updates in place:
- Numbers change,
- Charts shift,
- Values refresh continuously.
There is no scroll tension this time, but a different issue shows up. That’s what we’ll get into next.
Why The UI Feels Unstable And How To Fix ItIf you tried the chat demo and scrolled upward while the responses were coming in, you may have spotted the first issue right away: the UI keeps pulling you back down to the latest streamed content as it updates. This takes you out of context and never allows you the time to fully digest the content once it has passed.
We see that exact same issue in the second example, the log viewer. Without the tail toggle, the streamed content overrides your scroll position.
These aren’t bugs in the traditional sense that they produce code errors; rather, they are accessibility issues that affect all users. That said, they can be fixed and prevented with careful UX considerations as you plan and test your work.
Ensure Predictable Scroll BehaviorThis is the goal:
- Enable auto-scrolling when detecting that the user is at the bottom of the stream.
- Stop auto-scrolling when the user has scrolled upwards.
- Resume auto-scrolling if the user scrolls back to the bottom of the stream.
To do that, we need to know whether the user has intentionally moved away from the bottom, which we can assume is true when the scroll position is manually changed. We can track that behavior with a flag.
let userScrolled = false; chatEl.addEventListener('scroll', () => { const gap = chatEl.scrollHeight - chatEl.scrollTop - chatEl.clientHeight; userScrolled = gap > 60; });That 60px threshold matters. Without it, tiny layout changes (like a new line) would briefly create a gap and break auto-scroll, even if the user didn’t actually scroll.
Now let’s make sure that we enable auto-scrolling only when the user’s scroll position is equal to the stream’s scroll height, i.e., the user is at the bottom of the stream:
function autoScroll() { if (!userScrolled) { chatEl.scrollTop = chatEl.scrollHeight; } }One small thing that’s easy to miss: we need to reset userScrolled once a new stream begins. Otherwise, one scroll from a previous message can silently disable auto-scroll for the next one.
Solidify Layout StabilityWe saw this in the first example as well. As new content streams in, the layout jumps, or shifts, taking you out of your current context. To be specific about what’s shifting: it’s not the page layout in a broad sense, it’s the content directly below the chat bubble.
There’s also a subtler artifact worth calling out before we look at the code: cursor flicker. Because we’re wiping innerHTML and recreating every element on every tick, the cursor is being destroyed and re-added constantly, up to 80 times per second at fast speeds.
At normal speed, it’s easy to miss, but slow the slider down to around 30ms, and you’ll see a faint but persistent flicker at the end of the text. Once we fix the rebuild pattern, the flicker disappears entirely.
None of these changes is a big effort on its own. But once they are in place, the interface stops reacting blindly to every update. It becomes easier to read, easier to control, and a lot less distracting, even though the content is still coming in continuously.
There are even more considerations to take into account for ensuring a stable, predictable, and good user experience. For example, what happens if the stream is canceled mid-flow? And what can we do to ensure that user preferences are respected for things like reduced motion, keyboard navigation, and screen reader accessibility? Let’s get into those next.
Handling Interrupted StreamsMost streaming interfaces include a way to stop or cancel the stream. We saw that in the demos. But stopping often leaves the UI in an awkward state. The cursor might keep blinking, buttons don’t update, and the message just freezes mid-stream with no clear indication that it didn’t finish.
The problem is that the stop is usually wired to do one thing: cancel the timer. That’s not enough. You also need to (1) clear the pending buffer, (2) remove the cursor, (3) mark the response as incomplete, and (4) reset the buttons. Here’s how we accomplish those.
1. Stop The Stream CleanlyHere’s what stopStream needs to do, in order:
- Cancel the timer and flip the isStreaming flag so no more ticks run.
- Clear the requestAnimationFrame (RAF) buffer so nothing still queued gets written on the next frame.
Clearing the pending property matters because there might be characters buffered from the last stream instance that haven’t been flushed yet. If you don’t clear it, the next requestAnimationFrame fires, drains the buffer, and writes those characters to the DOM after the stream has officially stopped.
Now we move on to removing the cursor by calling markStopped on the bubble:
if (cursorEl && cursorEl.parentNode) cursorEl.remove(); markStopped(aiBubble); stopBtn.style.display = 'none'; retryBtn.style.display = ''; playBtn.style.display = ''; setStatus('Stopped', 'stopped'); chat.removeEventListener('scroll', onScroll); }The cursorEl.parentNode check is there because stopStream is also called internally when a new message fires mid-stream, at which point the cursor might already be gone. Calling remove() on a detached node throws, so we check first.
markStopped appends a small label to the bottom of the bubble so the user knows the response didn’t finish:
function markStopped(bubble) { if (!bubble) return; bubble.classList.add('stopped'); const label = document.createElement('span'); label.className = 'stopped-label'; label.textContent = 'response stopped'; bubble.appendChild(label); }The null check on bubble handles the edge case where stop fires before the AI message element has been initialized, which can happen if the user clicks stop during the 300ms delay before the bubble appears.
Provide A Retry OptionIf the stream simply stops — perhaps due to a network issue or some other unexpected error — we ought to provide the user with a path to re-attempt the stream. What that basically means is preventing the UI from doing the expensive work needed to scroll back up to the top, re-read the prompt, and retype it. With a retry option, the user only needs to click a button, and the stream restarts from the current position.
To make that work, we need to hold onto the question when the stream starts:
let lastQuestion = ''; function startStream(question, answer) { lastQuestion = question; // rest of setup... }Then, when the retry attempt runs, we reset everything and start fresh:
function retryStream() { if (currentMsgEl && currentMsgEl.parentNode) { currentMsgEl.remove(); } charIndex = 0; userScrolled = false; pending = ''; rafQueued = false; isStreaming = true; retryBtn.style.display = 'none'; stopBtn.style.display = ''; setStatus('Streaming...', 'streaming'); chat.addEventListener('scroll', onScroll, { passive: true }); setTimeout(() => { initAIMsg(); tick(lastAnswer); }, 200); }The reset is critical. Every piece of state needs to go back to its initial value, just like a brand new stream.
Note: We remove the entire message row (currentMsgEl), not just the bubble. If only the bubble is removed, the layout wrapper and avatar remain persistent and break the structure.
Send A New Message Mid-StreamThere’s one more edge case that’s easy to miss. If the user sends a new message while a stream is still running, you end up with two loops writing to the DOM at the same time. The result is messy, and characters from different responses get mixed together.
Here’s what to do: stop the current stream before starting a new one.
function startStream(question, answer) { if (isStreaming) { clearTimeout(streamTimer); isStreaming = false; pending = ''; rafQueued = false; if (cursorEl && cursorEl.parentNode) cursorEl.remove(); chat.removeEventListener('scroll', onScroll); } // now reset and start fresh charIndex = 0; userScrolled = false; isStreaming = true; lastQuestion = question; // ... }Here, we inline the cleanup rather than calling stopStream directly because stopStream also calls markStopped and resets the buttons. The next demo has all three behaviors wired up. You can start a stream, hit “Stop” mid-stream, and the cursor disappears, the “response stopped” label appears, and a “Retry” buttons displayed.
AccessibilityStreaming interfaces are often built and tested with a mouse, so they may feel just fine in a browser, but break down in other situations that may not have been considered, like whether a screen reader announces new content at all. Or navigating with a keyboard might get stuck or lose focus as things update. And, of course, moving text can be uncomfortable — or even disabling — for those with motion sensitivities.
The good part is that you do not need to rebuild everything to accommodate these things; they can be fixed with solutions that sit on top of what is already there.
Accommodating Assistive Technology With Live RegionsScreen readers don’t automatically announce content that shows up on its own. They usually read things when the user moves to them. So, in a streaming UI, where text builds up over time, nothing gets announced. The content is there, but the user doesn’t hear anything.
The fix is aria-live. It tells the browser to watch a container and announce updates as they happen, without the user needing to move focus.
<div id="chat" role="log" aria-live="polite" aria-atomic="false" aria-label="Chat messages" ></div>- role="log" tells assistive tech this is a stream of updates, like a running transcript. Some tools handle this automatically, but it’s safer to be explicit so behavior stays consistent.
- aria-atomic="false" makes sure only the new content is announced. Without it, some screen readers try to read the whole message again on every update, which quickly becomes unusable.
- aria-live="polite" queues updates instead of interrupting. Use assertive only for things that really need immediate attention, like errors.
Earlier, we inserted a “Response Stopped” label to the message when the stream stops mid-stream. Visually, that’s enough. But for a screen reader, that change needs to be announced.
Since the message is inside a live region with aria-live="polite", the label will be automatically announced as new content when it’s added to the DOM. The live region already handles the announcement, so no additional ARIA is needed on the label itself.
The Retry button that appears next also needs context. If a screen reader simply says “Retry, button,” it’s not clear what action that refers to. You can fix that by adding an aria-label that includes the original question:
retryBtn.setAttribute( 'aria-label', `Retry: ${lastQuestion.slice(0, 60)}` );What you can do here is to set this label when the button appears, not on page load:
retryBtn.style.display = 'inline-block'; retryBtn.setAttribute( 'aria-label', `Retry: ${lastQuestion.slice(0, 60)}` );We also call retryBtn.focus() after stopping. That way, keyboard users don’t have to Tab around with the keyboard to find the next action.
Testing with assistive technology: Don’t rely on assumptions about how screen readers announce this. Test with actual tools like NVDA (Windows), JAWS (Windows), or VoiceOver (Mac/iOS). Browser DevTools can show you what’s exposed in the accessibility tree, but they can’t tell you how the content sounds. A real screen reader will reveal whether the announcement is happening at the right time and in the right way.
Account For Keyboard NavigationThe controls need to work with the keyboard while the UI is live, so the Stop button has to be reachable. For someone not using a mouse, Tab + Enter is the only way to cancel a running stream.
Using display: none is fine for hiding buttons; it removes them from the tab order. The problem is using things like opacity: 0 or visibility: hidden. Those hide elements visually, but they can still receive focus, so users end up tabbing onto something they can’t see.
Use :focus-visible so the focus ring shows up for keyboard navigation, but not for mouse clicks:
btn:focus-visible { outline: 2px solid #1d9e75; outline-offset: 2px; }The cursor inside the message should have aria-hidden="true". It’s just visual. Without that, some screen readers try to read it as text, which gets distracting.
Motion SensitivityThe typewriter effect we see in practically every AI interface produces constant motion. As we’ve already discussed, certain amounts of motion can be disabling. Thankfully, browsers expose prefers-reduced-motion, which detects a user’s motion preferences at the operating system level.
For streaming, the best approach is simple: skip the animation and render the full response at once. The content stays the same, only without the motion.
const reducedMotion = window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches; if (reducedMotion) { initAIMsg(); for (const char of text) appendChar(char); if (cursorEl && cursorEl.parentNode) cursorEl.remove(); done(); return; } tick(text); // normal animationIn CSS, the cursor blink also needs to stop. Despite being a minor detail, a blinking cursor element counts as flashing content.
@media (prefers-reduced-motion: reduce) { .cursor { animation: none; opacity: 1; } }There we go! The demo below puts everything from this article together, so you can see how these patterns work in practice. It also includes a reduced motion toggle, so you can test the instant render version easily.
ConclusionStreaming itself is mostly solved. Getting data from the server to the client is not the hard part anymore. What breaks is the UI on top of it.
When content updates continuously, small things start to matter, like scroll behavior, layout stability, render timing, and how the interface responds to user actions. If those aren’t handled well, the UI feels unstable and hard to use.
The patterns in this article fix that by:
- Keeping scroll position under the user’s control,
- Updating only what has changed,
- Batching renders per frame,
- Handling stop and retry actions, and
- Making the interface accessible.
You don’t need all of these every time. But when streaming is involved, these are the places things usually go wrong.
Further Reading- Using Server-Sent Events
How to open a connection, handle events, and reconnect when needed. This is the transport layer, everything here builds on. - Streams API
Streaming data directly from fetch. Useful when you need more control than SSE. - Chrome DevTools Performance panel
Helps you see layout recalculations and paint costs, so you can verify performance improvements. - “How Large DOM Sizes Affect Interactivity, And What You Can Do About It”, Jeremy Wagner
Why large DOM trees slow things down, and how to keep them under control in long streaming sessions.
A Fresh View In May (2026 Wallpapers Edition)
May has a way of sneaking in with longer days, softer light, and that first real hint of summer in the air. It’s the season of fresh ideas and just enough energy to start something new, or finally pick up something you’ve been putting off. And sometimes, all it takes to spark that little bit of inspiration is a fresh view… even if it’s just on your desktop.
That’s where our monthly wallpapers series comes in. For the past 15 years, artists and designers from around the world have been contributing their designs to celebrate each new month. This May is no exception. Created with care and a unique personal touch, every wallpaper in this collection comes in a variety of screen resolutions and can be downloaded for free. A huge thank-you to everyone who got creative — this post wouldn’t be possible without your wonderful support!
If you too would like to get featured in one of our upcoming wallpapers posts, please don’t hesitate to join in. We can’t wait to see what you’ll come up with! Happy May!
- You can click on every image to see a larger preview.
- We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.
Designed by Ricardo Gimenes from Spain.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“A quiet ritual, a shared moment, a pause in the rush — tea invites you to slow down and discover warmth in the smallest details. Let each cup unfold its own little story.” — Designed by PopArt Studio from Novi Sad, Serbia.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- with calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“A small bee with a big garden plan checks each flower on her list and looks for the next bloom to visit.” — Designed by Ginger IT Solutions from Serbia.
- preview
- with calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Summer is getting closer, but we’re reminded of a more wintry and eerie landscape, like that of ‘The Shining.’ A truly great film, proving that you don’t need much, but it needs to be used well to create suspense and terror.” — Designed by Veronica Valenzuela from Spain.
- preview
- with calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
“Buddha Purnima, falling on May 1st, is the most sacred Buddhist festival commemorating the birth, enlightenment, and passing of Gautama Buddha. It is observed on the full moon day of the Vaisakha month, symbolizing spiritual liberation and the triumph of peace. The day serves as a global reminder of his core teachings: non-violence, compassion, and the path to ending suffering.” — Designed by V D Photography from Surat, Gujarat, India.
- preview
- with calendar: 1280x720, 1920x1080, 2560x1440, 3840x2160
- without calendar: 1280x720, 1920x1080, 2560x1440, 3840x2160
“The longing for warmth, flowers in bloom, and new beginnings is finally over as we welcome the month of May. From celebrating nature on the days of turtles and birds to marking the days of our favorite wine and macarons, the historical celebrations of the International Workers’ Day, Cinco de Mayo, and Victory Day, to the unforgettable ‘May the Fourth be with you’, May is a time of celebration — so make every May day count!” — Designed by PopArt Studio from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1440x900, 1440x1050, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“This month is dedicated to flowers, to join us and brighten our days giving a little more color to our daily life.” — Designed by Verónica Valenzuela Jimenez from Spain.
- preview
- without calendar: 800x480, 1024x768, 1152x864, 1280x800, 1280x960, 1440x900, 1680x1200, 1920x1080, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
Designed by Nathalie Ouederni from France.
Understand Yourself“Sunsets in May are the best way to understand who you are and where you are heading. Let’s think more!” — Designed by Igor Izhik from Canada.
- preview
- without calendar: 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“We are in May, the spring month par excellence, and we celebrate it in the Amazon jungle.” — Designed by Veronica Valenzuela Jimenez from Spain.
- preview
- without calendar: 640x480, 800x480, 1024x768, 1280x720, 1280x800, 1440x900, 1600x1200, 1920x1080, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“I wanted to make a big painterly vista with some mountains and a deck and such.” — Designed by Mike Healy from Australia.
Today, Yesterday, Or TomorrowDesigned by Alma Hoffmann from the United States.
- preview
- without calendar: 1024x768, 1024x1024, 1280x800, 1280x1024, 1366x768, 1440x900, 1680x1050, 1920x1080, 1920x1200, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
Designed by Julie Lapointe from Canada.
GeoDesigned by Amanda Focht from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1680x1200, 1920x1080, 1920x1440, 2560x1440
Designed by Julia Versinina from Chicago, USA.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Ricardo Gimenes from Spain.
- preview
- without calendar: 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440, 3840x2160
“In spring, especially in May, we all want bright colors and lightness, which were not there in winter.” — Designed by MasterBundles from Ukraine.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Springtime, especially May, is my favorite time of the year. And I like popsicles — so it’s obvious isn’t it?” — Designed by Steffen Weiß from Germany.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Designed by Rachel Hines from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x1024, 1366x768, 1400x900, 1400x1050, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“We don’t usually count the breaths we take, but observing nature in May, we can’t count our breaths being taken away.” — Designed by Ana Masnikosa from Belgrade, Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“The ‘lily of the valley’ came earlier this year. In France, we celebrate the month of May with this plant.” — Designed by Philippe Brouard from France.
- preview
- without calendar: 800x480, 1024x768, 1024x1024, 1280x720, 1280x1024, 1440x900, 1920x1080, 1920x1440, 2560x1440
“April and May are usually when everything starts to bloom, especially the magnolia trees. I live in an area where there are many and when the wind blows, the petals make it look like snow is falling.” — Designed by Sarah Masucci from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“‘As knowledge increases, wonder deepens.’ (Charles Morgan) So I tried to create an illustration based on this.” — Designed by Bisakha Datta from India.
- preview
- without calendar: 320x480, 640x480, 800x480, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x900, 1400x1050, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“May should be as bright and colorful as this calendar! That’s why our designers chose these juicy colors.” — Designed by MasterBundles from Ukraine.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Lixia is the 7th solar term according to the traditional East Asian calendars, which divide a year into 24 solar terms. It signifies the beginning of summer in East Asian cultures. Usually begins around May 5 and ends around May 21.” — Designed by Hong, Zi-Cing from Taiwan.
- preview
- without calendar: 1024x768, 1080x1920, 1280x720, 1280x800, 1280x960, 1366x768, 1400x1050, 1680x1050, 1920x1080, 1920x1200, 2560x1440
Designed by Elise Vanoorbeek from Belgium.
Rainy Days“Winter is nearly here in my part of the world and I think rainy days should be spent at home with a good book!” — Designed by Tazi Design from Australia.
- preview
- without calendar: 320x480, 640x480, 800x600, 1024x768, 1152x864, 1280x720, 1280x960, 1600x1200, 1920x1080, 1920x1440, 2560x1440
“Inspired by a little-known ‘holiday’ on May 4th known as ‘Bird Day’. It is the first holiday in the United States celebrating birds. Hurray for birds!” — Designed by Clarity Creative Group from Orlando, FL.
- preview
- without calendar: 320x480, 640x480, 640x960, 640x1136, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“I designed Magical Sunset as a friendly reminder to take a moment and enjoy life around you. Each sunset and sunrise brings a new day for greatness and a little magic.” — Designed by Carolyn Warcup from the United States.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1400x1050, 1440x900, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
“Edwin Way Teale once said that ‘[t]he world’s favorite season is the spring. All things seem possible in May.’ Now that the entire nature is clothed with grass and branches full of blossoms that will grow into fruit, we cannot help going out and enjoying every scent, every sound, every joyful movement of nature’s creatures. Make this May the best so far!” — Designed by PopArt Studio from Serbia.
- preview
- without calendar: 320x480, 640x480, 800x480, 800x600, 1024x768, 1024x1024, 1152x864, 1280x720, 1280x800, 1280x960, 1280x1024, 1366x768, 1440x900, 1440x1050, 1600x1200, 1680x1050, 1680x1200, 1920x1080, 1920x1200, 1920x1440, 2560x1440
Feeling inspired? We’ll publish the June wallpapers on May 31, so if you’d like to be part of the collection, please don’t hesitate to submit your design. We are already looking forward to it!

