Quality checks
| Group | Domains |
|---|---|
| Story | NAR brief and narrative · TIM rhythm and timing · LIF life and density · ART art direction |
| Motion | MOT easing and choreography · TXT on-screen text · SAF motion safety · WEB animated web pages |
| Sound | AUD audio · CAP captions |
| Delivery | REN render and encoding · LIC licences and rights |
Every rule and check is detailed in docs/en/REFERENTIAL.md.
29 of the 64 checks are measured in code, without an agent (which ones apply depends on the profile):
- output length and format;
- cuts made on motion, never between two parked shots;
- frozen frames, dead air and total near-still time (under 1 s per 30 s, end card excluded);
- sounds landing on their picture, when the storyboard lists sound cues (
umd sync); - black frames;
- flashes, as a full-frame approximation of WCAG 2.3.1;
- loudness and true peak;
- silences and abrupt audio cuts;
- render reproducibility, and how faithful the delivered encode is to the master (VMAF);
- caption coverage, sync and reading speed;
- for pages: smoothness, CLS and
prefers-reduced-motion; - in the code: hard-coded durations, AI motion tells, remote fonts and assets, hollow wording;
- asset inventory and licences.
The other checks are judged by the auditors, from the contact sheet and a few targeted frames.
Scoring
- Each check is a blocker (5 points), major (3) or minor (1). Passed = all points, partial = half, failed or not checked = none.
- A failed blocker caps its domain at 3/10 and the overall score at 5.9/10. Examples:
- a dangerous flash;
- text too short to read;
- a render that is not reproducible;
- stills not validated before animation;
- a non-commercial asset in an ad.
- The overall score weights the domains by profile:
promo,presentation,explainer,social,film,logoorweb. Domains that do not apply are ignored, such as captions for a logo or audio for a web page. - Thresholds can be tuned per project in the
thresholdsof.motion/project.json: −14 LUFS, 3 flashes per second, 3 s of dead air, VMAF 93… The dead-air, frozen-picture, near-still, cuts-on-motion, flash and loudness thresholds were checked with zero false alarm on 15 reference films scored 7 to 8 by an AI jury (docs/CALIBRATION.md). A rule that would have wrongly flagged 7 of these films (music dynamics) was dropped. The VMAF, caption and web ones remain conventions.
The full referential
Profiles and weights
| NAR | TIM | LIF | ART | MOT | TXT | SAF | WEB | AUD | CAP | REN | LIC | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
promo Promo or product launch | 3 | 3 | 2 | 3 | 3 | 3 | 2 | · | 2 | 2 | 3 | 3 |
presentation Presentation video (company, product, project) | 3 | 2 | 1 | 3 | 2 | 3 | 2 | · | 3 | 3 | 2 | 3 |
explainer Explainer or educational video | 3 | 2 | 1 | 2 | 2 | 3 | 2 | · | 3 | 3 | 2 | 2 |
social Vertical short for social media | 3 | 3 | 2 | 2 | 2 | 3 | 2 | · | 2 | 3 | 2 | 2 |
film Narrative animated short | 3 | 3 | 3 | 3 | 2 | 1 | 2 | · | 3 | 1 | 2 | 2 |
logo Logo animation or ident (2 to 8 s) | 1 | 2 | 1 | 3 | 3 | 1 | 2 | · | 1 | · | 3 | 2 |
web Animated web page or UI | 1 | 1 | 1 | 3 | 3 | 2 | 3 | 3 | · | · | · | 2 |
Default thresholds
loudness_lufs | -14 |
loudness_tolerance_lu | 1 |
true_peak_dbtp | -1 |
freeze_s | 1 |
hero_min_px | 170 |
dead_air_s | 3 |
motion_floor | 0.4 |
flashes_per_s | 3 |
flash_delta | 0.1 |
duration_tolerance | 0.1 |
vmaf_min | 93 |
caption_offset_ms | 100 |
caption_cps_max | 17 |
caption_coverage_min | 0.98 |
caption_lines_max | 2 |
text_min_s | 1.2 |
text_words_per_s | 3 |
web_smooth_frames_min | 0.95 |
web_cls_max | 0.1 |
hardcoded_motion_max | 3 |
ai_tells_max | 0 |
fonts_max | 2 |
black_frames_max_s | 0.1 |
silence_edge_max_s | 0.5 |
still_per_30s_max | 1 |
end_card_s | 2 |
sync_tolerance_ms | 45 |
NAR · Brief and narrative
One goal, one audience, a structure that holds and a script without AI phrasing.
Build rules
- Write the goal, the audience and the expected action in BRIEF.md before any shot.
- Structure: hook, development, payoff (or call to action). In film: the character wants something small, tries, something unexpected happens, it looks at the camera.
- Every storyboard beat has a duration and a single intent, written at the end of the line.
- Key information must be understood with the sound off: it is also on screen.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| NAR-01 | A written goal and audience, served by every scene | major | auditor | BRIEF.md states goal, audience and expected action; every beat in storyboard.md maps to it. |
| NAR-02 | Complete structure: hook, development, payoff | major | auditor | Contact sheet and storyboard: the hook lands within the first 2 seconds (promo, social), the end resolves (CTA, punchline or look at camera). |
| NAR-03 | Every beat has a duration and an intent | minor | automatic | umd lint: storyboard.beats_missing_duration and beats_missing_intent are 0. |
| NAR-04 | Understandable with the sound off | major | auditor | Contact sheet without audio: the main message and the call to action are readable on screen. |
| NAR-05 | Script, on-screen text and voice-over without AI phrasing | minor | automatic | umd lint: slop.count is 0 in BRIEF.md, storyboard.md, the script and captions. |
TIM · Rhythm and timing
No dead air, regular events, a duration that fits the format.
Build rules
- Something new happens about every 2 seconds; never more than 3 seconds without meaningful motion.
- Target duration set in the brief (social 15–60 s, promo 30–90 s, logo 2–8 s) and met within ±10%.
- Key shots hold long enough to be read; no shot under 0.5 s unless a deliberate rapid montage.
- With music: cut on the beats.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| TIM-01 | No dead air longer than 3 s | major | automatic | umd analyze: dead_air has no segment longer than thresholds.dead_air_s (except intended holds noted in the storyboard). |
| TIM-02 | Something new about every 2 s | major | auditor | umd analyze motion timeline and contact sheet: regular peaks, no long flat stretch. |
| TIM-03 | Cuts and accents land on the music | minor | auditor | Compare scenes (umd analyze) with beats (beat_this or librosa if installed, otherwise listening): 2 frames apart at most. |
| TIM-04 | Duration matches the brief and the platform | major | automatic | umd analyze: probe.duration within ±thresholds.duration_tolerance of project.json duration_s. |
| TIM-05 | Shots long enough to be read | minor | auditor | umd analyze scenes: no shot under 0.5 s outside a deliberate montage; text shots long enough (see TXT-01). |
| TIM-06 | Cuts land on motion, never between two parked shots | major | automatic | umd analyze: seams.parked = 0 (mean motion below motion_floor in the 0.25 s before AND after a cut). |
LIF · Life and density
Nothing is fully frozen, scenes vary, motions overlap.
Build rules
- Nothing is ever fully still, even on the last shot: breathing, blinking, living light or particles.
- Vary framing, composition and rhythm from scene to scene; never the same layout twice.
- Characters: eyes react 6 to 10 frames before the body.
- Offset elements (stagger, overlapping action): they never all move at once.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| LIF-01 | No frozen picture over 1 s, last shot included | major | automatic | umd analyze: freezes has no segment longer than thresholds.freeze_s. |
| LIF-02 | Visual variety between scenes | major | auditor | Contact sheet: no two scenes with the same composition, framing and entrance. |
| LIF-03 | Eyes lead the body, breathing and blinks | minor | auditor | Frames around a reaction (umd frames --at): gaze 6 to 10 frames before the body; blinks present. |
| LIF-04 | Offset motions, no mechanical unison | minor | auditor | Code (stagger, delays) and successive frames: elements of a group start and end at different times. |
| LIF-05 | Under 1 s of near-still picture per 30 s, end card excluded | major | automatic | umd analyze: stillness.per_30s ≤ thresholds.still_per_30s_max (0.5 s buckets below motion_floor, the last end_card_s seconds excluded). |
ART · Art direction
A look validated on stills before animating, faithful to the brief, without an AI signature.
Build rules
- Render key stills (umd still) and compare them with the reference before animating; correct for up to three rounds.
- Colours and type come from the brief and motion-tokens.json; at most two font families.
- No default purple gradient, glass everywhere, emoji as icons, generic 3D blobs or centred template layouts.
- Respect the format's safe areas (title-safe 90%, platform UI zones in 9:16).
- Logos and icons as vectors; no blurry upscaled asset.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| ART-01 | Key stills validated before animation | blocker | automatic | umd lint: stills.count ≥ 1 per scene in .motion/stills/ and storyboard.md has a dated "Stills validated" line. |
| ART-02 | Palette and type from the brief respected | major | auditor | umd lint (fonts.families ≤ thresholds.fonts_max, colours outside tokens) and frames: consistent with BRIEF.md. |
| ART-03 | No AI-signature visuals | major | auditor | Contact sheet against the list in references/craft/anti-slop.md. |
| ART-04 | Format safe areas respected | minor | auditor | Key frames: text and logo inside title-safe (90%) and outside the platform's UI zones (9:16). |
| ART-05 | Assets sharp at output resolution | major | auditor | Frames at 100%: logos, icons and photos sharp, no pixelation or upscale blur. |
| ART-06 | One idea, a hook and a hero moment at the target level | major | auditor | Jury (agents/critic.md): concept_wow ≥ quality_target from project.json (default 8). A hook readable before 2 s, one identifiable hero moment (time), a satisfying end frame. Cite the times. |
| ART-07 | Typography finished to the target level | major | auditor | Jury: design_typography ≥ quality_target. Tight tracking on large display, line breaks by meaning, no widow, one emphasis device per line, the right font loaded (no fallback). Cite the frame. |
| ART-08 | Colour and finish at the target level | major | auditor | Jury: finish_texture ≥ quality_target. A palette per sequence that follows the story (colour script), motivated light, grain or dither against banding, no aliasing. Cite the frame. |
MOT · Easing and choreography
Consistent durations and curves, a purpose for every motion, no AI motion tells.
Build rules
- Durations and curves only from .motion/motion-tokens.json; no hard-coded values in components.
- Every motion has a role: guide the eye, explain a change, give feedback, link two ideas.
- Entrances ease-out, exits ease-in, on-screen moves ease-in-out; never linear on a spatial move.
- One focal motion at a time; the others follow, offset.
- Ban AI tells: pulsing dots, blur on every entrance, bouncy springs everywhere, everything fading up 20 px, infinite floating.
- On the web, animate only transform and opacity; never transition: all.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| MOT-01 | Durations and curves come from motion tokens | major | automatic | umd lint: hardcoded_motion.count ≤ thresholds.hardcoded_motion_max outside the token file. |
| MOT-02 | No AI motion tells | major | auditor | umd lint (ai_tells) then successive frames: no infinite pulsing, systematic blur-in, springs everywhere or uniform fade-up. |
| MOT-03 | Every motion has a purpose | major | auditor | storyboard.md: every noted animation has a role; no purely decorative looping animation. |
| MOT-04 | Easing matches the physics of the motion | minor | auditor | umd lint (linear_moves) and code: entrances ease-out, exits ease-in, no linear on moves. |
| MOT-05 | One focal motion at a time | minor | auditor | Successive frames of a transition: one element leads, the others follow offset. |
| MOT-06 | Web: only transform and opacity, never transition: all | major | automatic | umd lint: layout_props.count and transition_all.count are 0. |
TXT · On-screen text
Long enough to read, contrasted, never clipped or overlapping.
Build rules
- Text display time: at least max(1.2 s, words ÷ 3 + 0.5 s).
- Contrast ≥ 4.5:1 (≥ 3:1 for large text); over moving backgrounds add a scrim or stroke.
- Minimum body text size: about 4% of frame height in video.
- No overlap or overflow; everything stays inside title-safe.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| TXT-01 | Every text stays on screen long enough to be read | blocker | automatic | umd lint: storyboard.text_too_short is 0 (rule max(text_min_s, words ÷ text_words_per_s + 0.5)), confirmed with umd frames. |
| TXT-02 | Text contrasted, even over moving backgrounds | major | auditor | Frames where text crosses a busy background: scrim, stroke or calm area; estimated contrast ≥ 4.5:1. |
| TXT-03 | No clipped, overlapping or out-of-zone text | major | auditor | Key frames of each card: full text, no overlap, inside title-safe. |
| TXT-04 | Text size large enough for the format | minor | auditor | Frame at 100%: body text height ≥ 4% of frame height (more in 9:16). |
SAF · Motion safety
No dangerous flashes, no nauseating motion without an alternative.
Build rules
- Never more than 3 flashes per second (WCAG 2.3.1), including white cuts and strobes.
- Limit fast zooms, spins and large parallax; on the web, turn them off with prefers-reduced-motion.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| SAF-01 | At most 3 flashes per second | blocker | automatic | umd analyze: flashes.max_per_s ≤ thresholds.flashes_per_s (full-frame measure, approximation of WCAG 2.3.1). |
| SAF-02 | No aggressive vestibular motion | minor | auditor | Successive frames: no fast, repeated full-screen zoom or spin, no long large parallax. |
WEB · Animated web pages
Smooth, stable, respectful of prefers-reduced-motion and native scrolling.
Build rules
- Every non-essential animation stops or shrinks with prefers-reduced-motion: reduce.
- Budget: 95% of frames on time on a 4× throttled CPU; animate transform and opacity.
- No animation shifts the layout (CLS < 0.1).
- No scroll-jacking: scrolling stays native, with keyboard and trackpad.
- Interactions: visible feedback within 100 ms, UI durations of 100 to 300 ms.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| WEB-01 | prefers-reduced-motion honoured | blocker | automatic | umd webperf: reduced_motion.respected is true (animations stopped or strongly reduced in reduce mode). |
| WEB-02 | Smooth animations, no dropped frames | major | automatic | umd webperf: smooth_ratio ≥ thresholds.web_smooth_frames_min with a 4× throttled CPU. |
| WEB-03 | No layout shift caused by animation | major | automatic | umd webperf: cls < thresholds.web_cls_max. |
| WEB-04 | Responsive, consistent interactions | major | auditor | Hover, focus, click: feedback within 100 ms, same durations and curves everywhere. |
| WEB-05 | No scroll-jacking, keyboard navigation intact | major | auditor | Scroll with wheel, keyboard (Space, arrows) and trackpad: native speed, sections reachable by focus. |
| WEB-06 | will-change used sparingly | minor | automatic | umd lint: will_change.count ≤ 5 permanent declarations. |
AUD · Audio
Compliant loudness, a clear voice, music ducking under the voice, sounds in sync.
Build rules
- Mix with umd mix (automatic ducking), then normalise with umd normalize (−14 LUFS, true peak ≤ −1 dBTP by default).
- Sound lands 0 to 1 frame after the image it underlines, never before.
- Fade in and out; no silence longer than 0.5 s at the start.
- Voice: humanised script, brand names pronounced correctly, 140 to 170 words per minute.
- Export 48 kHz stereo, AAC ≥ 192 kb/s (or Opus in WebM).
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| AUD-01 | Compliant loudness and true peak under the ceiling | blocker | automatic | umd analyze: loudness.integrated within ±thresholds.loudness_tolerance_lu of thresholds.loudness_lufs and loudness.true_peak ≤ thresholds.true_peak_dbtp. |
| AUD-02 | Music ducks under the voice | major | auditor | Mix command (umd mix or sidechaincompress) in render.json or the logs, and listening to a spoken passage: the voice clearly dominates. |
| AUD-03 | Sound effects in sync, 0 to 1 frame after the image | minor | auditor | With a "## Sound cues" section in the storyboard: umd sync measures each sound's attack against its event (±sync_tolerance_ms) and decides on its own. Without cues: watch the cuts and impacts; the sound lands 0 to 1 frame after the picture. |
| AUD-04 | No leading silence or abrupt cut | major | automatic | umd analyze: silence.leading_s and silence.trailing_s ≤ thresholds.silence_edge_max_s, and audio_end.abrupt is false. |
| AUD-05 | Clear, natural voice, names pronounced right | major | auditor | Listening and transcript: no robotic artefacts, 140–170 words/min, brand names correct. |
| AUD-06 | Delivery audio format | minor | automatic | umd analyze: probe.audio at 48 kHz, 2 channels, AAC ≥ 192 kb/s or Opus. |
| AUD-07 | Layered sound design at the target level | major | auditor | Jury: sound_sync ≥ quality_target. At hero moments several layers (riser, impact, sub, detail), the music carved under the voice, silence used as an accent at least once; each effect on its picture (umd sync). |
CAP · Captions
Every word present, on time, readable and spelled right.
Build rules
- Known script: forced alignment (ctc-forced-aligner). Otherwise: word timestamps (faster-whisper, WhisperX).
- Generate with umd captions, check with umd captions-check.
- Two lines at most, 17 characters per second at most, inside the safe area, never hiding the key visual.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| CAP-01 | Every word, in sync | blocker | automatic | umd captions-check: coverage ≥ thresholds.caption_coverage_min and max_offset_ms ≤ thresholds.caption_offset_ms. |
| CAP-02 | Readable, well-placed captions | major | auditor | Frames with captions: two lines at most, strong contrast, inside the safe area, not hiding the subject. |
| CAP-03 | Reasonable reading speed | minor | automatic | umd captions-check: max_cps ≤ thresholds.caption_cps_max and max_lines ≤ thresholds.caption_lines_max. |
| CAP-04 | Names and brands spelled exactly | minor | auditor | Compare the caption file with the script and BRIEF.md (proper names, brands, figures). |
REN · Render and encoding
A reproducible render, in the right format, with no visible loss or artefact.
Build rules
- Time is driven by the frame number (umd capture, useCurrentFrame, timeline.seek); never by the clock.
- Local fonts and assets (Fontsource): no network loading during render.
- High-quality master, then delivery encode H.264 High yuv420p, constant frame rate, faststart.
- Gradients: add grain or dithering against banding.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| REN-01 | Deterministic render: two identical renders | blocker | automatic | umd compare on two renders (umd render --twice): identical is true, or ssim ≥ 0.999 if the encoder adds noise. |
| REN-02 | Output format matches the brief | major | automatic | umd analyze: probe.width, height and fps equal the brief, constant frame rate, yuv420p for MP4. |
| REN-03 | Delivered encode faithful to the master | major | automatic | umd vmaf: vmaf ≥ thresholds.vmaf_min. |
| REN-04 | Local fonts and assets | major | automatic | umd lint: remote_assets.count is 0 (no Google Fonts, image or video CDN loaded at render). |
| REN-05 | No unintended black frames | minor | automatic | umd analyze: black has no segment longer than thresholds.black_frames_max_s outside planned fades; the first frame is not blank. |
| REN-06 | No artefacts: banding, aliasing, flicker | major | auditor | Frames at 100% on gradients, thin lines and moving text. |
LIC · Licences and rights
Every asset, model and dependency is allowed in the deliverable.
Build rules
- Record every asset in .motion/assets.lock.json with its source and licence as soon as it enters the project.
- Commercial deliverable: no non-commercial weights, no Tencent model in the EU, no embedded AGPL, no unlicensed asset.
- Remotion: free up to 3 employees, company licence above; declare it in project.json.
- Describe references in your own words; never have someone else's video copied.
| ID | Check | Severity | Method | How |
|---|---|---|---|---|
| LIC-01 | No asset, model or dependency forbidden for commercial use | blocker | automatic | umd licenses: violations is 0 for the project.json policy. |
| LIC-02 | Remotion licence fits the team | blocker | automatic | umd licenses: remotion.ok is true (project.json license_policy.remotion is individual, small-company, non-profit or company-license). |
| LIC-03 | Every asset is inventoried with its licence | major | automatic | umd licenses: unlisted_assets is 0 and every assets.lock.json entry has source and license. |
| LIC-04 | Required attributions present | minor | auditor | Assets marked attribution_required: credits in the video, the description or deliverables/credits.txt. |
| LIC-05 | No third-party trademark, likeness or work without rights | major | auditor | Contact sheet and assets: third-party logos, real faces, music and clips under rights are justified; references described, not copied. |