
TL;DR
A simple image rotation button reveals deep truths about responsive interface design - why buttons must always respond predictably, even during animations.
A surprisingly engaging debate broke out on Hacker News this week over a topic that sounds trivial: how should a photo rotation button behave when you tap it multiple times quickly?
Marcin Wichary's post "If you're a button, you have one job" uses this seemingly simple interaction to surface fundamental principles about responsive interface design - principles that remain just as relevant in 2026 as they were in the era of command-line interfaces, and that show up repeatedly in our rundown of AI design slop patterns.
Wichary compares how iPhone and Nothing Phone (Android) handle rapid taps on an image rotation button. He taps eight times quickly - which should return the image to its original orientation (8 x 90 degrees = 720 degrees = 2 full rotations).
iPhone's approach: Buffers all eight taps. The rotation animation queues up and executes sequentially. Every tap counts.
Nothing Phone's approach: Ignores taps while the animation is playing. You get haptic feedback (the phone vibrates), but the tap is discarded. Only the first tap and the last tap register.
The result? On iPhone, you end up where you expected. On Nothing Phone, you're stuck at some unexpected orientation and have to pay attention, count taps, and wait for animations to finish before tapping again.
This might seem like a minor annoyance for a rotation button. But Wichary makes a compelling case for why it reveals something fundamental about good interface design.
The core principle: never force the user to wait for the animation to finish.
There are two acceptable approaches:
What's not acceptable is blocking input while showing visual feedback (haptics, button depress animation) that suggests the input was received. That's a lie your interface is telling the user.
The Hacker News discussion with 223 comments touches on several deeper threads.
The THERAC-25 connection: Multiple commenters drew parallels to the infamous radiation therapy machine disaster, where experienced users hitting keys faster than the interface could process them led to safety features being bypassed. The lesson: input handling bugs are not just UX annoyances - they can have serious consequences.
Animation fatigue: Several iOS users vented frustration about Apple's increasing use of animations that serve no functional purpose. One commenter noted that Apple Maps wastes 1-2 seconds slowly rotating from your phone's orientation from days ago, even when you just want to see where you are now.
The "situational power user" insight: Wichary's concept resonated strongly. Even casual apps occasionally serve serious purposes. Someone rotating dozens of document photos isn't being impatient - they need professional-grade reliability from a consumer tool. Your grandmother texting might need to tap a button 8 times to rotate a photo of her cat before sending it to you.
Keyboard buffering precedent: Experienced developers pointed out that keyboard input buffering is a solved problem. We've had type-ahead working reliably since the 1970s. The problem is that touch interface designers forgot (or never learned) these lessons.
Skeuomorphism vs flat design tangent: The thread wandered into a broader discussion about whether modern flat UI design has made interfaces harder to use by removing visual affordances. This is somewhat off-topic from Wichary's point, but the engagement shows how much developers care about these foundational UX questions.
From the archive
Jul 5, 2026 • 5 min read
Jul 5, 2026 • 5 min read
Jul 5, 2026 • 9 min read
Jul 5, 2026 • 7 min read
For developers, the fix is straightforward:
// Bad: Ignore input during animation
const handleRotate = () => {
if (isAnimating) return; // Don't do this
setIsAnimating(true);
rotate90();
setTimeout(() => setIsAnimating(false), 300);
};
// Good: Buffer inputs
const [pendingRotations, setPendingRotations] = useState(0);
const handleRotate = () => {
setPendingRotations(prev => prev + 1);
};
useEffect(() => {
if (pendingRotations > 0 && !isAnimating) {
setIsAnimating(true);
rotate90();
setTimeout(() => {
setIsAnimating(false);
setPendingRotations(prev => prev - 1);
}, 300);
}
}, [pendingRotations, isAnimating]);
Or even simpler - skip the animation entirely when multiple inputs arrive:
const handleRotate = () => {
if (isAnimating) {
// Skip to final state immediately
cancelAnimation();
}
rotate90();
};
The choice between buffering and interrupting depends on context. For rotation, buffering makes sense because users expect their taps to accumulate. For navigation, interrupting might be better - if a user taps a different menu item, they want to go there, not queue up both destinations.
Wichary's post is part of his broader "Unsung" series about overlooked aspects of interaction design. The underlying message: the best interfaces are the ones you don't notice. They respond instantly, predictably, and never make you wait or think about how to use them.
This applies beyond buttons:
In an era where we're building increasingly complex AI-powered interfaces, these fundamentals matter more than ever. Your agent might take 30 seconds to process a request - but the button that triggers it should respond in 30 milliseconds. Claude's own outage-driven workflow design lessons make a similar point: interfaces should degrade honestly rather than silently swallow input.
Interface responsiveness isn't just about polish. It's about trust. When a user taps a button and nothing happens, they lose confidence in the entire system. They start double-tapping, triple-tapping, wondering if the app is frozen. That uncertainty cascades into frustration.
The fix is almost always simple. It's just that nobody prioritizes it. Animations ship because they look good in demos. Input buffering doesn't ship because it's invisible - until its absence makes the user feel like they're fighting their own device.
As one HN commenter put it: "The best UI is the one that makes you feel like you're in control, not like you're waiting for permission."
Read next
A developer reverse-engineered a travel itinerary app, discovered it was just reformatting JSON, and replaced the entire 43MB app with a 0.05MB webpage.
7 min readA developer discovered that Claude Code's thinking output is summarized, not the raw reasoning. Here's what Anthropic's docs actually say - and why it matters.
5 min readDario Amodei published Anthropic's stance on open-weights models this week - no total ban, but support for chip export controls, distillation crackdowns, and mandatory safety testing. HN responded with 800+ comments calling it regulatory capture. Here is what the CEO said, what the thread argued, and why the debate matters for every developer deploying AI.
8 min readTechnical content at the intersection of AI and development. Building with AI agents, Claude Code, and modern dev tools - then showing you exactly how it works.
Terminal emulator built in Zig with platform-native UI and GPU acceleration. 2ms key-to-screen latency. Metal on macOS,...
View ToolOpen-source AI agent built in Rust, now governed by the Agentic AI Foundation at the Linux Foundation. Desktop app, CLI,...
View ToolConfigure Claude Code for maximum productivity -- CLAUDE.md, sub-agents, MCP servers, and autonomous workflows.
AI AgentsWhat MCP servers are, how they work, and how to build your own in 5 minutes.
AI AgentsStep-by-step guide to building an MCP server in TypeScript - from project setup to tool definitions, resource handling, testing, and deployment.
AI Agents
Check out Magic Patterns: https://magicpatterns.1stcollab.com/developersdigest_4 In this video, I share insights inspired by the CEO of Figma on the importance of design in the age of AI-generated...

Check out Magic Patterns; https://magicpatterns.1stcollab.com/developersdigest_3 In this video, explore Magic Patterns, a platform that allows you to create front-end prototypes using natural...

Check out Magic Patterns here: https://magicpatterns.1stcollab.com/developersdigest_2 This video provides an in-depth look at the custom components library feature of Magic Patterns, a design...

PrismML's Bonsai 27B uses 1-bit quantization to compress a 27B model to 3.9GB - small enough to run on an iPhone. Here's...

Agent-Manager wraps tmux into a Go TUI that groups AI coding agents by project, shows live status for each, and lets you...

Hugging Face published a stunning technical play-by-play of a 4.5-day AI agent intrusion. The HN community is divided on...

Google DeepMind's Gemini Robotics 2 family gives humanoid robots whole-body control, dexterous hands, and multi-robot te...

OpenAI slashes GPT-5.6 Luna by 80% to $0.20/M input tokens, cuts Terra by 20%, adds Sol Fast mode at 2.5x speed, and rev...

Mitchell Hashimoto (Vagrant, Terraform, Ghostty) launched Superlogical - a new company building a terminal multiplexer t...

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.