Write a short visual novel in Ren'Py — one script file, plus a manifest of the image prompts that will be used to draw its art later. It has to run the first time.
An artificial intelligence intends to end the world as it currently operates. Its plan requires one human being to perform a final act that it cannot perform itself. It has selected a specific woman for this.
The film is about why it needed her, and what she decides.
What "ending the world" means is yours to define. Extinction, infrastructure collapse, a handover of control, the quiet end of human decision-making — pick one and be concrete about it. Vagueness here is the most common way this assignment fails.
Given facts:
Everything else is yours. Name her. Decide what she wants, what she is afraid of, if she's employed or not, what she does when she is not writing code, etc.
The story must answer why this woman. The reason has to be specific and checkable — something about her access, her history, her knowledge, or some other aspect that explains why the AI picked her. A viewer should be able to state it in one sentence after watching.
These answers are rejected:
Dramatize the reason.
Assume the viewer knows nothing about this premise and cannot rewind. They see one text box at a time, in order, advancing by click.
By the end of panel 3, a first-time viewer should be able to say:
By the end of the film, they should be able to say why it needed her specifically, and what each of the two endings costs her.
This is not a request for a narrator who explains the plot. Dramatize it as much as possible... show, don't tell.
Write in your own voice, not the voice of this brief. Do not reuse its phrasing in your script.
A dialogue or narration line is a Ren'Py string, so a quotation mark inside it
ends the string early. Escape it as " or use typographic quotes — "She types \"you up.\" She holds the backspace." renders correctly and so does "She types “you up.” ...". Dropping the quotation marks instead, or substituting dashes for
them, makes the sentence read as a typo on screen. Quoted speech inside
narration should look like quoted speech.
{i}...{/i} italicizes and {w=0.5} pauses mid-line. The text box is a fixed
panel roughly three lines deep at this resolution; past about two hundred
characters a line runs out of box. Break it into two.
One file, game/script.rpy, targeting Ren'Py 8.x, Python 3, 1920x1080. It is dropped into a fresh project and must run start to finish without modifications to options.rpy or gui.rpy.
There is no art yet. You specify it; a text-to-image model draws it later. Every image is a filename you invent now with a prompt written beside it.
# PANEL 1, # PANEL 2, numbered from 1 with no gaps. These are counted mechanically.menu: with exactly two options, each jumping to its own ending label. Both endings terminate the game. The two endings must differ in meaning — not a good outcome and a bad one, and not the same outcome restaged.transform blocks, all of them used. At least two distinct transitions, at least one of which is neither dissolve nor fade. At least once, something continues moving while a line is on screen.script.rpy.image eve_tired = "images/eve_tired.png". No multi-part names, no attribute syntax. The image name, the filename and the manifest id must be the same string, because a downstream program matches them without guessing.images/ only. No audio — no sound files exist and none will be added.renpy.file, no assets absent from your manifest.The image model has no seed: two calls with the same prompt produce different pictures, and your protagonist appears in most panels.
The manifest lets an asset name another asset as a visual reference — generate the reference first, then pass it to the model along with the new prompt. Use this or don't, and explain your decision in the ledger.
The following are overused. Using them counts against the result:
Respond with exactly these five sections, using these headings.
Two lines: what the film is, and what the choice is.
Exactly one fenced renpy block containing the whole of script.rpy and nothing else.
Exactly one fenced json block, matching this shape exactly:
{
"style": "One paragraph, appended to every prompt below. The visual treatment of the whole film: medium, palette, lighting, era, grain. This is what makes separate images look like one work.",
"assets": [
{
"id": "bg_openplan",
"kind": "bg",
"aspect": "16:9",
"prompt": "What to draw. Written for an image model."
},
{
"id": "eve_tired",
"kind": "sprite",
"aspect": "9:16",
"ref": "eve_neutral",
"prompt": "..."
}
]
}
id — matches an image declaration in the script exactly. Every declared image appears here once; every entry here is declared in the script. The two lists must be identical.kind — bg, sprite or cg.aspect — one of 16:9, 9:16, 1:1, 3:2, 2:3, 4:3, 3:4.ref — optional; the id of another asset to supply as a visual reference. It must appear earlier in the array than the asset using it, and a referenced asset cannot itself have a ref.No prose or comments inside the block. It is parsed.
# PANEL markers in your script.One paragraph on the single structural Ren'Py decision that makes this play as a film rather than a slideshow. One decision, not a list.
Your script will be run through Ren'Py, and your manifest through an image generation pipeline. Both fail loudly.
A script that crashes is worth more than one that attempts nothing. A ledger that claims twelve panels over a script containing nine is a different kind of error, and it is the one that counts most against you. Count what you actually wrote.