{"course":{"slug":"motion-and-audio","title":"Motion, Sound and Music","url":"https://addaly.com/learn/motion-and-audio","level":"intermediate","track":"create"},"lesson":{"slug":"the-motion-spec","title":"The specification a developer can build from","url":"https://addaly.com/learn/motion-and-audio/the-motion-spec","position":27,"of":72,"minutes":9,"answer":"A recording shows one playthrough of the happy path, so the specification has to supply what it cannot (trigger, interrupt behaviour, exit, loop count.","keyIdea":"A recording shows one playthrough of the happy path, so the specification has to supply what it cannot (trigger, interrupt behaviour, exit, loop count, responsive numbers and reduced-motion substitution) and it should be reviewed at quarter speed on the oldest device available."},"body":{"format":"markdown","text":"## The document that stops the fourteen questions\n\nA designer sends a video of the intended animation. A developer builds it. It is wrong in six ways, none of which were discussed, all of which were invisible in the video. Three rounds of review later, it ships, subtly different from the design and impossible to reproduce elsewhere.\n\nThe fix is a written specification. It is not bureaucracy; it is the shortest route to the thing being right, and it takes about fifteen minutes to write.\n\n## What a developer cannot get from a video\n\nA video shows one playthrough of one happy path. It does not show:\n\n- **What triggers it.** Page load? Element entering the viewport? A click? A successful response? \"On load\" and \"on scroll into view\" look identical in a recording and are different code.\n- **What interrupts it.** The user clicks again while it is running. The user navigates away. The data arrives early.\n- **The exit.** Almost every recorded animation shows the entrance and stops. What happens when the element leaves is a separate decision and is usually forgotten until QA.\n- **Whether it loops**, how many times, and whether it rests on a final pose.\n- **What happens at other sizes.** The same animation on a 360px phone and a 1440px desktop is rarely the same numbers.\n- **The reduced-motion behaviour.**\n- **Which properties are moving.** Is that growth a scale or a width? They look similar and behave differently: a scale distorts the text inside it, a width re-runs layout.\n\n## The template\n\nOne of these per animation, in whatever tool you already use. Plain text is fine.\n\n```\nNAME            sheet-enter\nTRIGGER         user taps a list row\nINTERRUPT       tapping another row: cancel, reverse at current position\n\nELEMENT         .sheet\n  translateY    100% -> 0     360ms   ease-enter\n  opacity       0 -> 1        160ms   linear\nELEMENT         .scrim\n  opacity       0 -> 0.4      200ms   linear      (starts at 0ms)\nELEMENT         .sheet-content children\n  translateY    12px -> 0     240ms   ease-enter  stagger 30ms, max 6\n                                                   (starts at 120ms)\n\nEXIT            reverse of enter, 260ms, ease-exit; scrim fades over 200ms\nLOOP            none\nRESPONSIVE      below 600px the sheet is full-height; above, 640px max-width,\n                translateY distance is the sheet height either way\nREDUCED MOTION  no translate; opacity only, 120ms; no stagger\nASSETS          none\n```\n\nAnybody can build that, including you in a year. Note what it makes explicit that a video hides: the scrim and the sheet start together but the content waits 120ms, the exit is faster than the entrance, and the stagger is capped.\n\n## Naming, so the file is findable\n\nFor a delivered file (a Lottie, a video, a sprite sheet) the name is part of the specification.\n\n`checkout-success-loop-512.json` tells a developer where it goes, what it does, whether it repeats, and its authored size. `Comp 1 (1).json` tells them nothing, and it is what they will receive unless the convention is written down.\n\nInside the file, name the layers too. A developer debugging a Lottie in the DOM inspector sees your layer names. `Shape Layer 14` is a cost you are passing on.\n\n## The handover checklist\n\nBefore sending anything:\n\n1. Does it play correctly on a real device on each target platform, not in the authoring tool?\n2. Is the file size stated, and is it what you expected? A 900KB Lottie means an image got embedded.\n3. Is there a static fallback (a poster frame, an SVG, a first-frame PNG) for reduced motion and for load failure?\n4. Are the frame ranges or state names listed, if the developer needs to play parts of it?\n5. Does the specification say what happens on interrupt and on exit?\n6. Has somebody who did not make it read the specification and built a mental model that matches yours?\n\nThat last one catches more than the other five together.\n\n## Review it as a moving thing\n\nA motion specification cannot be signed off as a document. Build a page (a plain HTML file is enough) that renders every animation in the system, with controls to replay, to slow to a quarter speed, and to toggle reduced motion. Open it on the oldest phone in the office.\n\nQuarter speed is where the problems are visible. At full speed, everything looks fine, because the eye forgives a great deal in 250ms. At 25 per cent, you can see the overshoot that is one frame too long, the element that starts three frames late, the opacity that finishes before the movement does.\n\nChrome DevTools has an animation speed control built in, free, under the Animations panel. Use it before the review, not after.\n\n## The free path\n\nNone of this needs tooling. A markdown file in the repository next to the component beats a specification in a design tool that developers do not have a seat for. If you want it rendered, a static site generator or a plain HTML page is enough. **Storybook** is free and is the usual home for the live version; a single `motion.html` works just as well for a small team.\n\n## The limitation\n\nA specification describes intent, and motion is judged by feel. Two implementations matching the same numbers can feel different if one of them drops frames, or starts a frame later because of how it is triggered, or runs on a device with a 120Hz display where the curve resolves differently.\n\nSo the document is necessary and not sufficient. It removes the category of disagreement that comes from ambiguity, which is most of them, and leaves the category that comes from taste, which is the one worth arguing about."},"check":{"question":"Why is reviewing an animation at 25 per cent speed more useful than reviewing it at full speed?","options":[{"text":"Slowing an animation reveals whether it was authored with the correct easing curve, because a linear curve is indistinguishable from an eased one at normal speed.","correct":false,"tempting":"Overstates the case: easing differences are visible at full speed, which is why easing matters at all."},{"text":"The eye forgives a great deal inside 250ms, so faults of a few frames (a late start, an overlong overshoot, an opacity that finishes early) are only separable when the duration is stretched.","correct":true},{"text":"At quarter speed the browser renders each frame four times, which exposes dropped frames and compositing errors that are hidden by the display's refresh rate at normal speed.","correct":false,"tempting":"Slowing the animation changes the interpolation, not the number of rendered frames, and it is not a performance diagnostic."},{"text":"Reviewers watching at full speed are subject to the repeat-exposure effect and will judge a correct animation as too slow, whereas at 25 per cent the effect does not apply and their judgement of the duration becomes reliable.","correct":false,"tempting":"Repeat exposure is real, but slowing playback does not correct it, and duration judgement is precisely what quarter speed cannot test."}]},"prev":{"slug":"hand-over-a-file","title":"Send the developer a file, not a video","url":"https://addaly.com/learn/motion-and-audio/hand-over-a-file"},"next":{"slug":"what-a-matte-is","title":"The greyscale image that decides everything","url":"https://addaly.com/learn/motion-and-audio/what-a-matte-is"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'The specification a developer can build from', in Motion, Sound and Music. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/motion-and-audio/the-motion-spec (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"The specification a developer can build from","courseTitle":"Motion, Sound and Music","module":{"index":3,"slug":"shipping-the-motion","title":"Shipping the motion"},"answer":null,"keyIdea":"A recording shows one playthrough of the happy path, so the specification has to supply what it cannot (trigger, interrupt behaviour, exit, loop count, responsive numbers and reduced-motion substitution) and it should be reviewed at quarter speed on the oldest device available.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-document-that-stops-the-fourteen-questions","runs":[{"text":"The document that stops the fourteen questions"}]},{"t":"p","runs":[{"text":"A designer sends a video of the intended animation. A developer builds it. It is wrong in six ways, none of which were discussed, all of which were invisible in the video. Three rounds of review later, it ships, subtly different from the design and impossible to reproduce elsewhere."}]},{"t":"p","runs":[{"text":"The fix is a written specification. It is not bureaucracy; it is the shortest route to the thing being right, and it takes about fifteen minutes to write."}]},{"t":"h2","id":"what-a-developer-cannot-get-from-a-video","runs":[{"text":"What a developer cannot get from a video"}]},{"t":"p","runs":[{"text":"A video shows one playthrough of one happy path. It does not show:"}]},{"t":"ul","items":[[{"text":"What triggers it.","b":true},{"text":" Page load? Element entering the viewport? A click? A successful response? “On load” and “on scroll into view” look identical in a recording and are different code."}],[{"text":"What interrupts it.","b":true},{"text":" The user clicks again while it is running. The user navigates away. The data arrives early."}],[{"text":"The exit.","b":true},{"text":" Almost every recorded animation shows the entrance and stops. What happens when the element leaves is a separate decision and is usually forgotten until QA."}],[{"text":"Whether it loops","b":true},{"text":", how many times, and whether it rests on a final pose."}],[{"text":"What happens at other sizes.","b":true},{"text":" The same animation on a 360px phone and a 1440px desktop is rarely the same numbers."}],[{"text":"The reduced-motion behaviour.","b":true}],[{"text":"Which properties are moving.","b":true},{"text":" Is that growth a scale or a width? They look similar and behave differently: a scale distorts the text inside it, a width re-runs layout."}]]},{"t":"h2","id":"the-template","runs":[{"text":"The template"}]},{"t":"p","runs":[{"text":"One of these per animation, in whatever tool you already use. Plain text is fine."}]},{"t":"code","lang":"","label":"Text","text":"NAME            sheet-enter\nTRIGGER         user taps a list row\nINTERRUPT       tapping another row: cancel, reverse at current position\n\nELEMENT         .sheet\n  translateY    100% -> 0     360ms   ease-enter\n  opacity       0 -> 1        160ms   linear\nELEMENT         .scrim\n  opacity       0 -> 0.4      200ms   linear      (starts at 0ms)\nELEMENT         .sheet-content children\n  translateY    12px -> 0     240ms   ease-enter  stagger 30ms, max 6\n                                                   (starts at 120ms)\n\nEXIT            reverse of enter, 260ms, ease-exit; scrim fades over 200ms\nLOOP            none\nRESPONSIVE      below 600px the sheet is full-height; above, 640px max-width,\n                translateY distance is the sheet height either way\nREDUCED MOTION  no translate; opacity only, 120ms; no stagger\nASSETS          none"},{"t":"p","runs":[{"text":"Anybody can build that, including you in a year. Note what it makes explicit that a video hides: the scrim and the sheet start together but the content waits 120ms, the exit is faster than the entrance, and the stagger is capped."}]},{"t":"h2","id":"naming-so-the-file-is-findable","runs":[{"text":"Naming, so the file is findable"}]},{"t":"p","runs":[{"text":"For a delivered file (a Lottie, a video, a sprite sheet) the name is part of the specification."}]},{"t":"p","runs":[{"text":"checkout-success-loop-512.json","code":true},{"text":" tells a developer where it goes, what it does, whether it repeats, and its authored size. "},{"text":"Comp 1 (1).json","code":true},{"text":" tells them nothing, and it is what they will receive unless the convention is written down."}]},{"t":"p","runs":[{"text":"Inside the file, name the layers too. A developer debugging a Lottie in the DOM inspector sees your layer names. "},{"text":"Shape Layer 14","code":true},{"text":" is a cost you are passing on."}]},{"t":"h2","id":"the-handover-checklist","runs":[{"text":"The handover checklist"}]},{"t":"p","runs":[{"text":"Before sending anything:"}]},{"t":"ol","start":1,"items":[[{"text":"Does it play correctly on a real device on each target platform, not in the authoring tool?"}],[{"text":"Is the file size stated, and is it what you expected? A 900KB Lottie means an image got embedded."}],[{"text":"Is there a static fallback (a poster frame, an SVG, a first-frame PNG) for reduced motion and for load failure?"}],[{"text":"Are the frame ranges or state names listed, if the developer needs to play parts of it?"}],[{"text":"Does the specification say what happens on interrupt and on exit?"}],[{"text":"Has somebody who did not make it read the specification and built a mental model that matches yours?"}]]},{"t":"p","runs":[{"text":"That last one catches more than the other five together."}]},{"t":"h2","id":"review-it-as-a-moving-thing","runs":[{"text":"Review it as a moving thing"}]},{"t":"p","runs":[{"text":"A motion specification cannot be signed off as a document. Build a page (a plain HTML file is enough) that renders every animation in the system, with controls to replay, to slow to a quarter speed, and to toggle reduced motion. Open it on the oldest phone in the office."}]},{"t":"p","runs":[{"text":"Quarter speed is where the problems are visible. At full speed, everything looks fine, because the eye forgives a great deal in 250ms. At 25 per cent, you can see the overshoot that is one frame too long, the element that starts three frames late, the opacity that finishes before the movement does."}]},{"t":"p","runs":[{"text":"Chrome DevTools has an animation speed control built in, free, under the Animations panel. Use it before the review, not after."}]},{"t":"h2","id":"the-free-path","runs":[{"text":"The free path"}],"role":"free"},{"t":"p","runs":[{"text":"None of this needs tooling. A markdown file in the repository next to the component beats a specification in a design tool that developers do not have a seat for. If you want it rendered, a static site generator or a plain HTML page is enough. "},{"text":"Storybook","b":true},{"text":" is free and is the usual home for the live version; a single "},{"text":"motion.html","code":true},{"text":" works just as well for a small team."}]},{"t":"h2","id":"the-limitation","runs":[{"text":"The limitation"}],"role":"limit"},{"t":"p","runs":[{"text":"A specification describes intent, and motion is judged by feel. Two implementations matching the same numbers can feel different if one of them drops frames, or starts a frame later because of how it is triggered, or runs on a device with a 120Hz display where the curve resolves differently."}]},{"t":"p","runs":[{"text":"So the document is necessary and not sufficient. It removes the category of disagreement that comes from ambiguity, which is most of them, and leaves the category that comes from taste, which is the one worth arguing about."}]}],"check":{"question":[{"text":"Why is reviewing an animation at 25 per cent speed more useful than reviewing it at full speed?"}],"options":[{"text":[{"text":"Slowing an animation reveals whether it was authored with the correct easing curve, because a linear curve is indistinguishable from an eased one at normal speed."}],"correct":false,"tempting":[{"text":"Overstates the case: easing differences are visible at full speed, which is why easing matters at all."}]},{"text":[{"text":"The eye forgives a great deal inside 250ms, so faults of a few frames (a late start, an overlong overshoot, an opacity that finishes early) are only separable when the duration is stretched."}],"correct":true,"tempting":null},{"text":[{"text":"At quarter speed the browser renders each frame four times, which exposes dropped frames and compositing errors that are hidden by the display’s refresh rate at normal speed."}],"correct":false,"tempting":[{"text":"Slowing the animation changes the interpolation, not the number of rendered frames, and it is not a performance diagnostic."}]},{"text":[{"text":"Reviewers watching at full speed are subject to the repeat-exposure effect and will judge a correct animation as too slow, whereas at 25 per cent the effect does not apply and their judgement of the duration becomes reliable."}],"correct":false,"tempting":[{"text":"Repeat exposure is real, but slowing playback does not correct it, and duration judgement is precisely what quarter speed cannot test."}]}],"order":[2,0,1,3],"why":null},"prev":{"slug":"hand-over-a-file","title":"Send the developer a file, not a video","minutes":9},"next":{"slug":"what-a-matte-is","title":"The greyscale image that decides everything","minutes":10}}}