How do you format a VN script?

Engines want labeled dialogue, not prose. Enter script text to get formatted output for RenPy and TyranoBuilder.

Format a visual novel script by labeling every spoken line with its speaker, keeping stage directions on separate cue lines, then converting dialogue into engine tags. This tool parses NAME colon lines, emits RenPy quoted dialogue and Tyrano character tags, counts converted lines, and flags unlabeled lines for repair.

Convert the script

Fill in the fields and run it. Everything is calculated in your browser — nothing is uploaded, and there is no signup.

Worked examples

Real results from the calculator above, shown in full so you can check the method against your own numbers.

Three-line platform scene — both engines

Two labeled lines convert cleanly and one bare narration line is flagged for a label.

1 of 3 lines need a speaker label before import

2 lines convert cleanly and 1 unlabeled lines fall back to NARRATOR, which keeps counts moving but assigns voices that may be wrong. Label each flagged line with its true speaker before copying output into an engine. This is a planning transform of the text entered, not an engine import check.

Total lines
3
Non-empty lines parsed
Dialogue lines
3
2 labeled plus 1 flagged
Lines needing labels
1
Assigned to NARRATOR
Output formats
2
RenPy plus Tyrano

Before and after the conversion

  • Lines in (pasted text)Every non-empty line counted once3
  • Labeled dialogue linesSPEAKER colon lines that convert directly2
  • Cue and direction linesComments in RenPy, semicolon lines in Tyrano0
  • Unlabeled lines assigned to NARRATORConverted with a fallback voice — verify each one1
  • RenPy output linesLabel header plus one line per beat4
  • Tyrano output linesOne tagged line per beat3
Dialogue lines converted3
Parsed lines — speaker, text and conversion status
LineSpeakerTextStatus
1MIRAThe train is already leaving.dialogue
2KAIThen we run.dialogue
3NARRATORRain hits the platform glass.needs label

Ren'Py output (4 lines): label scene_1: / mira "The train is already leaving." / kai "Then we run." / "Rain hits the platform glass."

Tyrano output (3 lines): [chara name="MIRA"]The train is already leaving.[p] / [chara name="KAI"]Then we run.[p] / [chara name="NARRATOR"]Rain hits the platform glass.[p]

How to finish the format

  • Fix the 1 flagged lines first: open the parsed-lines table, find each needs-label row, and type the true speaker name with a colon.
  • Change the default speaker only as a temporary safety net — a fallback voice of NARRATOR keeps counts moving but hides casting mistakes.
  • Copy the engine output only after flagged lines reach zero, so no line ships under the wrong character tag.

Cue-heavy rooftop scene — RenPy only

Directions route to comments while four dialogue lines become quoted RenPy lines.

5 lines parsed — 4 dialogue lines ready to convert

All 5 lines carry speaker labels or clean cue marks, so 4 dialogue lines convert directly into RenPy quoted lines and Tyrano character tags with nothing left flagged. This is a planning transform of the text entered, not an engine import check.

Total lines
5
Non-empty lines parsed
Dialogue lines
4
4 labeled plus 0 flagged
Lines needing labels
0
Assigned to NARRATOR
Output formats
1
RenPy only

Before and after the conversion

  • Lines in (pasted text)Every non-empty line counted once5
  • Labeled dialogue linesSPEAKER colon lines that convert directly4
  • Cue and direction linesComments in RenPy, semicolon lines in Tyrano1
  • Unlabeled lines assigned to NARRATORConverted with a fallback voice — verify each one0
  • RenPy output linesLabel header plus one line per beat6
  • Tyrano output linesTyrano output not selected0
Dialogue lines converted4
Parsed lines — speaker, text and conversion status
LineSpeakerTextStatus
1SCENErooftop, night winddialogue
2SORADo you hear that bell?dialogue
3NARRATOR[wind rises]cue
4RINI hear it every night now.dialogue
5SORAThen tonight we answer it.dialogue

Ren'Py output (6 lines): label scene_1: / scene "rooftop, night wind" / sora "Do you hear that bell?" / # [wind rises] / rin "I hear it every night now." / sora "Then tonight we answer it."

How to finish the format

  • Copy the Ren'Py output for the 4 dialogue lines into a test project and click through every beat before writing the next scene.
  • Add cue lines for each background, music, and sprite change now — engines stage a scene from cues, not from dialogue alone.

Unlabeled diary page — Tyrano only

Prose without labels falls back to the default speaker and every line is flagged.

Nothing parseable — every line needs a speaker label

All 3 lines arrived without a SPEAKER colon label or a cue mark, so zero dialogue lines can convert and all 3 lines are flagged for repair. Add a name and colon to each spoken line and keep directions on cue lines. This is a planning transform of the text entered, not an engine import check.

Total lines
3
Non-empty lines parsed
Dialogue lines
3
0 labeled plus 3 flagged
Lines needing labels
3
Assigned to NARRATOR
Output formats
1
Tyrano only

Before and after the conversion

  • Lines in (pasted text)Every non-empty line counted once3
  • Labeled dialogue linesSPEAKER colon lines that convert directly0
  • Cue and direction linesComments in RenPy, semicolon lines in Tyrano0
  • Unlabeled lines assigned to NARRATORConverted with a fallback voice — verify each one3
  • RenPy output linesRenPy output not selected0
  • Tyrano output linesOne tagged line per beat3
Dialogue lines converted3
Parsed lines — speaker, text and conversion status
LineSpeakerTextStatus
1NARRATORThe lighthouse lamp turned again.needs label
2NARRATORShe counted the seconds between flashes.needs label
3NARRATORSomewhere below, a door closed softly.needs label

Tyrano output (3 lines): [chara name="NARRATOR"]The lighthouse lamp turned again.[p] / [chara name="NARRATOR"]She counted the seconds between flashes.[p] / [chara name="NARRATOR"]Somewhere below, a door closed softly.[p]

How to finish the format

  • Add a SPEAKER colon label to every spoken line — with 3 flagged lines, the fastest repair is assigning the true voice line by line from the table.
  • Move directions and sounds onto cue lines starting with a bracket, asterisk, or a word like SFX or BG, so the parser stops treating them as dialogue.

The direct answer: labeled dialogue converts, prose does not

A visual novel script is formatted when every spoken line starts with the speaker name and a colon, each direction sits on its own cue line, and the whole page uses one beat per line. Paste that structure into the converter and it builds engine-ready output: quoted dialogue lines under a scene label for RenPy, and character-tagged lines with page-break markers for TyranoBuilder. The tool also counts what it parsed, shows how many lines converted, and flags every unlabeled line so nothing ships under the wrong voice.

That answer matters because engines cannot read paragraphs. A novel paragraph holds narration, action, interior thought, and two speakers arguing, all inside one block of text. An engine needs the opposite: one voice per line, one instruction per line, every line tagged. Writers who paste prose directly into an engine spend their first week splitting paragraphs by hand. Writers who format first spend that week directing scenes.

Why engines reject prose formatting

RenPy reads a script file as instructions. A line with a character id followed by quoted words means one character speaks. A quoted line with no id means narration. A line starting with a hash mark means a comment the player never sees. Anything else is either a different instruction or an error. Prose paragraphs match none of those shapes, so the engine stops or misreads them.

TyranoBuilder works from tags instead of indentation. A character tag assigns the next spoken line to a named sprite. The spoken text follows, then a marker tells the engine to wait for a click before continuing. Direction lines use comment marks so staging notes never borrow a character voice. A paragraph with three voices and a door slamming in the middle cannot map onto that structure without being split first.

The converter exists to make that split visible before import. It reads pasted text line by line, sorts each line into labeled dialogue, cue, or flagged, and shows both engine shapes side by side. The writer sees exactly which lines convert and which need repair, while the text is still cheap to change.

How the parsing works, step by step

The transform runs in four passes over the pasted text. First it splits everything on line breaks and discards fully empty lines, so blank spacing never inflates the counts. Second it tests each remaining line against the speaker pattern: a name of letters, digits, spaces, apostrophes, or hyphens, followed by a colon, followed by spoken words. A line like MIRA followed by a colon and a sentence passes. A line with a name and colon but nothing after it is marked as needing a label, because an empty speech line is almost always a paste mistake.

Third, lines that fail the speaker pattern are tested against cue patterns. A line starting with an asterisk, hash, bracket, or parenthesis is treated as a direction. So is any line beginning with the words SFX, MUSIC, CG, BG, SCENE, or CUE, regardless of capitalization. These conventions are deliberately narrow: the tool would rather flag an ambiguous line than silently file a spoken sentence as a direction.

Fourth, every line that is neither labeled dialogue nor a cue becomes a flagged line. It keeps its full text, receives the default speaker chosen in the form, usually NARRATOR, and appears in the parsed-lines table with the status needs label. The engine output still includes it, using the fallback voice, but the metrics count it separately so the writer knows verification is owed.

How the two engine outputs are built

RenPy output starts with a scene label line, then one indented line per parsed beat. Labeled dialogue becomes a lowercase character id followed by the spoken words in double quotes, with any double quotes inside the speech converted to single quotes so the line never breaks. Narration and flagged lines become bare quoted lines with no id. Cue lines become hash comments. The header plus one line per beat means a five-line scene produces six RenPy lines, and the breakdown block reports both numbers so the writer can confirm the arithmetic.

Tyrano output uses one tagged line per beat with no header. Labeled dialogue becomes a character tag carrying the speaker name in capitals, then the spoken text, then a page-break marker. Cue lines become semicolon comments. Flagged lines convert like dialogue but keep the fallback speaker, which is why the tool insists they be relabeled before copying output anywhere permanent.

Selecting both formats doubles the preview without changing the parse. The line counts, the flagged lines, and the table stay identical; only the number of output previews changes. Writers comparing engines use the both setting once, then switch to a single target while drafting so the page stays focused.

Worked numbers: the default three-line sample

The default sample contains three pasted lines. Line one reads MIRA with a colon and a sentence about a train leaving. Line two reads KAI with a colon and a short reply about running. Line three is a bare sentence about rain on platform glass, with no speaker and no cue mark.

The parser counts three total lines. Two are labeled dialogue and convert directly. Zero are cues. One is flagged and assigned to NARRATOR. Dialogue lines therefore read as two, and the metric for lines needing labels reads as one. With both formats selected, RenPy output holds four lines, meaning one label header plus three beats, and Tyrano output holds three lines, one per beat.

The verdict for this sample is a warning, not a pass. Two of three lines converting sounds healthy, yet the single flagged line represents a third of the scene speaking in a fallback voice. The warning headline names the exact fraction so the writer feels the weight: one of three lines needs a speaker label before import. Repair means typing NARRATOR with a colon in front of the rain sentence if it is truly narration, or a character name if someone speaks it. After that edit the same text parses as three clean lines with zero flags.

Worked numbers: a six-line scene with cues

Consider a six-line rooftop scene: a SCENE cue naming the rooftop at night, a labeled SORA line asking about a bell, a bracketed wind direction, a labeled RIN reply, a second SORA line, and a MUSIC cue for a bell theme. The parser counts six total lines. Four are labeled dialogue. Two are cues. Zero are flagged.

Dialogue lines read as four. RenPy output holds seven lines: one header plus six beats, with the two cues rendered as hash comments. Tyrano output holds six lines, with cues as semicolon comments. The verdict is a pass, and the recommendations advise copying output into a test project and adding sprite-change cues next. This example shows the shape the tool rewards: roughly one cue for every two or three dialogue lines, zero fallbacks, every voice explicit.

Illustrative hypothetical example: the lighthouse diary

This first illustrative hypothetical example follows a writer converting a diary-style passage. She pastes three sentences of lyrical prose with no labels: a lamp turning, a woman counting flashes, a door closing below. The tool counts three total lines, zero labeled dialogue, zero cues, and three flagged lines, all assigned to NARRATOR.

The verdict is a fail, not a warning, because zero lines carry true labels: flagged lines convert mechanically with a fallback voice, but nothing in the scene has a verified speaker. The recommendations are blunt about the risk. Three fallback voices in a three-line scene means the entire passage speaks as narration, which may match the writer intent or may hide the fact that the third line is someone entering the room. The repair differs completely by intent. If the passage is memory narration, labeling each line NARRATOR with a colon clears the flags honestly. If the door line is a heard event followed by a spoken reaction that was never pasted, the scene needs a new line, not a label. The converter cannot know which is true. It can only show that three lines currently share one unverified voice, and force the decision before import.

The lesson generalizes. Prose-first writers often discover missing dialogue while formatting. A sentence like a door closed softly reads as narration until it is staged, then someone must react to it. Formatting exposes the absent reaction while adding it costs nothing.

Illustrative hypothetical example: the crowded argument

This second illustrative hypothetical example follows a writer staging a four-person argument. He pastes eight lines, all correctly labeled with four speaker names, plus zero cue lines. The parser counts eight total lines, eight labeled dialogue lines, zero cues, zero flags. Everything converts.

The verdict is still a warning, for a different reason: no cue lines separate the action in a scene of eight or more dialogue lines. The tool passes the conversion but warns that pacing and staging live only inside spoken lines. In an argument scene that warning is usually correct. Eight uninterrupted speeches with no beat, no movement, and no volume cue will play as talking heads even if the words are strong. The repair is adding two or three cue lines: a bracketed beat where someone stands, an SFX cue for a slammed cup, a MUSIC cue that cuts underneath the final line. The line count rises from eight to eleven, RenPy output grows correspondingly, and the scene gains a skeleton the director can stage.

Writers sometimes resent this warning because the formatting is technically perfect. The tool raises it anyway because long dialogue runs without cues are the most common staging failure in first visual novels. Labels tell the engine who speaks. Only cues tell it what anything looks like while they speak.

Edge cases the parser handles deliberately

Single-word interjections with labels convert normally. A line reading KAI with a colon and the word Go parses as dialogue for KAI. Very short lines are not penalized because visual novels legitimately speak in fragments.

Speaker names normalize to capitals internally, so Mira, MIRA, and mira with colons all assign to the same voice. Character ids for RenPy derive from the lowercased name with non-alphanumeric runs collapsed to single underscores, so a speaker named LADY GREY becomes a clean id without spaces. Names longer than twenty-four characters after the first letter fail the speaker pattern on purpose and fall to flagged status, because a thirty-character speaker label is almost always a pasted sentence with a colon in it rather than a name.

Colons inside spoken text do not confuse the parse because the pattern splits on the first colon only. A line reading RIN with a colon followed by words containing another colon keeps everything after the first colon as dialogue. Timestamps like 12 colon 30 inside speech survive for the same reason.

Quotation marks inside dialogue are converted to single quotes in RenPy output so the surrounding double quotes never terminate early. Tyrano output keeps original punctuation because its tag structure does not quote the speech. Neither engine output alters word order, capitalization of the spoken text, or trailing punctuation.

Lines that are only a speaker name with a colon and no speech parse as needing a label rather than as empty dialogue, because silent labeled lines crash pacing in both engines. The table shows the speaker with empty text, which reads oddly on purpose: it mirrors the hole in the scene.

Failure modes and what each one costs

The total-silence failure is an empty paste or whitespace only. Total lines read as zero, both outputs are empty, and the verdict is informational. Nothing is lost because nothing was entered. The repair is pasting the scene.

The all-prose failure is a full page with no labels and no cue marks. Every line flags, the voice fallback blankets the scene, and the verdict warns rather than fails, because flagged lines still convert mechanically. The cost of ignoring the warning is a scene where every line speaks as NARRATOR. In RenPy that renders as page after page of bare quoted narration with no sprites talking. In Tyrano it renders as one character tag repeated until the reader stops believing anyone is present. Repair is labeling each true speaker, which for a long scene is slow but straightforward.

The cues-only failure triggers the fail verdict. A paste of five direction lines and zero spoken lines has clean structure but nothing to perform. The cost is a scene that stages an empty room. Repair is adding the dialogue the directions describe.

The mixed-prose failure is the most expensive in practice: twenty labeled lines plus fifteen bare lines scattered through. Conversion looks mostly green, so writers ship it. The flagged fifteen speak as narration inside a voiced scene, which reads as a narrator interrupting conversations to describe things the sprites should show. Repair means reading the table row by row, which feels tedious at twenty-plus lines but takes less time than re-recording or re-timing a built scene later.

The mega-line failure is pasting a whole chapter as a handful of enormous lines instead of one beat per line. Counts look tiny, nothing flags, both outputs look clean, yet each engine line holds a paragraph with multiple speakers. The tool cannot detect this because each line technically carries one label. The defense is a writer habit: if any single table row shows truncated text with an ellipsis, open that line and check whether two voices share it. Splitting it before import saves the scene.

Naming, casting, and keeping the voice list small

Every distinct speaker label becomes a voice the project must cast, sprite, and direct. A script with fourteen speaker names needs fourteen character designs or a hard conversation about who can merge. The parsed-lines table doubles as a cast list: scanning the speaker column shows the full roster of the pasted passage. Writers who find minor characters with one line each can merge them into a single ensemble label before the art bill grows.

Consistency matters more than cleverness in speaker names. Using MIRA in one scene and MIR in the next creates two voices that never meet in the table unless both scenes are pasted together. Pick one spelling per character, write it the same way every time, and treat the speaker column as a spell-checker. The normalization to capitals forgives case drift but not spelling drift.

The default speaker deserves a deliberate choice. NARRATOR suits third-person or reflective passages. A protagonist name suits first-person stories where unlabeled lines are really interior monologue by the lead. Setting the fallback to the true majority voice reduces wrong-voice damage while flags remain, but it never replaces labeling. A fallback is a safety net with a hole count displayed beside it.

Cue vocabulary worth standardizing early

The parser recognizes a small cue vocabulary: SFX, MUSIC, CG, BG, SCENE, and CUE at the start of a line, plus bracket, asterisk, hash, and parenthesis marks. Standardizing a slightly wider personal vocabulary around those roots pays off across a whole project. SFX for discrete sounds, MUSIC for themes and cuts, BG for backgrounds, CG for special illustrations, SCENE for location headers, and bracketed lines for blocking and beats covers nearly every staging need in an early script.

Write each cue as its own line even when it shares a moment with dialogue. A line reading SFX thunder followed by a separate spoken line stages cleanly in both engines. A line mashing a thunder description and a speech into one labeled line stages as speech with a weather report inside it. One instruction per line is the entire discipline, and cues are where it shows most.

Music cues deserve verbs, not just titles. MUSIC bell theme starting reads differently from MUSIC bell theme, and the difference survives into production when the audio lead reads the script. The parser treats both as cues either way, so the extra verb costs nothing at conversion time and buys clarity later.

Pacing a scene for clicks and page breaks

Both engines advance on clicks or taps, and the converter output follows that rhythm: one parsed beat becomes one engine beat. A scene of thirty rapid one-line exchanges therefore means thirty clicks, which can feel either electric or exhausting depending on line length. Reading the converted line count before import gives the writer a click budget. If a quarrel runs forty beats, merging the shortest interjections pairwise cuts clicks without cutting voices.

Tyrano page-break markers deserve special attention. The converter appends one per dialogue beat, which is the safe default: every line waits for the reader. Writers who want multi-line pages that advance together can join beats after import, but starting from one-break-per-line keeps timing predictable during the first playtest. RenPy needs no equivalent marker because each quoted line already advances on click by default.

Narration density controls perceived speed more than dialogue count. Five narration beats between speeches slow a scene even when total lines look modest. When the metrics show flagged or narration lines outnumbering labeled dialogue, read the passage aloud and cut or voice the surplus before building.

From formatted lines to a testable build

Formatted output is not a finished scene. It is a clean draft the engines can load. The recommended sequence after conversion is copying the output into a fresh test project, clicking through every beat, and noting three things: voices that sound wrong, clicks that feel rushed or dead, and cues that lack art or audio. Those notes become the next edit pass in the writing document, not in the engine file. The writing document stays the source of truth; the engine file stays a disposable preview until the script locks.

Character declarations come next in RenPy: each lowercase id needs a definition line pairing it with a display name and color. The converter emits the id but not the declaration, because display names and colors are art decisions the tool cannot make. In Tyrano, each speaker name needs a matching sprite registration before expressions can change. Planning those registrations from the speaker column prevents the common stall where a formatted script waits weeks on missing art.

Save files and rollback behavior also deserve one playtest each. Long labeled arguments can trap rollback if every line advances state, and dense narration can flood the backlog. Neither problem is visible in converted text. Both appear within minutes of clicking through a real build.

FAQ-adjacent depth: questions writers ask next

Writers often ask whether to format in the writing app or in the engine. Format in the writing app. Engines are slow text editors with project files that punish large deletions. A plain document with one beat per line revises in seconds, pastes cleanly into the converter, and re-exports in one motion. Move text into the engine only for playtests, and keep editing at the source.

Another frequent question is how much of a script to convert at once. One scene at a time beats one chapter at a time. Scene-sized pastes keep the parsed table readable, keep flagged counts small enough to fix immediately, and keep each engine preview focused on one location and cast. Chapter-sized pastes produce tables of sixty rows where flags hide. The tool caps the displayed table at twelve rows for exactly this reason: if the scene needs more rows than fit comfortably, it is probably two scenes sharing a paste.

Writers also ask whether narration or dialogue should dominate. Playable visual novels lean heavily toward dialogue, often two voiced lines for every narration beat, because sprites on screen promise conversation. A metrics readout showing narration outnumbering dialogue two to one usually signals a novel chapter wearing a script costume. Converting some narration into spoken reactions, or into cue-driven staging with fewer words, restores the balance without cutting story.

A subtler question is whether two engines really need two formats from one source. They do when the project has not committed to an engine, and they do not once it has. Early in a project, generating both previews reveals which engine shapes the writing more naturally. Late in a project, generating only the shipping target removes a copy that could drift out of sync. The target selector exists to match that lifecycle: both while deciding, one while building.

Finally, writers ask how to handle two speakers in one pasted line. Split the line. Give each voice its own beat even when the exchange is fast. Engines cannot perform overlap from a single line without special instructions, and readers cannot attribute half a line at a glance. Two short beats always play better than one doubled line.

Where this work continues

Formatting is the doorway into full visual novel production, and the doorway leads somewhere specific. The Visual Novel studio at the /vn address, reached through the book-to-film route, carries this exact work forward into branching scenes, character sheets, and art direction. A converted script becomes the raw material for mapping choices, designing the cast that speaks the labeled lines, and planning the backgrounds and sprites each cue demands.

That sequence is intentional. Labels become cast members, cues become art lists, scenes become branches. Writers who arrive with formatted output skip the cleanup phase entirely and start directing. The converter handles the text transform here so the studio sessions can spend their time on decisions only a writer or director can make.

A closing checklist for every scene

Before calling any scene formatted, confirm five things. Every spoken line carries its true speaker label. Every direction, sound, and scene change sits on its own cue line. The flagged count reads zero. The engine output has been clicked through once in a test project. The writing document, not the engine file, holds the latest words. Scenes that pass all five import without drama. Scenes that skip any of them import the skip along with the words.

How to use this

  1. Paste one beat per line

    Put each spoken line and each direction on its own line, labeled like MIRA: The train is already leaving.

  2. Set the fallback speaker

    Choose the default name, usually NARRATOR, that unlabeled lines borrow until you label them properly.

  3. Pick the engine output

    Select RenPy, TyranoBuilder, or both to control which formatted previews the tool builds.

  4. Repair flags and copy output

    Read the parsed-lines table, label every flagged row, then copy the engine lines into a test project.

Questions authors ask

How do you format a visual novel script?
Put one beat per line, label each spoken line with SPEAKER and a colon, keep directions on separate cue lines, then translate dialogue into quoted RenPy lines or Tyrano character tags. Three clean labeled lines convert into three engine lines with zero flags.
What does a RenPy dialogue line look like?
A RenPy line names a short character id, then wraps the spoken words in double quotes, indented under a label. Narration uses quotes with no id, and directions become hash comments so they never play as speech.
What does a TyranoBuilder script line look like?
A Tyrano line opens with a character tag carrying the speaker name, then the spoken text, then a page-break marker. Direction lines use semicolon comments instead of character tags so staging never borrows a voice.
Should narration have a speaker label?
Yes, give narration a consistent label such as NARRATOR rather than leaving lines bare. Bare lines force the converter to guess, and a guess repeated fifty times becomes fifty wrong voices to fix by hand.
How do you handle stage directions in a VN script?
Write each direction on its own line starting with a bracket, asterisk, or a cue word like SFX, MUSIC, BG, or SCENE. The converter routes those lines to comments instead of dialogue, which keeps pacing readable in both engines.
What is the biggest formatting mistake in VN scripts?
Mixing prose paragraphs with dialogue, so one pasted line holds speech, action, and a second speaker at once. Splitting to one beat per line before converting removes most flags immediately.

Related tools