Every user interface has its set pieces: the checkout flow, the onboarding wizard, the password reset sequence. These are moments where the interaction is predictable enough to plan in advance, yet critical enough that a stumble can break trust. In sports, set pieces are rehearsed until they become second nature—free kicks, penalty corners, lineout moves. In UI design, we do the same, but the transition from training ground (design mockups, prototypes, user testing) to match day (live production, real users, unpredictable contexts) is where many plans unravel. This guide compares three conceptual processes behind set-piece planning, helping teams choose the right approach for their context.
Why Set-Piece Planning Matters Now
Modern interfaces are more complex than ever. A single page might contain multiple micro-interactions: form validation, tooltip triggers, animation sequences, and error recovery paths. Each of these can be considered a set piece—a bounded interaction that can be designed, tested, and optimized independently. The problem is that many teams treat every interaction as a one-off, reinventing the wheel for each feature. This leads to inconsistency, longer development cycles, and a higher cognitive load for users who must relearn patterns across the product.
Set-piece planning addresses this by treating common interaction patterns as reusable assets. Instead of designing a new modal from scratch each time, a team defines a modal pattern with specific behaviors: how it opens, how it closes, what happens on background click, how keyboard navigation works. This pattern becomes a set piece that can be deployed across the product. The challenge lies in how you conceptualize and document these pieces—too rigid and they break in edge cases; too loose and they lose consistency.
We see three dominant conceptual processes in the industry: linear scripting, conditional branching, and emergent pattern libraries. Each has its origins in different design philosophies and toolsets. Linear scripting comes from motion design and animation storyboards. Conditional branching borrows from logic trees and state machines. Emergent pattern libraries grow out of design system thinking and atomic design. Understanding their trade-offs helps teams decide which to use for which scenario.
The stakes are high. Poorly planned set pieces lead to fragmented user experiences, accessibility failures, and technical debt. A button that animates differently in every screen is not just ugly—it's confusing. A form that recovers from errors inconsistently can cause data loss. By comparing these processes, we aim to give teams a framework for making deliberate choices rather than defaulting to whatever tool they used last.
Core Idea in Plain Language
Think of a set piece as a predictable interaction sequence that you can design, test, and reuse. The core idea is that you don't want to improvise every time a user clicks a button. You want a plan—a script, a decision tree, or a pattern—that guides the interaction from start to finish. The three processes differ in how much they prescribe vs. how much they leave open.
Linear scripting is like a movie script: every frame is planned in order. When the user clicks 'Add to Cart', the button changes to a spinner, then a checkmark, then the cart icon updates, then a toast appears. Each step is fixed. This works well for simple, deterministic flows where the outcome is always the same. But it breaks when something unexpected happens—a network error, a user who double-clicks, an accessibility tool that intercepts the animation.
Conditional branching is like a choose-your-own-adventure book: the interaction follows different paths based on conditions. If the user is logged in, go to checkout; if not, show a login modal. Within the modal, if the user clicks 'Forgot password', branch to reset flow. This handles more real-world complexity but requires designers and developers to anticipate every branch. It can become unwieldy if there are too many conditions.
Emergent pattern libraries are less about scripting specific sequences and more about defining reusable behaviors that combine at runtime. Instead of scripting a modal, you define behaviors: open, close, overlay, focus trap. Developers compose these behaviors as needed. This is flexible and scalable but requires a shared vocabulary and strong governance to prevent pattern drift.
Which one is best? It depends on the team's maturity, the product's complexity, and the team's ability to enforce consistency. A startup might benefit from linear scripts for its first few features. A mature design system team might prefer emergent patterns. The key is to recognize that each process has a place and that mixing them thoughtfully can be powerful.
How It Works Under the Hood
Let's peel back the layers of each process to see what they demand from teams and tools.
Linear Scripting
Linear scripting starts with a storyboard: a sequence of frames showing the interface at each step. Tools like Figma, Principle, or After Effects are used to prototype the exact timing and easing. The script is then handed to developers as a spec with precise durations, easing curves, and state changes. Under the hood, this often translates to CSS keyframe animations or JavaScript promises that chain actions. The advantage is predictability—what you see in the prototype is what you get in production. The disadvantage is fragility: any deviation (slow network, user interruption) breaks the script, and the fallback behavior is often undefined.
Conditional Branching
Conditional branching requires a state machine or decision tree. Designers map out all possible states and transitions using tools like XState, Sketch (with plugins), or even a flowchart. Each node represents a state (e.g., 'idle', 'loading', 'success', 'error'), and edges represent transitions triggered by events. The spec includes not just the happy path but every branch: what happens when the API returns a 500, what happens when the user hits Escape, what happens when the session expires mid-flow. Developers implement this as a finite state machine in code, often using libraries like XState or Redux. The advantage is robustness—the interaction handles all known conditions. The disadvantage is complexity: the state machine can grow exponentially, and maintaining it requires discipline.
Emergent Pattern Libraries
Emergent pattern libraries work at a higher level of abstraction. Instead of scripting a specific flow, the team defines a set of behaviors (e.g., 'focusable', 'dismissable', 'animatable') that can be composed. These behaviors are often implemented as React hooks, Vue composables, or Web Components. The design system provides the building blocks, and developers assemble them per context. For example, a modal pattern might include behaviors for overlay click dismissal, Escape key handling, focus trapping, and animation presets. Each behavior is independently tested and documented. The advantage is flexibility—the same behaviors can be combined in novel ways without redesign. The disadvantage is abstraction overhead: new team members must learn the behavior library, and debugging composed behaviors can be harder.
Worked Example: Password Reset Flow
Let's walk through a common set piece—password reset—using each process. This will highlight the practical differences.
Linear Scripting Approach
In linear scripting, the designer creates a storyboard: Step 1: User clicks 'Forgot password' → link turns gray. Step 2: A modal slides up from bottom over 300ms with easing ease-out. Step 3: User enters email and clicks 'Send reset link' → button shows spinner for 1.2s. Step 4: Success message appears with a green checkmark animation. Step 5: Modal auto-closes after 3s. The developer implements this as a precise sequence, often using a promise chain or CSS animation with delays. This works perfectly on a fast connection with no errors. But what if the email is invalid? The script doesn't account for it—the designer assumed the happy path. The developer must add a conditional, breaking the linear model.
Conditional Branching Approach
Here, the team maps all states: idle, email entry, loading, success, error (invalid email), error (network failure), rate-limited. Each state has defined transitions. For example, from 'email entry', if user clicks 'Send' and email is valid, go to 'loading'. If API returns 400, go to 'error' with message. If API returns 429, go to 'rate-limited' with countdown. The designer specifies the UI for each state: error message placement, button state, animation for error shake. The developer implements a state machine that ensures only valid transitions occur. The result is robust—every known condition is handled. But the spec is large, and maintaining it requires updating the state machine for new edge cases (e.g., what if the user switches tabs mid-flow?).
Emergent Pattern Library Approach
The team has predefined behaviors: 'form', 'validation', 'async-action', 'notification', 'modal'. They compose these for the password reset. The form behavior handles input state and validation rules. The async-action behavior handles loading, success, and error states generically. The notification behavior can show success or error toasts. The modal behavior provides overlay and dismiss. The developer assembles them with configuration: a modal containing a form with an async action that triggers a notification on result. The behaviors are reused across the product—the same async-action behavior is used for login, signup, and profile updates. The advantage is consistency and speed: new flows can be assembled quickly. The downside is that the team must invest in building and maintaining the behavior library, and debugging a composed flow can require tracing through multiple behavior layers.
Edge Cases and Exceptions
No process handles every situation perfectly. Here are common edge cases that challenge each approach.
Network Variability
Linear scripts assume ideal conditions. In practice, network latency can cause animations to finish before data arrives, or data can arrive before an animation completes. A linear script that shows a spinner for exactly 1.2 seconds might leave users staring at a frozen button if the request takes longer. Conditional branching handles this by defining states like 'loading' that persist until the response arrives, but it requires careful design of loading indicators that don't rely on fixed durations. Emergent patterns often rely on generic loading states that adapt, but they may lack the polish of a custom animation.
Accessibility Overrides
Screen readers, keyboard navigation, and reduced-motion settings can disrupt set pieces. A linear script that relies on visual animations may fail for voice control users who trigger actions faster than the animation chain. Conditional branching can include accessibility states (e.g., 'reduced-motion' branch that skips animations), but this adds complexity. Emergent patterns can be designed with accessibility built into each behavior (e.g., focus trapping in modal behavior respects reduced motion), but testing all combinations is difficult.
Concurrent Interactions
What happens when a user triggers a second action while a set piece is in progress? Linear scripts often assume single-threaded interaction and may queue or ignore subsequent inputs. Conditional branching can define a 'blocked' state that disables inputs during transitions. Emergent patterns rely on the developer to compose concurrency handling, which can lead to inconsistencies across features. For example, one modal might allow background interaction while another blocks it.
Internationalization
Text length varies by language, which can break linear scripts that rely on precise layout. A button that fits 'Send' in English might overflow with 'Enviar' in Spanish. Conditional branching can include layout states for different text lengths, but this is rarely done. Emergent patterns with flexible containers handle this better, but they may not account for right-to-left languages in animation directions.
Limits of the Approach
Each process has inherent limitations that teams should acknowledge before committing.
Linear Scripting Limits
Linear scripting is brittle. It assumes a deterministic world where every user follows the same path. Real users interrupt, backtrack, and multitask. A linear script that works in a usability lab may fail in the wild when a user receives a phone call mid-checkout. It also scales poorly: every variation requires a new script, leading to a proliferation of similar but slightly different sequences. Teams using linear scripting often end up with 'script drift' where the same pattern behaves differently across features because each script was written independently.
Conditional Branching Limits
Conditional branching is only as good as the branches you anticipate. Real-world interactions have infinite variability—user roles, device capabilities, third-party integrations, and environmental factors (battery saver, dark mode, font size). Mapping all branches is impractical. The state machine can become a 'big ball of mud' with hundreds of states and transitions that are hard to reason about. Moreover, conditional branching often leads to defensive design: every possible error is handled, but the UX becomes cluttered with error messages and fallback states that users rarely see.
Emergent Pattern Library Limits
Emergent patterns require high team maturity and strong governance. Without it, behaviors diverge: one developer might use a notification behavior with a slide animation, another with a fade. The library becomes inconsistent, defeating its purpose. Onboarding new team members is slow—they must learn the behavior vocabulary before contributing. Debugging is harder because the root cause of a bug might be in a behavior layer that the developer didn't write. Finally, emergent patterns can feel generic; custom flows that need a unique interaction may require bending the library in ways it wasn't designed for.
Reader FAQ
Q: Can we mix these processes in the same product?
A: Yes, and many teams do. For example, use linear scripting for high-visibility marketing flows (onboarding, checkout) where polish matters, conditional branching for form-heavy features (settings, profile), and emergent patterns for internal tools. The risk is inconsistency—users may notice different interaction patterns. Define clear criteria for when to use each.
Q: Which process is best for a startup with a small team?
A: Start with linear scripting for your core flows. It's fast to prototype and implement, and you can iterate quickly. As the product grows and you encounter edge cases, introduce conditional branching for critical paths. Invest in an emergent pattern library only when you have a design system team or at least three developers consistently building similar features.
Q: How do we test set pieces effectively?
A: For linear scripts, test with real network conditions and accessibility tools. For conditional branching, use state machine visualizers to simulate all transitions. For emergent patterns, test each behavior in isolation and then in combination. Automated visual regression testing helps catch drift.
Q: What tools support each process?
A: Linear scripting: Figma prototypes, Principle, After Effects. Conditional branching: XState, Sketch flowcharts, Mermaid diagrams. Emergent patterns: React Storybook, Pattern Lab, Zeroheight. The tool matters less than the conceptual alignment across the team.
Q: How do we prevent set-piece planning from slowing down development?
A: Start small. Pick one high-frequency interaction (e.g., button loading state) and define it as a set piece. Document it minimally—a code snippet and a short spec. Expand only when you see repetition. Over-planning upfront is a common mistake; let the need emerge.
Practical Takeaways
Set-piece planning is not about rigid rules but about intentional choices. Here are three specific moves you can make this week.
Audit your current set pieces. List the five most common interaction sequences in your product (login, search, checkout, etc.). For each, note which process was used to design it. You'll likely find a mix, sometimes unintentionally. Identify inconsistencies—e.g., two modals that behave differently on Escape key.
Choose one process for your next feature. Based on the feature's complexity and team size, pick linear, conditional, or emergent. Write a one-page spec that defines the set piece using that process's language (storyboard, state machine, or behavior composition). Share it with developers before coding begins.
Test your set pieces against edge cases. For each set piece, test three scenarios: slow network (use throttling), screen reader interaction (VoiceOver or NVDA), and reduced motion (enable in OS settings). Fix the top three failures. This will reveal which process is working and where it breaks.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!