Skip to content

feat(core): toggle slide canvas between 16:9 and 4:3#191

Open
itskylechung wants to merge 4 commits into
1weiho:mainfrom
itskylechung:itskylechung/aspect-ratio-toggle
Open

feat(core): toggle slide canvas between 16:9 and 4:3#191
itskylechung wants to merge 4 commits into
1weiho:mainfrom
itskylechung:itskylechung/aspect-ratio-toggle

Conversation

@itskylechung

@itskylechung itskylechung commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

What

Adds a per-slide aspect-ratio toggle so a deck can mix 16:9 and 4:3 slides. A meta.aspect field ('16:9' default, '4:3' opt-in) drives the canvas dimensions everywhere a slide is rendered, and a DEV-only toolbar button flips it.

How

  • meta.aspect — new optional SlideAspect field on SlideMeta. getCanvasDims() in sdk.ts maps it to dimensions (16:9 → 1920×1080, 4:3 → 1440×1080; height stays fixed so existing 1080-tall content isn't rescaled, the 4:3 frame just narrows).
  • RenderingSlideCanvas takes an aspect prop; threaded through the editor canvas, thumbnail rails (vertical + horizontal), presenter, present mode + overview grid, and home-page card previews.
  • Exportsexport-pdf (@page size, frame + supersample dims) and export-html (.os-frame size, fit script) read the slide's aspect.
  • WritersetSlideAspect / updateMetaAspectInSource edit meta.aspect in index.tsx via a new PUT /__slides/:id/aspect dev endpoint. Resetting to 16:9 removes the field (it's the default) and cleans up the line so the file doesn't accrete blank lines.
  • Toolbar button — DEV-only segmented 16:9 / 4:3 control next to the Inspect toggle.
  • i18n — added strings for en / ja / zh-cn / zh-tw.

Tests

  • New getCanvasDims unit tests (default / 16:9 / 4:3).
  • New updateMetaAspectInSource tests covering insert / replace / remove / no-op / fresh-meta, including the no-stray-blank-line invariant.
  • Full suite: 263 passing. typecheck + biome check clean.

A changeset (minor) is included.

Summary by CodeRabbit

  • New Features

    • Added an aspect ratio toggle to switch slides between 16:9 and 4:3; choice is stored with the slide and honored across editor, thumbnails, presenter, present mode, and HTML/PDF exports
    • Slide aspect can be updated programmatically via a new slide metadata update route
  • Localization

    • Added toggle UI text in English, Japanese, Simplified Chinese, and Traditional Chinese

itskylechung and others added 2 commits June 1, 2026 14:46
Adds a meta.aspect field on slides ('16:9' default, '4:3' opt-in)
and a DEV-only toolbar button that flips it. The new ratio flows
through the editor canvas, thumbnail rails, presenter, present
mode, and HTML/PDF exports.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
updateMetaAspectInSource was stripping the `aspect: '4:3',` substring but
leaving the surrounding indentation + newline, so the meta object grew a
blank, indented line on each round-trip. The removal path now eats the
whole source line.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 1, 2026

Copy link
Copy Markdown

@itskylechung is attempting to deploy a commit to the Yiwei Ho Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2f853fac-6554-4334-b2ef-2a67fd08463e

📥 Commits

Reviewing files that changed from the base of the PR and between 821eaf2 and 078bbd1.

📒 Files selected for processing (4)
  • packages/core/src/app/lib/sdk.ts
  • packages/core/src/app/routes/home.tsx
  • packages/core/src/editing/slide-ops.test.ts
  • packages/core/src/editing/slide-ops.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/app/lib/sdk.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/core/src/editing/slide-ops.test.ts
  • packages/core/src/app/routes/home.tsx
  • packages/core/src/editing/slide-ops.ts

Walkthrough

Adds slide aspect-ratio support (16:9 and 4:3): new SlideAspect type and getCanvasDims, source rewrite and persistence, dev PUT route, component prop threading (Player/SlideCanvas/thumbnails/presenter), export sizing for HTML/PDF, localization, and a Changeset release note.

Changes

Slide Aspect Ratio Toggle

Layer / File(s) Summary
Core data model and canvas dimensions helper
packages/core/src/app/lib/sdk.ts, packages/core/src/app/lib/sdk.test.ts
Adds SlideAspect (`'16:9'
Server-side source rewrite & persistence
packages/core/src/editing/slide-ops.ts, packages/core/src/editing/slide-ops.test.ts
Implements SlideAspectValue, validateSlideAspect, updateMetaAspectInSource to insert/replace/remove aspect in export const meta while preserving formatting, and setSlideAspect to resolve slide entry, apply rewrite, and write back with structured error results; tests cover insertion, overwrite, removal, no-op, trailing-comment handling, and meta creation.
Dev API endpoint for aspect updates
packages/core/src/vite/routes/slides.ts
Adds PUT /__slides/:id/aspect that validates body, calls setSlideAspect, sends a full-reload websocket event, and returns { ok: true, slideId, aspect }.
Component prop threading & canvas sizing
packages/core/src/app/components/player.tsx, packages/core/src/app/components/slide-canvas.tsx, packages/core/src/app/components/present/overview-grid.tsx, packages/core/src/app/components/thumbnail-rail.tsx
Player, SlideCanvas, PresentOverviewGrid, and ThumbnailRail accept optional aspect prop; SlideCanvas and thumbnail components derive canvasW/canvasH from getCanvasDims(aspect) and update scaling/layout math accordingly.
Route integration and DEV toggle
packages/core/src/app/routes/slide.tsx, packages/core/src/app/routes/presenter.tsx, packages/core/src/app/routes/home.tsx
Slide route reads slide.meta?.aspect, wires aspect into Player, SlideCanvas, and rails, and adds a DEV-mode toolbar toggle that PUTs the new aspect; Presenter and Home routes use getCanvasDims and pass aspect to previews/thumbnails.
HTML and PDF export aspect-aware sizing
packages/core/src/app/lib/export-html.ts, packages/core/src/app/lib/export-pdf.ts
exportSlideAsHtml and exportSlideAsPdf compute per-slide canvasW/canvasH via getCanvasDims(slide.meta?.aspect) and thread dimensions through rendering; PDF export uses buildPrintStyles(width,height) to generate dynamic print CSS instead of hardcoded 1920×1080.
Localization strings for toggle
packages/core/src/locale/types.ts, packages/core/src/locale/en.ts, packages/core/src/locale/ja.ts, packages/core/src/locale/zh-cn.ts, packages/core/src/locale/zh-tw.ts
Adds aspectToggleTitle and aspectToggleAria to the Locale['slide'] type and translations (en, ja, zh-cn, zh-tw).
Release notes
.changeset/aspect-toggle.md
Adds a Changeset declaring a minor bump and documenting the aspect-ratio toggle across editor, presenter, present mode, and exports.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • 1weiho

Poem

🐰 I hopped through code to change the frame,
Swapped sixteen-nine and four-to-three the same,
Meta saved the shape, UI follows through,
Exports and previews dance in tune too,
A little rabbit cheers: aspect switch—hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: adding a toggle to change slide canvas aspect ratio between 16:9 and 4:3.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 821eaf23d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/editing/slide-ops.ts Outdated

const exportDefaultIdx = source.search(/export\s+default\b/);
if (exportDefaultIdx === -1) return null;
const insertion = `export const meta: SlideMeta = { aspect: ${newLiteral} };\n\n`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid emitting an unimported SlideMeta type

When toggling a valid slide module that has no export const meta block (for example, just export default [Cover] satisfies Page[];) to 4:3, this branch inserts export const meta: SlideMeta = ... without adding or ensuring a SlideMeta import. That leaves the slide with an unresolved type name and breaks the dev/build type pipeline immediately after using the new aspect toggle on such slides.

Useful? React with 👍 / 👎.

…lue mirror

DEFAULT_ASPECT was exported but never consumed. Document why the editor-side
SlideAspectValue union is kept separate from the client SlideAspect type.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/core/src/editing/slide-ops.ts (1)

257-260: ⚡ Quick win

Reuse the shared aspect contract here.

This redefines the same union/default that packages/core/src/app/lib/sdk.ts already exports, so the persistence layer can drift from the runtime/UI contract over time. Import type SlideAspect and DEFAULT_ASPECT instead of duplicating the literals here.

Also applies to: 269-270

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/editing/slide-ops.ts` around lines 257 - 260, Replace the
duplicated union with the shared SDK contract: import the exported type
SlideAspect and DEFAULT_ASPECT from the shared module and use SlideAspect in
place of the local SlideAspectValue type, and update validateSlideAspect to
accept unknown and return SlideAspect | null using the shared literals (and
fallback/default where appropriate); also update the other occurrences that
repeat the literals (previously at the same block) to reference DEFAULT_ASPECT
instead of hardcoded '16:9'/'4:3' so persistence and runtime use the single
source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/app/routes/home.tsx`:
- Line 463: The outer preview shell is hardcoded to "aspect-video" while
SlideCanvas gets slide?.meta?.aspect, causing mismatched thumbnails; update the
outer preview container (the element wrapping SlideCanvas near the SlideCanvas
invocation) to use the slide's aspect (e.g., compute a className based on
slide?.meta?.aspect with a sensible default like "aspect-video") so the wrapper
and SlideCanvas share the same aspect ratio; look for the wrapper element around
SlideCanvas and replace the fixed "aspect-video" with a dynamic class derived
from slide?.meta?.aspect (or map common ratio strings to Tailwind aspect
classes) so 4:3 slides render correctly.

In `@packages/core/src/editing/slide-ops.ts`:
- Around line 298-312: When removing the matched property in the remove branch,
extend the deletion span to also consume same-line trailing whitespace and
comments: after computing lineEnd = idx + matchLen, advance lineEnd over
spaces/tabs, then if you see '//' advance to the next newline, or if you see
'/*' advance until the closing '*/' (inclusive); finally if the next char is a
newline consume it as well before building before/after and stripping the
dangling comma. Update the block around lineEnd (the variables body, lineEnd,
idx, match, openBrace, closeBrace) to perform these extra consumes so trailing
inline comments are removed with the property.

---

Nitpick comments:
In `@packages/core/src/editing/slide-ops.ts`:
- Around line 257-260: Replace the duplicated union with the shared SDK
contract: import the exported type SlideAspect and DEFAULT_ASPECT from the
shared module and use SlideAspect in place of the local SlideAspectValue type,
and update validateSlideAspect to accept unknown and return SlideAspect | null
using the shared literals (and fallback/default where appropriate); also update
the other occurrences that repeat the literals (previously at the same block) to
reference DEFAULT_ASPECT instead of hardcoded '16:9'/'4:3' so persistence and
runtime use the single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ec0ffbda-6731-4426-9756-3154b81c3748

📥 Commits

Reviewing files that changed from the base of the PR and between 9b8202e and 821eaf2.

📒 Files selected for processing (20)
  • .changeset/aspect-toggle.md
  • packages/core/src/app/components/player.tsx
  • packages/core/src/app/components/present/overview-grid.tsx
  • packages/core/src/app/components/slide-canvas.tsx
  • packages/core/src/app/components/thumbnail-rail.tsx
  • packages/core/src/app/lib/export-html.ts
  • packages/core/src/app/lib/export-pdf.ts
  • packages/core/src/app/lib/sdk.test.ts
  • packages/core/src/app/lib/sdk.ts
  • packages/core/src/app/routes/home.tsx
  • packages/core/src/app/routes/presenter.tsx
  • packages/core/src/app/routes/slide.tsx
  • packages/core/src/editing/slide-ops.test.ts
  • packages/core/src/editing/slide-ops.ts
  • packages/core/src/locale/en.ts
  • packages/core/src/locale/ja.ts
  • packages/core/src/locale/types.ts
  • packages/core/src/locale/zh-cn.ts
  • packages/core/src/locale/zh-tw.ts
  • packages/core/src/vite/routes/slides.ts

Comment thread packages/core/src/app/routes/home.tsx
Comment thread packages/core/src/editing/slide-ops.ts
- Emit untyped `export const meta` when inserting into a slide with no meta
  block, so a missing SlideMeta import can't dangle (Codex).
- Eat a same-line trailing comment when removing the aspect property so it
  isn't orphaned inside meta (CodeRabbit).
- Make the home-card frame aspect-aware so 4:3 previews aren't pillarboxed in
  a 16:9 shell (CodeRabbit).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant