Screenplay formatting is surprisingly complex. Every element — sluglines, action, dialogue, parentheticals — has strict industry standards. Here's what we learned building TaleForge's screenplay editor with Next.js.
The Challenge
Screenplays follow the Courier 12pt standard with precise margins:
- Scene headings: ALL CAPS, left-aligned
- Action: left-aligned, present tense
- Character names: centered, ALL CAPS
- Dialogue: centered, narrower margins
- Parentheticals: centered, in parentheses
Most web editors treat text as a single format. Screenplays need context-aware formatting.
Architecture Decisions
1. TipTap as the Editor Core
We chose TipTap for its extensibility. Custom nodes for each screenplay element:
const SceneHeading = Node.create({
name: 'sceneHeading',
group: 'block',
content: 'text*',
// Auto-uppercase, left margin
parseHTML() {
return [{ tag: 'div[data-type="scene-heading"]' }]
},
})
2. Auto-Detection
When a user types INT. or EXT., we auto-detect it as a scene heading. After pressing Enter on a character name, the next block becomes dialogue.
3. PWA for Offline Writing
Writers need to write anywhere. TaleForge uses service workers to cache the entire editor:
// sw.js - Cache screenplay editor assets
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('taleforge-v1').then(cache =>
cache.addAll(['/editor', '/fonts/courier.woff2'])
)
)
})
4. Prisma for Data
Each screenplay is stored with structured scene data:
model Screenplay {
id String @id @default(cuid())
title String
scenes Scene[]
author User @relation(fields: [authorId])
authorId String
}
Results
TaleForge now offers a free screenplay editor that:
- Auto-formats as you type
- Works offline as a PWA
- Supports 10 languages
- Includes a marketplace for publishing
The full platform also includes book and manga editors — making it possible to adapt a screenplay into a novel or graphic novel, all in one tool.
Try it free at tale-forge.com
Have you built rich text editors with custom formatting? What challenges did you face? Share in the comments!
Top comments (0)