MasterSlides
Google Docs into vertical Chinese slides, paginated by the browser, driven by a phone
At a glance
- Problem
- At the Tzu Chi Foundation, talks and meetings are written in Google Docs and shown in Traditional Chinese, often set vertically: top to bottom, right to left.
- What I built
- MasterSlides turns a Google Doc that is shared by link into a paginated presentation.
- Outcome
- Open source; decks export to PDF and editable PPTX, with 74 tests covering conversion, pagination, storage and playlists.
- My role
- Solo
- Period
- 2026-01 → 2026-06
Abilities shown
Each links to the ability and its level on the Skills page.
The problem
At the Tzu Chi Foundation, talks and meetings are written in Google Docs and shown in Traditional Chinese, often set vertically: top to bottom, right to left. The staff who prepare them are not engineers, often have about ten minutes before going on stage to line up the day’s documents, and slide tools handle vertical Chinese poorly.
What I built
MasterSlides turns a Google Doc that is shared by link into a paginated presentation. Staff paste a link, fill in date, title and speakers, and get a deck that reads vertically or horizontally. A QR code on screen opens a phone remote for paging, a laser-pointer spotlight and zoom. An admin dashboard shows which docs are public and confirms before deleting. Decks also export to PDF and editable PPTX.
How it works
- The server exports the doc as Markdown, converts it to HTML, moves images into file storage and keeps one record per doc id. Re-importing overwrites it and its images.
- The date, title and speakers are stored as fields, and the server builds a standard first slide from them.
- The paginator adds elements one at a time into the page that will be shown. When
scrollWidthorscrollHeightoverflows, it takes the element back and starts a new page, or splits a long block in place with a binary search. It reruns on font, orientation or window changes. - Viewer and phone subscribe to a per-room WebSocket channel on drust. A server endpoint publishes the commands.
- The same handlers run under a Bun dev server and Cloudflare Pages Functions.
Decisions
- Let the browser do the layout. Pagination went through Paged.js, CSS columns, canvas measurement with pretext, a binary search in a hidden wrapper, and finally measuring inside the real page. The hidden wrapper cut off the last vertical column on narrow screens. Measuring where the page is rendered removes that mismatch.
- Self-host the Ministry of Education Standard Kaiti font. System Kaiti fonts render differently on macOS and iPad.
- Keep the publish token on the server. Browsers subscribe with the anonymous token. Publishing to a room needs the service token, which never leaves the server.
- Move from Supabase to drust. Early versions ran on Express and Socket.io, then on self-hosted Supabase. Storage moved in late May 2026 and realtime in early June, onto my own BaaS.
Outcome
The source is public on GitHub. Built solo from January to June 2026, with 8 design specs paired with plans and 74 tests covering conversion, pagination, storage and playlists. I built it with Claude Code in a spec → plan → implement → review loop.