LAWSOFUX · motion lab
Concept · goal-gradient-effect

Goal-Gradient Effect

Opacity-stepped bands palette · warm tan / cream takeaways · 3

Definition

Effort accelerates as a perceived goal gets closer. The closer a user feels to completion, the harder they push to finish — and the more painful any added step feels. Even artificial progress (a head-start checkmark, a partial bar) reliably increases follow-through.

Why it matters for ShurIQ reports

A multi-page brief or evidence-trail walkthrough behaves like a multi-step task: visible progress through the report keeps the reader pushing to the end. Section indicators on the editorial brief, viewport pagination dots, and "3 of 5 viewports" affordances on the viz hub all convert ambient progress into motivation. Without them, a reader stalls in the middle and never reaches the recommendation.

Takeaways

Visual motion language

Progress bars accelerate visibly as the goal nears (ease-out curve, not linear), with a glow-burst on completion. Numbers count-up faster on the last interval than the first.

Cavalry recreation seed. 7 full-canvas-width rectangles (697×84 in a 697×702 viewbox), 19px vertical gutters. All filled #f4f1d0 (cream). Set fill-opacity per stripe top-to-bottom: 1.0, 0.8, 0.6, 0.4, 0.3, 0.2, 0.1. Animate each stripe fading in from 0 to its target opacity, sequential top-to-bottom, ~120ms per stripe (~840ms total). Hold 2s; loop. Background: warm tan #C9B477.

Origins

Clark Hull, 1932 — proposed the goal-gradient hypothesis, demonstrated empirically in 1934.

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 · goal-gradient-effect · Cavalry scene
// CORRECTED 2026-04-30 · verified from production page
// Motion family: opacity-stepped horizontal bands (7 full-width stripes)
// Opacity gradient 1.0 -> 0.1 cascading top-to-bottom
// Palette: warm tan + purples
// 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_goal-gradient-effect_";

  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    = "#C9B477";
  var CREAM = "#D6CDB0";

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

  // 7 full-width stripes, stepped opacity 1.0/0.8/0.6/0.4/0.3/0.2/0.1
  // Stripe geometry: 880 wide x 84 tall, 19px gutter -> step=103
  var stripeW = 880;
  var stripeH = 84;
  var step    = 103; // 84 + 19
  var topY    = (6 * step) / 2; // top stripe Y (positive=up)
  var opacities = [100, 80, 60, 40, 30, 20, 10];

  for (var j = 0; j < 7; j++) {
    var s = api.primitive("rectangle", PREFIX + "stripe_" + j);
    api.set(s, {
      "generator.dimensions": [stripeW, stripeH],
      "position.x": 0,
      "position.y": topY - j * step,
      "opacity": 0
    });
    api.setFill(s, true);
    api.set(s, { "material.materialColor": CREAM });

    var t0 = j * 4;        // ~120ms per stripe (assuming 30fps -> 4 frames)
    var t1 = t0 + 8;
    api.keyframe(s, t0, { "opacity": 0 });
    api.keyframe(s, t1, { "opacity": opacities[j] });
    api.magicEasing(s, "opacity", t1, "EaseOut", "");
  }

  var layerCount = api.getAllSceneLayers().length;
  console.log("scene built: goal-gradient-effect (" + layerCount + " layers)");
})();