A dependency-light Static Site Generator that turns a folder of Google Docs into a fast, modern, deployable website — no CMS, no database.
Write an article in Google Docs → drop it in a Drive folder → run two commands → get a polished static site (images included).
Demo theme: UroCare UK — a fictional association of urology specialists. Clean, clinical, trustworthy design. Perfect as a tutorial you can clone, rebrand and reuse.
- 🔌 Pulls Google Docs from a shared Drive folder (
post/+img/). - 🧼 "Forced" styling — strips all the noise Word/Google Docs add and keeps
only structure (
h1–h4,p, lists, links, images), so every article looks consistent and modern via one stylesheet. - ✍️ Typography pre-formatter — fixes common typing mistakes (double spaces, spacing around punctuation, smart quotes, em dashes, ellipses).
- 🖼️ Image support — images from the
img/folder (matched to a post by file name) are downloaded and appended to the article. The first matching image becomes the post thumbnail on the landing and blog pages. - 🏠 Landing page + blog + per-article pages, fully responsive.
- 🎬 Subtle motion — sticky header, scroll-reveal animations (respects
prefers-reduced-motion). - 🚀 Static output in
dist/— host it anywhere (GitHub Pages, Netlify, etc.).
Google Drive (shared folder)
├── post/ ← Google Docs (one file = one article)
└── img/ ← images, matched to a post by file name
│ (1) npm run sync → sync-drive.js
▼
content/articles/*.json ← Docs exported to HTML + downloaded images
│ (2) npm run build → build.js
▼
dist/ ← landing + blog + article pages (ready to deploy)
Create a shared folder and add two sub-folders inside it:
<shared folder> ← GOOGLE_DRIVE_FOLDER_ID points here
├── post/
│ └── test-1 ← Google Doc (the article title = the file name)
└── img/
├── test-1.jpg ← cover / thumbnail (first match)
├── test-1-2.jpg ← appended after the cover, at the end of the post
└── test-1-3.png ← more images, in order …
Share the shared folder (not just the sub-folders) with your service account email, with Viewer access.
Images in img/ are linked to a post when their file name matches the post
name. A separator is required before any number suffix, so test-10 is not
confused with test-1.
Post (in post/) |
Images (in img/) |
Result |
|---|---|---|
test-1 |
test-1.jpg |
thumbnail on cards and shown at end of post |
test-1 |
test-1.jpg, test-1-2.jpg… |
all appended at the end of the article, in order |
test-1 |
test-10.jpg |
not matched (different post) |
Accepted separators between the post name and the number: space, -, _, ().
Examples that all match post test-1: test-1, test-1-2, test-1_3, test-1 (4).
The first matching image is the thumbnail (landing + blog cards). All matching images are appended at the end of the article body — the cover is not duplicated at the top of the page.
.
├── sync-drive.js # Extraction engine (Drive → JSON + images)
├── build.js # SSG: JSON + templates → dist/
├── templates/
│ ├── landing.html # Home page
│ ├── blog.html # Blog listing
│ ├── article.html # Single article
│ └── partials/ # Shared head / header / footer
├── assets/
│ ├── styles.css # Single source of truth for styling
│ ├── app.js # Header + scroll-reveal + mobile menu
│ └── img/ # Logo, hero, placeholder
├── content/articles/ # Synced JSON + images (from npm run sync)
└── dist/ # Build output (generated, git-ignored)
| File | Role |
|---|---|
sync-drive.js |
Extraction. Authenticates to Drive (JWT), exports Docs from post/, downloads matching images from img/, writes JSON. |
build.js |
Hydration. Sanitises HTML, fixes typography, injects content into templates and writes dist/. |
assets/styles.css |
One stylesheet that "forces" a consistent look on every page and article. |
# 1. Install dependencies
npm install
# 2. Build the site (uses synced content in content/articles/)
npm run build
# 3. Preview locally
npm run serve # then open the printed URLcp .env.example .env # fill in GOOGLE_DRIVE_FOLDER_ID and GOOGLE_CREDENTIALS_JSON
npm run sync # pull docs + images from Drive
npm run build # regenerate the site
# or both in one step:
npm run generate- Write or edit a Google Doc in the
post/folder. - Add images to
img/using the same base name (e.g.my-post.jpg,my-post-2.jpg). - Run
npm run sync && npm run build(ornpm run generate). - Deploy
dist/or preview withnpm run serve.
- Go to the Google Cloud Console and create a project.
- Enable the Google Drive API.
- Create a Service Account and generate a JSON key.
- In Google Drive, create a shared folder with
post/andimg/sub-folders. - Share the shared folder with the service account email (Viewer access).
- Put the shared folder ID and the JSON (single line) into
.env:
GOOGLE_DRIVE_FOLDER_ID=1AbC...xyz
GOOGLE_CREDENTIALS_JSON='{"type":"service_account","client_email":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...","...":"..."}'
.envis git-ignored. Never commit your real credentials.
- Headings (
Heading 1/2/3in the Doc) → real<h1>/<h2>/<h3>→ styled automatically. - Paragraphs →
<p>with consistent spacing. - Bold / italic → converted to
<strong>/<em>. - Typos → double spaces, spacing around punctuation, straight quotes,
--and...are automatically corrected. - Images from
img/→ downloaded tocontent/articles/images/<slug>/, appended at the end of the article; the first match is the thumbnail. - The document's own title block is removed (the site renders the title), and everything else (inline colours, fonts, custom classes) is stripped, so the site stays clean and on-brand no matter how the Doc was formatted.
- Style: clinical, minimal, trustworthy, modern.
- Palette: white
#FFFFFF, medical navy#1E3A8A, medical blue#3B82F6, light grey#F3F4F6. - Type:
Inter(sans-serif).
MIT — use it freely for your own tutorial, blog or client project.