Rule handbook metadata
- Rule
DET.MOTION.NO_AUTO_PLAY_FLASH· lanedeterministic- Page status
- current
- page_version
f6716461755c5906686a586535661bb7dc3d022d186faaf718efbf89ed7070d3- generated_at
- 2026-05-25T14:30:00.000Z
- registry_fingerprint
2ce40848effce579d3e4879f6ca85535183a14db201870a6c007da424624550c
How this rule is fixed
Pilot deterministic fixer: handbook_after · harness mode standalone · verify expect_rule_clean.
- Harness:
apply-harness-fixture-remediation.pycopies the After example HTML from this handbook page onto the defect fixture, theninvoke-det-ruleset-remediation-verify.shre-audits and expects zero findings for this rule. - Production sites:
run-website-ux-remediation-loop.shrunshandbook_html_patch(HTML patches inlib/ux-deterministic-fixers/fixers/patches/) before invoking the Cursor agent when the quality gate still fails.
Detection module: docs/design/ux-audit/deterministic-design-rules.md#det-motion-no_auto_play_flash. Scroll down for Before / After examples and Evidence and remediation steps.
Purpose
Photosensitive visitors and readers under cognitive load need pages that do not auto-play strobing motion. Kitchen Sink ships always-on motion primitives in Ksc (css/forge-theme.css: .pulse, .pulse-amber, .breathe-link, .breathe-static), ambient loops, living backgrounds, and script-assembly fly-ins — most use slow cycles (≥2s) on box-shadow or outline, not rapid opacity toggles. This deterministic rule enforces the WCAG 2.3.1 general flash threshold: a simple on/off luminance cycle must not exceed three flashes per second (~0.67s minimum duration for an infinite opacity toggle).
The check module design-rules/deterministic/generated/det-motion-no-auto-play-flash.check.js scans visible DOM nodes and stylesheets in Playwright for:
- Fast infinite animations —
animation-iteration-count: infinitewith duration below the safe toggle cycle. - Risky animation/@keyframes names —
blink,flash,strobe,seizure, orflicker. - Autoplay video — visible
<video autoplay>that may include rapid luminance changes.
Plan: Inventory every visible infinite loop, custom @keyframes name, and autoplay video on first-screen URLs. Do: Keep decorative motion slow, rename risky keyframes, gate fast loops behind user intent, and provide static fallbacks under prefers-reduced-motion. Check: Run the auditor metrics phase or auditor-tests/invoke-det-ruleset-harness.sh --only-rule DET.MOTION.NO_AUTO_PLAY_FLASH. Adjust: When a product surface needs attention without strobing, use KS .pulse / hover .breathe-* (≥2s) or one-shot entrances — not sub-second opacity blinks.
Passing signals
- No risky names on running animations or
@keyframesrules (pulse-glow,breathe-cyan,forge-theme-auroraare fine;blink,flash-strobe,ks-flicker-borderare not). - Infinite loops on visible elements use duration ≥ ~0.67s for simple on/off cycles, or use slow KS defaults (
.pulse/.pulse-amberat 3s,.breathe-*at 2.2–2.5s on hover). - Opacity or luminance changes stay gradual (ease-in-out, box-shadow/outline pulses) rather than hard 0↔1 toggles faster than 3 Hz.
- Autoplay video is absent, or muted decorative video is hidden/off-screen with
prefers-reduced-motion: reducepausing playback and a static poster fallback. @media (prefers-reduced-motion: reduce)disables non-essential infinite animation (pairs withDET.MOTION.PREFERS_REDUCED).- Decorative motion stays on small accents (stat tile, badge) — not full-viewport strobing backgrounds behind body copy.
Failing signals
- Custom
@keyframes blink/flash/strobeapplied withanimation: … 0.2s infinite(or any duration < 0.67s with infinite iteration) on visible text, cards, or hero bands. - Animation names containing
blink,flash,strobe,seizure, orflickereven when duration looks slow — the name signals intent the check flags. - Multiple fast infinite loops in the same viewport (status badge + alert banner + background mesh all strobing).
- Autoplay video visible without user gesture (
<video autoplay>on hero or ambient layer), especially when unmuted. - Inline
<style>blocks in handbook/showcase pages that reintroduce seizure-risk patterns outside theme tokens. - Full-width
.glass/.forge-cardpanels with hard opacity oscillation that estimates > 3 flashes per second on a simple toggle model.
Before example
Before (failing example)
Sync in progress — strobing faster than three flashes per second.
Failing KS markup: custom blink keyframes at 0.2s infinite on a hero stat band, plus visible autoplay video.
After example
After (passing example)
Sync complete — static text; motion reserved for hover accents.
Slow 3s glow — below flash threshold.
Passing KS markup: slow theme pulse on an accent tile, static copy for status, no autoplay video, reduced-motion fallback.
Evidence and remediation
Evidence: Auditor metrics field motionNoAutoPlayFlashReport.violations[] with kinds:
| Kind | Meaning |
|---|---|
fast-infinite-animation |
Infinite loop duration below ~0.67s; estimatedFlashesPerSecond above 3 |
risky-animation-name |
Running animation-name matches blink/flash/strobe/seizure/flicker |
risky-keyframes-name |
Stylesheet @keyframes rule name matches risky keywords |
autoplay-video |
Visible <video autoplay> on the page |
Each finding includes selectorHint (tag, class, optional data-ks-hash), duration, estimated Hz, and page URL.
Remediate (in order):
- Remove or slow infinite animations — target ≥ 0.67s per cycle for on/off toggles; prefer KS
.pulse/.pulse-amber(3s) or hover-only.breathe-link/.breathe-static(≥2.2s). - Rename
@keyframesandanimation-namevalues — dropblink,flash,strobe,seizure,flickerfrom identifiers. - Delete autoplay on decorative video; require user play, or hide video under
prefers-reduced-motionwith a static poster image. - Add reduced-motion overrides (
animation: none !important) for any remaining decorative loops — seeDET.MOTION.PREFERS_REDUCED. - Re-run
analyze-website-ux.mjsmetrics on affected URLs; pair withAI.MOTION.INTENTIONALITYwhen motion volume still feels distracting but passes frequency gates.
Harness verification:
python3 generator/build_rule_defect_fixtures.py
auditor-tests/invoke-det-ruleset-harness.sh --only-rule DET.MOTION.NO_AUTO_PLAY_FLASH