Convert a Doc outline into a Slides deck
Turn Doc headings and bullets into a Slides deck — one slide per H1.
Published Oct 26, 2025
Northwind’s strategy deck starts life as a Doc outline. Writing the argument in prose is faster than fighting slide placeholders, so the thinking happens in a Doc — and then someone spends an afternoon copying headings onto title slides and bullets into body boxes by hand. The deck and the outline drift apart the moment that copying starts.
This script does the copying for you. It reads a Doc where each Heading 1 marks a slide and the paragraphs beneath it are that slide’s content, then builds a Slides deck with one slide per H1. Rework the outline in the Doc, run it again, and you get a fresh deck — the Doc stays the single source of truth.
What you’ll need
- A Google Doc structured as an outline: every section starts with a Heading 1, and the lines under it are the body content for that slide.
- A title for the new deck. The script creates the deck itself, so you only supply the name.
- Nothing else — Slides is created fresh on each run.
The script
// The Doc that holds the outline — the long string from its URL.
const OUTLINE_DOC_ID = '1abcDocId';
// The title for the deck the script creates.
const DECK_TITLE = 'Northwind Strategy';
/**
* Reads an outline Doc and builds a Slides deck: one slide per Heading 1,
* with the paragraphs beneath each heading as that slide's body text.
* Returns the URL of the new deck.
*/
function docToDeck() {
const body = DocumentApp.openById(OUTLINE_DOC_ID).getBody();
// 1. Create the deck and set its built-in title slide.
const deck = SlidesApp.create(DECK_TITLE);
const intro = deck.getSlides()[0];
intro.getPlaceholders()[0].asShape().getText().setText(DECK_TITLE);
// 2. Walk the Doc top to bottom, building slides as we go.
let currentSlide = null;
for (let i = 0; i < body.getNumChildren(); i++) {
const c = body.getChild(i);
// Skip anything that is not a paragraph (tables, images, page breaks).
if (c.getType() !== DocumentApp.ElementType.PARAGRAPH) continue;
const para = c.asParagraph();
const text = para.getText();
// Skip blank lines so they do not pad the body text.
if (!text) continue;
if (para.getHeading() === DocumentApp.ParagraphHeading.HEADING1) {
// 3. A Heading 1 starts a new slide — set its title, clear its body.
currentSlide = deck.appendSlide(SlidesApp.PredefinedLayout.TITLE_AND_BODY);
currentSlide.getPlaceholders()[0].asShape().getText().setText(text);
currentSlide.getPlaceholders()[1].asShape().getText().setText('');
} else if (currentSlide) {
// 4. Any other line becomes a body line on the current slide.
const bodyShape = currentSlide.getPlaceholders()[1].asShape().getText();
bodyShape.appendText(text + '\n');
}
}
Logger.log('Built deck: ' + deck.getUrl());
return deck.getUrl();
}
How it works
docToDeckopens the outline Doc and creates a new Slides deck with the configured title.- It sets the deck’s first slide — the built-in title slide — to
DECK_TITLEby writing into placeholder0. - It loops through every child element of the Doc body in order. Anything that is not a paragraph (a table, an image, a page break) is skipped, as are blank paragraphs.
- When it hits a Heading 1, it appends a new
TITLE_AND_BODYslide, writes the heading text into the title placeholder, and clears the body placeholder so it starts empty. - Any other non-blank paragraph is appended to the current slide’s body placeholder, one line at a time. Lines before the first Heading 1 are ignored, because there is no slide to attach them to yet.
- It logs and returns the deck URL so you can open it straight away.
Example run
Say the outline Doc reads:
Market Position (Heading 1)
We lead in the mid-market.
Enterprise share is growing.
Risks (Heading 1)
Two competitors cut prices.
Supplier costs are up 8%.
After a run you get a three-slide deck:
| Slide | Title | Body |
|---|---|---|
| 1 | Northwind Strategy | (title slide) |
| 2 | Market Position | We lead in the mid-market. / Enterprise share is growing. |
| 3 | Risks | Two competitors cut prices. / Supplier costs are up 8%. |
Each Heading 1 became one slide, and the lines beneath it became that slide’s body text — no manual copying.
Run it
This is an on-demand job — run it whenever the outline is ready to present:
- In the Apps Script editor, set
OUTLINE_DOC_IDandDECK_TITLE, selectdocToDeck, and click Run. - Approve the authorisation prompt the first time.
- Check the execution log for the deck URL, or open it from your Drive.
Watch out for
- It creates a new deck every run. Run it three times and you have three decks
in your Drive. If you want to refresh one deck in place, open a fixed deck by
ID and clear its slides instead of calling
SlidesApp.create. - Content before the first Heading 1 is dropped. Lines that appear above the first H1 have no slide to land on, so they are silently skipped — keep your intro text under a heading.
- Long sections overflow the slide. The body placeholder does not auto-shrink past a point; if a section has fifteen lines, Slides will spill them off the edge. Split dense sections into more Heading 1s.
- It copies plain text only. Bold, links, and nested bullet levels from the Doc are flattened — every body line lands as a plain bullet. Restyle in Slides afterwards if presentation matters.
Related
Generate personalized study guides from notes
Reformat raw notes into structured study guides — for Northwind's internal training programme.
Updated Feb 8, 2026
Build a contract-clause assembly system
Construct Northwind agreements from a library of approved clauses — drag-drop in code.
Updated Feb 1, 2026
Translate and resolve Doc comments
Localise reviewer feedback on a shared Doc so multilingual teams can collaborate.
Updated Jan 25, 2026
Auto-archive finalized Docs to dated folders
File completed Northwind Docs by month so the active folder stays focused on in-flight work.
Updated Jan 18, 2026
Build a fillable intake form inside a Doc
Create structured intake forms with placeholder fields readers can fill — for client briefs.
Updated Jan 11, 2026