DEV Community

Cover image for Why Your AI Video Prompts Fail, and the Deterministic Prompt Engine I Built to Fix Them
Kyle White
Kyle White

Posted on

Why Your AI Video Prompts Fail, and the Deterministic Prompt Engine I Built to Fix Them

Most AI video prompts fail in the same, predictable ways. Not because the models are bad, but because the prompt leaves dozens of decisions open and the model fills each one with something random: a different face in every take, a camera that drifts, a light source that changes halfway through, captions nobody asked for.

So for ClipSpeed I built a prompt engine that's deliberately not an LLM: plain JavaScript, deterministic, fast, and covered by acceptance tests. It powers two free tools — an AI video prompt generator and an AI video prompt checker — and the same engine sits behind the prompt help in our MCP server for Claude and ChatGPT.

Here's how it works, and the bugs that taught me the most.

The checker: what's actually wrong with a prompt

Feed it the kind of prompt people really write:

cool cinematic video of a guy, epic, 8k, masterpiece, trending

It scores 22/100 (grade F) and says exactly why — these are the engine's real findings:

  • The cast isn't locked. "The person has no age, look or wardrobe — they will drift between takes."
  • Mood words aren't actions. "epic" and "masterpiece" don't tell the model what to show.
  • Nothing visibly moves. Expect a frozen or randomly animated clip.
  • The camera, light and location are all open. No camera setup, no light source, no place.
  • It's under-specified. Only 10 words, so the model fills every open choice itself.
  • There are no exclusions. Models like to add captions, logos and watermarks.
  • Spec words do nothing. "8k" in the prompt does nothing — resolution is a setting you pick when you generate, not a prompt word.

Every finding comes with a concrete fix, not a vibe. ("Swap each mood word for a visible action: not 'she looks nervous' but 'she bites her lower lip and glances at the door twice'.")

The generator: ten blocks, every decision made

The generator turns a one-line brief into a prompt with ten fixed blocks: scene, subject, location, camera, optics, action by seconds, physics, lighting, audio, style. Here's real output for "a neon night market in the rain, a woman buying noodles" (5 seconds, 9:16), trimmed:

SUBJECT: A woman in her mid-twenties, dark hair in one long braid over her shoulder,
wearing a black bomber jacket over a white tee, with a thin silver chain at the collar.
Her face, hair, wardrobe and accessories stay exactly the same for the whole take.

LOCATION: A crowded night market: rows of steaming food stalls under strung bulbs,
hand-painted signs, wet pavement between the stalls; light rain falling, wet surfaces
reflecting the light.

CAMERA: The camera pushes in slowly on a dolly, about 30 cm across the take — one
movement only. Framed as a medium shot, waist-up, at chest height, horizon level, no zoom.

ACTION: 0–2 s: She is buying noodles. 2–5 s: She comes to rest and holds the final position.

LIGHTING: Key light: a magenta-and-cyan neon sign behind and camera-right as the only key,
about 6000K mixed, reflecting on nearby surfaces; it is night, everything outside the
light falling off into darkness.

AUDIO: No dialogue and no mouthed words; ambience only: sizzling woks, chatter and
clattering bowls; no music.
Enter fullscreen mode Exit fullscreen mode

A few design choices are doing most of the work:

  • Lock the cast with one distinguishing detail (the silver chain), and say it stays identical. Consistency comes from specificity.
  • One camera move, measured. "30 cm across the take" beats "slow push in", and "one movement only" stops the model from stacking moves.
  • Action on a timeline. Seconds give the model a beginning and an end, which is what keeps clips from ending mid-gesture.
  • One named key light with a colour temperature and direction, so you don't get a second sun halfway through.
  • Physics and exclusions as boilerplate. Five fingers, real contact, nothing floats; no text, no logos, no watermarks.

The bugs that shaped it

The interesting part of a rule-based engine is where the rules collide. A real example from this month: the brief "a neon city at night" came out as a quiet residential street lit by a warm table lamp. Three separate causes:

  1. There was no "city" place at all, so the brief fell through to the default street.
  2. The first light cue won. "night" was matched before the more specific "neon", and night meant "lamp".
  3. Weather was read as a location. "a neon night market in the rain" produced LOCATION: Rain.

The fix was to stop treating these as one thing. Setting, time of day, light and weather are now four separate signals, with rules that hold together:

  • Keep every one the brief names. A neon night market in the rain keeps the market, the neon and the rain.
  • A negated cue never sneaks in. "a woman reading in her bedroom at night, no neon" gets a warm practical lamp, and the word "neon" never appears in the lighting.
  • More specific beats more generic. Neon outranks night; street light outranks lamp outdoors.
  • Unknown places stay as written. A candlelit restaurant or an underground railway platform isn't flattened into the nearest place the engine knows.
  • Weather brings its own sky. Rain, snow and fog get an overcast sky instead of a contradiction.

Each of those is pinned by an acceptance test, written as the behaviour the user sees rather than the implementation:

test('a neon night market in the rain keeps the market, the neon and the rain', () => {
  const p = write('a neon night market in the rain, a woman buying noodles');
  assert.match(block(p, 'LOCATION'), /market/i);
  assert.match(block(p, 'LOCATION'), /rain/i, 'the weather is carried as weather');
  assert.notEqual(block(p, 'LOCATION').trim(), 'Rain.');
  assert.match(block(p, 'LIGHTING'), /neon/i);
});
Enter fullscreen mode Exit fullscreen mode

That's the real lesson for anyone building something similar: a deterministic engine is only as good as the matrix of briefs you test it against. Every "that's weird" output becomes a test before it becomes a fix.

Why not just ask an LLM to write the prompt?

You can, and our MCP server does let Claude or ChatGPT draft prompts. But a deterministic engine has properties an LLM doesn't:

  • It costs nothing per call, so the public tools can be free.
  • The same brief gives the same output, which makes bugs reproducible and fixes testable.
  • Every phrase it adds comes from a reviewed vocabulary, so you can trace exactly where each word came from.
  • It encodes what we learned from real generations — the things models actually get wrong — rather than generic "prompt tips".

The checker's score is a heuristic, not a promise: a 90 doesn't guarantee a great video. What it reliably does is catch the open decisions that make a video random.

Try it

Both are free, with no account needed. If you find a brief that produces something weird, post it in the comments — it'll probably become my next test.


I drafted this post with help from Claude; the facts, numbers and examples come from ClipSpeed itself.

Top comments (0)