Skip to main content

Bidirectional sync between a Slidev markdown deck and Google Slides as native, editable objects

Project description

slidesync

Bidirectional sync between a Slidev markdown deck and Google Slides — as native, editable objects (title/body/bullets/tables/positioned images, brand-styled text boxes), not pasted screenshots.

Version: 0.1.0

uvx slidesync --help            # run without installing
pip install slidesync           # or install the CLI + library

Why

Exporting a deck to images gives you something you can't edit; pasting markdown by hand gives you something you can't version. slidesync keeps a .slidev.md file as the source of truth and renders it into real Slides objects, so the result stays fully editable in Google Slides — and pull reconstructs the markdown back from those objects, so the loop is reversible.

  • push — markdown → Slides (idempotent upsert, never a blind append).
  • pull — Slides → markdown (handles multi-text-box and externally-authored decks, bullet nesting, tables, images, and speaker notes).
  • roundtrip — push a sample to a scratch deck, pull it back, assert the two are semantically identical, delete the scratch deck.

Auth (no setup)

Auth is borrowed from the gog CLI — no separate OAuth client. slidesync reads the client id/secret from ~/Library/Application Support/gogcli/credentials.json and the refresh token via gog auth tokens export, then mints a short-lived access token. The stored token already carries the slides + drive scopes; the Slides API must be enabled on the gog Cloud project. Override the account with --account or $SLIDESYNC_ACCOUNT. (Currently macOS-only — it reads gog's macOS Application Support path.)

Commands

Command Purpose
slidesync push <file.slidev.md> [--deck ID] [--new "Title"] [--anchor SLIDE] [--prune] [--force] markdown → Slides
slidesync pull <deckId> --out <file.md> [--all] Slides → markdown (--all includes non-managed slides)
slidesync roundtrip [--keep] self-test: push a sample, pull, assert identical
slidesync layouts <deckId> list a deck's theme layouts + placeholders
slidesync make-templates <deckId> inject branded {{token}} template slides

push resolves the target deck from (in order) --deck, --new, or a top-level deck: frontmatter key. Relative image paths resolve against the markdown file's directory.

slidesync push deck.slidev.md            # targets `deck:` frontmatter
slidesync push deck.slidev.md --new "Talk"
slidesync pull <id> --out deck.slidev.md
slidesync roundtrip

Idempotent sync (upsert)

Each managed slide is created with objectId = s2g_<keyHash>_<contentHash>. keyHash = per-slide id: frontmatter, else title slug, else index (survives edits/reorders); contentHash is over a canonical render, so push → pull → push is a no-op. Diff per run: identical hash → skip; same key, new content → replace; new key → create. Removed slides are kept unless --prune. Only s2g_ slides are ever touched — hand-authored slides are invisible to the sync. A hidden <!-- s2g {...} --> marker in speaker notes carries the human id, image path, and template vars so pull can recover them.

Markdown dialect

Top-level frontmatter: theme:, deck:. Slides separated by ---; each slide may have its own frontmatter (id:, template:, layout:).

  • # h1 = headline, ## h2 above an # h1 = kicker; a lone ## is the title.
  • Bullets -/*; ordered 1. (nest with 2-space indent). Inline **bold** / *italic* / `code` / [link](url). GFM tables. ![alt](path) images (uploaded to Drive; alt becomes the accessibility description, round-tripped on pull). Blank lines preserved as spacing. <!-- notes --> become speaker notes.
  • Internal links: [text](#slide-id) becomes a native Slides link to the slide whose id: (or title slug) is slide-id.

Built-in brand kit (IBM Plex; red #C0392B kicker)

Select per slide via template: — native styled boxes, no in-deck templates: dark/title, appendix, question/label, topic, content, graph/full (single full-bleed image), prompt/code (verbatim monospace). Slides with no template: fall back to a generative path (section / title+body / table / image) that also brands the background + IBM Plex.

Custom slides (diagrams) — pull-authoritative

Give a slide a fenced ```gslides block holding literal Slides API requests (use __PAGE__ for the slide page id). Sync is pull-authoritative / push-if-missing: the Slides copy is the source of truth — push only creates the slide when missing, pull captures the live drawing back into the block.

Development

uv sync
uv run pytest -q          # offline tests (no network/auth)

Releases publish to PyPI via Trusted Publishing (OIDC) on a v*.*.* tag — see .github/workflows/release.yml. Bump with uvx bumpver update --patch.

Caveats

  • Slidev-only constructs (<v-clicks>, <div grid>, CSS) are flattened/stripped — this is a content mapper, not a CSS renderer.
  • On pull, the slide model holds a single image, so a slide with multiple images keeps the first; image contentUrls from foreign decks are ephemeral.

License

MIT © Daniel Hails

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slidesync-0.1.0.tar.gz (31.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slidesync-0.1.0-py3-none-any.whl (27.7 kB view details)

Uploaded Python 3

File details

Details for the file slidesync-0.1.0.tar.gz.

File metadata

  • Download URL: slidesync-0.1.0.tar.gz
  • Upload date:
  • Size: 31.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for slidesync-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fe9c3fbe4c70640341b24f4e02792b321d16dc3ee7154d6c51db4d291178e93c
MD5 7d30a809e122034c392739f4ef565872
BLAKE2b-256 2a7350099427f5cd94d3ad48b8377f959ac1447d726413a447315cf4b20ac490

See more details on using hashes here.

Provenance

The following attestation bundles were made for slidesync-0.1.0.tar.gz:

Publisher: release.yml on DJRHails/slidesync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file slidesync-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: slidesync-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 27.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for slidesync-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e3b0b0a7b8a7bba32a4c1953096e8a7bdcf1acc13aaa44e73f833e6408340e44
MD5 7156ed48fcf634026e047222fc7adb00
BLAKE2b-256 3530e448e7ebbf7a53abb4bbe1b4bf113b316ed34d7eb67d51898603407ee444

See more details on using hashes here.

Provenance

The following attestation bundles were made for slidesync-0.1.0-py3-none-any.whl:

Publisher: release.yml on DJRHails/slidesync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page