Skip to content

Final Draft (FDX) import #190

@stultus

Description

@stultus

What

Import .fdx (Final Draft XML) files into Scriptty as a Film, into a Series as a new Episode, or via the standard Open dialog (auto-detected by extension). Mirrors the Fountain import flow (#184) — same dirty-state guards, same import-summary toast, same per-episode entry points.

Why

Final Draft is the dominant pro screenwriting tool. Co-writing handoffs frequently arrive as .fdx. Scriptty already imports Fountain (#184) but not FDX, so writers coming from Final Draft hit a wall on day one.

Spec research findings (lock the design)

Done a thorough pass on the FDX format — full report in the implementation comment below. Key facts that shape v1:

  • Format: XML 1.0, UTF-8, no public DTD. Only <Content> is required at the root; everything else is optional and varies wildly across Final Draft versions and other apps that round-trip the format.
  • Element types are explicit (Type="Scene Heading", "Action", "Character", "Parenthetical", "Dialogue", "Transition", "Shot", "General", "Lyrics", "Outline N"). No Fountain-style forced-prefix heuristics needed — just dispatch on the attribute.
  • Inline formatting uses sibling <Text> children with Style="Bold+Italic+Underline" (+-separated). Maps directly to ProseMirror's bold/italic/underline marks (Scriptty already supports all three).
  • Title page is free-form <Paragraph> blocks — no <Title>/<Author> semantic markers. Real Final Draft pads with blank lines and centres credits. v1: dump full title-page text into meta.extra["fdx_title_page"] and try a Beat-style heuristic for meta.title / meta.author / meta.draft_date / meta.contact.
  • Dual dialogue: <Paragraph><DualDialogue><Paragraph Type="Character">…</Paragraph><Paragraph Type="Dialogue">…</Paragraph>…</DualDialogue></Paragraph>. Collapse to sequential pairs (matches Fountain handling per Fountain import (round-trip-safe) #184 scope).
  • Locked scene numbers (<Paragraph Type="Scene Heading" Number="1A">) — meaningful for production. v1: drop with summary count, revisit when scene_cards gains a free-form metadata field.

Scope decisions (locked)

FDX feature Scriptty mapping
Type="Scene Heading" / "Shot" scene_heading node (Shot folded — Scriptty has no separate Shot type)
Type="Action" / "General" / "Lyrics" / "Outline N" action node
Type="Character" (incl. extensions like (V.O.)) character node — extensions kept inline
Type="Parenthetical" parenthetical node — parens kept in content (project convention)
Type="Dialogue" dialogue node
Type="Transition" transition node
<Text Style="Bold"> / "Italic" / "Underline" (or +-combined) ProseMirror bold/italic/underline marks
<Text Style="Strikeout"/"AllCaps"/"Highlight"> dropped (no Scriptty equivalent)
<DualDialogue> collapsed to sequential Character/Dialogue pairs, counted
<TitlePage> best-effort meta.title / meta.author / meta.draft_date / meta.contact + full text → meta.extra["fdx_title_page"]
FDX Version attribute meta.extra["fdx_source_version"] (cheap debug aid)
<Revisions> + <Text RevisionID> dropped, counted
<ScriptNotes> / inline <ScriptNote> dropped, counted (re-anchoring Range="loc,end" is unreliable once the editor touches the doc)
<LockedPages> / <Paragraph Number="1A"> dropped, counted
<TagData> (production tagging) dropped, counted
<SceneProperties> (colour, length, arc beats) dropped
<HeaderAndFooter>, <PageLayout>, <SmartType>, <Watermarking>, <Macros>, <Actors>, <CastList>, etc. dropped (Scriptty has no equivalent concepts)
.fdr (legacy binary) not supported — .fdx only

No new ProseMirror node types, no editor schema changes. Reuses meta.extra from #185.

Sub-issues

  • FDX parser (Rust, with quick-xml dep) — TBD
  • FDX wiring: menu, Open dialog filter, Import as Episode, summary toast — TBD

Out of scope (this feature)

  • FDX export (no current writers requesting it; Fountain export is the canonical co-writing handoff)
  • Locked page-number preservation (deferred until scene_cards gains a free-form metadata bag)
  • Revision-mark / draft-history preservation (deferred until Scriptty grows a revision model)
  • Inline script-note preservation (the Range="loc,end" anchors break the moment the editor touches the doc — better to drop loudly than preserve wrong)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions