{
  "schemaVersion": 1,
  "type": "resource",
  "id": "motion",
  "evaluation": {
    "reviewedOn": "2026-10-19",
    "status": "checked",
    "modes": [
      "local-fixture",
      "source-review"
    ],
    "summary": "Motion 14.4.0 interpolated 0→50→100 and restored opacity after cancellation. The raw animation still ran under reduced motion. An immediate pause comparison drifted; after two animation frames, the value remained stable for the next 100 ms.",
    "reportUrl": "/design-evaluations/resource-motion.json",
    "identity": {
      "target": "motion",
      "version": "14.4.0",
      "integrity": "sha512-JJTIdeNjtF2zi/py0ndRKxQF+8z2pcDUgJYXul7zqbhMvyTLRsPFR9ifE/j4cFCpCMlehQVJkTwd7BZFiPKgQg=="
    },
    "environment": [
      "Chromium 155.0.8059.82; fresh disposable browser context, no account state or ambient credential variables.",
      "Synthetic inputs only; no uploads, purchases, accounts or private data.",
      "Pinned extracted assets/modules; browser HTTP(S) and WebSocket requests denied. No install/lifecycle scripts; no process-wide Node egress guarantee."
    ],
    "tests": [
      {
        "name": "Numeric animation seek",
        "mode": "local-fixture",
        "method": "Seek a paused linear object animation at 0/0.5/1 seconds",
        "result": "pass",
        "observation": "[0,50,100]"
      },
      {
        "name": "DOM interpolation and cancel",
        "mode": "local-fixture",
        "method": "Seek opacity to half time then cancel",
        "result": "pass",
        "observation": "{\"values\":[0,50,100],\"opacity\":0.625,\"restored\":0.25}"
      },
      {
        "name": "Initial immediate pause comparison",
        "mode": "local-fixture",
        "method": "Request reduced motion; observe unguarded JS animation and pause",
        "result": "fail",
        "observation": "{\"reduced\":true,\"running\":true,\"paused\":false}"
      },
      {
        "name": "Reduced-motion boundary and pause",
        "mode": "local-fixture",
        "method": "Request reduced motion; pause then compare values after two animation frames and a further 100 ms",
        "result": "pass",
        "observation": "{\"reduced\":true,\"running\":true,\"immediate\":14.299999999999999,\"settled\":15.1,\"final\":15.1,\"paused\":true}"
      },
      {
        "name": "Framework integration",
        "mode": "local-fixture",
        "method": "Mount/unmount animated components in a real framework application",
        "result": "not-run",
        "observation": "No framework dependency tree or application was installed; lifecycle behavior remains untested."
      }
    ],
    "security": {
      "scope": "Manifest/license and selected entry/source inspection, plus the named synthetic local fixture. No active exploitation or full security audit.",
      "findings": [
        {
          "level": "caution",
          "basis": "observed",
          "title": "Motion policy belongs to the application",
          "detail": "The reduced-motion fixture still advanced the unguarded animation. Add an explicit preference branch and leave essential state changes readable without waiting for animation."
        },
        {
          "level": "caution",
          "basis": "observed",
          "title": "Pause measurement needs a settled rendered value",
          "detail": "The initial immediate-after-pause comparison failed. The follow-up recorded 14.3 immediately, 15.1 after two frames and 15.1 another 100 ms later. That supports settled pause behavior; it does not establish that every pending update stops synchronously."
        },
        {
          "level": "info",
          "basis": "observed",
          "title": "Pinned sample and network boundary",
          "detail": "The fetched archive matched its registry SHA-512. The selected fixture made zero outbound attempts under an HTTP/WebSocket deny rule. No package lifecycle scripts executed; this does not audit all package code or dependencies."
        }
      ],
      "limits": [
        "No React/Vue mount cycle, scroll-linked effects, touch gestures, frame-rate profiling, Motion+ access or real application state.",
        "No complete dependency/vulnerability audit, authenticated data access, server authorization, retention or production security certification."
      ]
    },
    "practicalCaveats": [
      "Choose interruption and teardown behavior before adding springs or scroll-linked effects.",
      "Test reduced motion with the exact API and framework adapter you ship; the JavaScript fixture does not certify another integration."
    ],
    "limits": [
      "Only the pinned global browser bundle, numeric interpolation, opacity cancellation and a short pause/motion-preference probe.",
      "No React/Vue mount cycle, scroll-linked effects, touch gestures, frame-rate profiling, Motion+ access or real application state."
    ],
    "sources": [
      {
        "label": "JavaScript quick start",
        "url": "https://motion.dev/docs/quick-start"
      },
      {
        "label": "Animation controls",
        "url": "https://motion.dev/docs/animate"
      },
      {
        "label": "Dated repository snapshot source",
        "url": "https://github.com/motiondivision/motion"
      },
      {
        "label": "Exact evaluated package archive",
        "url": "https://registry.npmjs.org/motion/-/motion-14.4.0.tgz"
      }
    ]
  }
}
