LAWSOFUX · motion lab
Concept · paradox-of-the-active-user

Paradox of the Active User

Single-form composition palette · warm tan / cream takeaways · 3

Definition

Users skip the documentation and start using the product immediately, even when reading the manual would save them time. They optimize for short-term task completion at the cost of long-term efficiency. Designers must accept this and embed guidance into the path of use.

Why it matters for ShurIQ reports

A new client receiving a brand-intelligence brief will not read the methodology page first; they will jump to the stack rank. Tooltips, hover-state explanations, and inline definitions on technical terms (consensus floor, brand power score, viewport) keep them oriented without forcing them to leave the page. The methodology page exists for trust, not for first-pass reading.

Takeaways

Visual motion language

First-encounter elements glow-burst gently to signal "new" without blocking; tooltips fade in on dwell with a 400ms delay so they assist without interrupting flow.

Cavalry recreation seed. Construct a Penrose tribar SVG from 3 trapezoids forming a triangle with shifted depths. Apply tints cream / mid / dark for the three faces. Rotate the entire group around its center continuously at 30°/sec (12s/full rotation). Optional: 1s slow opacity flicker every 6s suggesting "can't read the manual".

Origins

Mary Beth Rosson and John Carroll, 1987 — human-computer interaction research on novice users.

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 · paradox-of-the-active-user · Cavalry scene
// Motion family: single-form (rotating impossible-tribar)
// Palette: olive-mustard + cream tints
// 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_paradox-of-the-active-user_";

  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     = "#8C7C45";
  var LIGHT  = "#D6CDB0";
  var MID    = "#B5A875";
  var DARK   = "#6E5F2F";

  var bg = api.primitive("rectangle", PREFIX + "bg");
  api.set(bg, { "generator.dimensions": [1080, 1080] });
  api.setFill(bg, true);
  api.set(bg, { "material.materialColor": BG });

  // Approximate tribar with 3 staggered triangles forming a triangle outline
  // We use 3 outline triangles + 3 small inner ones for layered look
  var tints = [LIGHT, MID, DARK];

  // Outer triangle (light)
  var outer = api.primitive("polygon", PREFIX + "tri_outer");
  api.set(outer, {
    "generator.sides": 3,
    "generator.radius": 240,
    "position.x": 0, "position.y": 0,
    "rotation.z": 0,
    "opacity": 0
  });
  api.setFill(outer, true);
  api.set(outer, { "material.materialColor": LIGHT });

  // Middle triangle (mid)
  var mid = api.primitive("polygon", PREFIX + "tri_mid");
  api.set(mid, {
    "generator.sides": 3,
    "generator.radius": 170,
    "position.x": 0, "position.y": -10,
    "rotation.z": 0,
    "opacity": 0
  });
  api.setFill(mid, true);
  api.set(mid, { "material.materialColor": MID });

  // Inner triangle (dark)
  var inner = api.primitive("polygon", PREFIX + "tri_inner");
  api.set(inner, {
    "generator.sides": 3,
    "generator.radius": 100,
    "position.x": 0, "position.y": -20,
    "rotation.z": 0,
    "opacity": 0
  });
  api.setFill(inner, true);
  api.set(inner, { "material.materialColor": DARK });

  // Counter-rotated overlay triangle (creates the "impossible" interlock illusion)
  var overlay = api.primitive("polygon", PREFIX + "tri_overlay");
  api.set(overlay, {
    "generator.sides": 3,
    "generator.radius": 200,
    "position.x": 0, "position.y": 5,
    "rotation.z": 60,
    "opacity": 0
  });
  api.setFill(overlay, true);
  api.set(overlay, { "material.materialColor": MID });

  // Reveals
  api.keyframe(outer,   0,  { "opacity": 0   });
  api.keyframe(outer,   18, { "opacity": 100 });
  api.keyframe(overlay, 6,  { "opacity": 0   });
  api.keyframe(overlay, 24, { "opacity": 70  });
  api.keyframe(mid,     12, { "opacity": 0   });
  api.keyframe(mid,     28, { "opacity": 100 });
  api.keyframe(inner,   18, { "opacity": 0   });
  api.keyframe(inner,   34, { "opacity": 100 });

  // Continuous group rotation simulated by individual rotations
  var rotators = [outer, overlay, mid, inner];
  var startRot = [0, 60, 0, 0];
  for (var i = 0; i < rotators.length; i++) {
    api.keyframe(rotators[i], 30,  { "rotation.z": startRot[i]       });
    api.keyframe(rotators[i], 200, { "rotation.z": startRot[i] + 360 });
  }

  // Optional opacity flicker on outer (~6s)
  api.keyframe(outer, 144, { "opacity": 100 });
  api.keyframe(outer, 156, { "opacity": 70  });
  api.keyframe(outer, 168, { "opacity": 100 });

  var layerCount = api.getAllSceneLayers().length;
  console.log("scene built: paradox-of-the-active-user (" + layerCount + " layers)");
})();