Definition
When a user faces too many simultaneous options, decision quality collapses and the user disengages or defers. The cost is not deciding wrong; the cost is not deciding at all. The phrase travels under "paradox of choice," but the operational behavior is paralysis.
Why it matters for ShurIQ reports
A 21-company stack rank can become noise unless the viewport collapses into the 3–5 entries a reader can actually act on. Featured rows, default sorts, and progressive disclosure on competitor cards keep an executive moving through the brief instead of stalling on row eleven. The dashboard's job is to pre-decide what to show first.
Takeaways
- Default to a curated short list, with the full set available behind one expansion gesture.
- For comparison panels (pricing tiers, competitor cards), enforce side-by-side layout — never force the reader to keep tabs in working memory.
- Highlight one recommended option per decision surface; remove every option the reader cannot act on this week.
- Add filter and search before adding rows — opportunity to narrow always beats opportunity to scroll.
Visual motion language
Show the long list first, then collapse non-priority rows to half-height with a 300ms ease-out as the priority rows zoom and the reader's focus narrows. The collapse should feel like the system is helping the reader decide.
Origins
Alvin Toffler, 1970 — introduced in Future Shock under the term "overchoice."
Cavalry scene
The script below builds this concept's motion in Cavalry through the Stallion bridge. Pipe to cavalry_run_script via MCP, or paste into Cavalry's JavaScript Editor.
// Laws of UX · choice-overload · Cavalry scene
// Motion family: grid-stagger
// Palette: cobalt + cream
// To run: pipe to cavalry_run_script tool, or paste into Cavalry's JavaScript Editor
// Built 2026-04-30 by ShurAI
(function () {
var PREFIX = "claude_lawofux_choice-overload_";
var existing = api.getAllSceneLayers();
for (var i = 0; i < existing.length; i++) {
try {
var nm = api.getNiceName(existing[i]);
if (nm && nm.indexOf("claude_lawofux_") === 0) api.deleteLayer(existing[i]);
} catch (e) {}
}
var BG = "#1E5C8C";
var DARK = "#163E5C";
var CREAM = "#D6CDB0";
var bg = api.primitive("rectangle", PREFIX + "bg");
api.set(bg, { "generator.dimensions": [1080, 1080], "position.x": 0, "position.y": 0 });
api.setFill(bg, true);
api.set(bg, { "material.materialColor": BG });
// 5-cols × 4-rows grid of dots, 90px spacing, 60px diameter
var COLS = 5, ROWS = 4, SPACE = 100, R = 30;
var startX = -((COLS - 1) * SPACE) / 2;
var startY = ((ROWS - 1) * SPACE) / 2;
var idx = 0;
for (var r = 0; r < ROWS; r++) {
for (var c = 0; c < COLS; c++) {
var d = api.primitive("ellipse", PREFIX + "dot_" + r + "_" + c);
api.set(d, {
"generator.radius": [R, R],
"position.x": startX + c * SPACE,
"position.y": startY - r * SPACE,
"opacity": 0
});
api.setFill(d, true);
var fill = ((r + c) % 2 === 0) ? CREAM : DARK;
api.set(d, { "material.materialColor": fill });
var inFrame = idx * 2; // ~80ms stagger
var endFrame = inFrame + 8; // 333ms fade
api.keyframe(d, inFrame, { "opacity": 0 });
api.keyframe(d, endFrame, { "opacity": 100 });
idx++;
}
}
// Ghost overflow row below
for (var g = 0; g < 5; g++) {
var gd = api.primitive("ellipse", PREFIX + "ghost_" + g);
api.set(gd, {
"generator.radius": [R, R],
"position.x": startX + g * SPACE,
"position.y": startY - ROWS * SPACE,
"opacity": 0
});
api.setFill(gd, true);
api.set(gd, { "material.materialColor": CREAM });
var f0 = 50 + g * 5;
var f1 = f0 + 12;
api.keyframe(gd, f0, { "opacity": 0 });
api.keyframe(gd, f1, { "opacity": 35 });
}
var layerCount = api.getAllSceneLayers().length;
console.log("scene built: choice-overload (" + layerCount + " layers)");
})();