Skip to content

feat: better custom preview aspect ratios - #4450

Merged
Julusian merged 5 commits into
mainfrom
claude/surface-button-dimensions-g9ebr1
Sep 3, 2026
Merged

feat: better custom preview aspect ratios#4450
Julusian merged 5 commits into
mainfrom
claude/surface-button-dimensions-g9ebr1

Conversation

@Julusian

@Julusian Julusian commented Sep 3, 2026

Copy link
Copy Markdown
Member

Replaces #4381

Shortcuts for more aspect ratios for different surfaces in the style editor.

There isn't enough space on the bar to show everything the user could end up with, and if that list becomes dynamic they will need some better way to identify them.

So instead, we add some options to the bottom of the popover:

image

This uses data sourced from the 'known' surfaces (the ones both connected and disconnected in the surfaces table).
To do this we are now storing the full surface layout definition they provide, which we can use for more in the future. So this will start working after Companion next sees those surfaces.

So this will work for any connected surfaces that use different aspect ratios, not just official ones. Anything connected over satellite will appear here too.

Summary by CodeRabbit

  • New Features

    • Added surface layout and button-size information for connected and offline surfaces.
    • Added live updates for surface layouts and available button dimensions.
    • Added an aspect-ratio picker with presets, custom width/height values, and ratios derived from connected surfaces.
    • Surface layouts now persist with surface configuration.
  • Improvements

    • Aspect-ratio controls are organized into a dedicated, more compact picker beneath the layered button preview.

…ton preview

Every surface already reports a layout manifest when it connects - style
presets with bitmap sizes, and the map of controls that use them - but
Companion threw it away after resolving the draw styles. That left the
layered button preview's aspect ratio picker with a hardcoded list, which
cannot grow to cover every surface model.

Persist the manifest alongside the other details kept for offline surfaces
(type, integrationType, gridSize) and publish it on two subscriptions: the
full manifest for future use (drawing real surface shapes in the ui), and a
compact per-surface list of distinct button sizes for consumers which only
need the shapes. Both are only rebuilt while something is subscribed.

The custom aspect ratio popover now offers the ratios of the surfaces you
actually have, reduced to their simplest form and labelled with the model
names shown in the surfaces table. Connecting a Stream Deck Neo is enough
for 124:29 to appear; no surface details are baked into the ui.

Also fixes an emulator resize not being pushed to the ui: the handler
persisted the new size but never triggered a surfaces list update.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZbz3FYcyfrqRFSUUBuuV4
The dropdown was the wrong control: it binds a selected value, so whenever
the applied ratio was not one of the surface derived choices - which is the
normal case, since the preset bar covers the common ones - it rendered its
invalid state, showing a red "Custom: 9:7".

These are actions, not a selection. They are now rows in the popover, in the
same style as the grid zoom control's reset row: click one to apply it and
close. What is currently applied is already shown by the preset bar and the
W/H fields, and the row matching it is marked active.

Ratios the preset buttons already cover are left out, so the list only ever
offers a shape that cannot be reached otherwise, and it disappears entirely
when there is nothing to add - leaving the popover exactly as it was.

The picker moves into its own file so it can be rendered in a story, which
is how the above was checked. That turned up the ratio glyph being invisible
in the popover: its rule was nested under the canvas footer, so it never
applied anywhere else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZbz3FYcyfrqRFSUUBuuV4
The input group prefixes size to their text, so the single letter W and H
labels came out different widths (41px vs 37px) and the two fields did not
line up. Pin them to a shared width, with the letter centred.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZbz3FYcyfrqRFSUUBuuV4
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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: Team

Run ID: cc99302b-1ea4-49a4-9909-1cd992d26f77

📥 Commits

Reviewing files that changed from the base of the PR and between fc9bfc0 and c8e3930.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (22)
  • companion/lib/Surface/Config.ts
  • companion/lib/Surface/Controller.ts
  • companion/lib/Surface/Handler.ts
  • companion/lib/Surface/IP/ElgatoEmulator.ts
  • companion/lib/Surface/IP/Satellite.ts
  • companion/lib/Surface/LayoutSummary.ts
  • companion/lib/Surface/PluginPanel.ts
  • companion/lib/Surface/Types.ts
  • companion/lib/Surface/Util.ts
  • companion/test/Surface/Config.test.ts
  • companion/test/Surface/ControllerLayouts.test.ts
  • companion/test/Surface/LayoutSummary.test.ts
  • companion/test/Surface/PanelLayouts.test.ts
  • shared-lib/lib/Model/Surfaces.ts
  • shared-lib/package.json
  • webui/src/Buttons/EditButton/EditButton.css
  • webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/AspectRatioPicker.css
  • webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/AspectRatioPicker.stories.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/AspectRatioPicker.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/LayeredButtonPreviewRenderer.tsx
  • webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/__tests__/surfaceAspectRatios.test.ts
  • webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/surfaceAspectRatios.ts
💤 Files with no reviewable changes (1)
  • webui/src/Buttons/EditButton/EditButton.css

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The PR adds shared surface layout models, persists layouts from panels, publishes layout and bitmap-size subscriptions, and replaces the layered editor’s aspect ratio controls with a surface-aware picker.

Changes

Surface Layout and Aspect Ratio Picker

Layer / File(s) Summary
Layout contracts and surface providers
shared-lib/lib/Model/Surfaces.ts, companion/lib/Surface/{Types,Config,Util}.ts, companion/lib/Surface/IP/*, companion/lib/Surface/PluginPanel.ts
Surface layout types are re-exported and added to surface configuration. Satellite, emulator, and plugin panels expose layout manifests. Handler configuration stores the current layout.
Layout summaries and subscriptions
companion/lib/Surface/LayoutSummary.ts, companion/lib/Surface/Controller.ts
Companion builds layout manifests and distinct bitmap-size records from connected and stored surfaces. New tRPC subscriptions emit initial and changed payloads with deep-equality suppression.
Backend validation
companion/test/Surface/*
Tests cover layout persistence, migration, provider behavior, summary generation, connected and offline surfaces, deduplication, and subscription updates.
Aspect ratio picker
webui/src/Buttons/EditButton/LayeredButtonEditor/Preview/*, webui/src/Buttons/EditButton/EditButton.css
The preview uses a dedicated aspect ratio picker. It supports preset ratios, clamped custom dimensions, and ratios derived from subscribed surface bitmap sizes. Styles, stories, and utility tests are added.

Poem

Surface layouts take flight,
Button sizes join the stream,
Ratios find their shape,
Tests guide each careful change,
And panels shine anew.

Merge Risk: ⚪ Minimal · up to c8e39

No actionable merge-blocking risk remains in the current change.

🚥 Pre-merge checks | ✅ 4
✅ 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 clearly describes the main change: adding improved custom aspect-ratio options for the preview editor.
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.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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.

shared-lib had a hand written copy of the surface layout schema, which is
owned by @companion-surface/base and is what both the plugin and satellite
surfaces already describe their layouts with. There was no reason for it:
that package's only dependency is zod, which shared-lib already depends on.

Depend on it directly and re-export its types, so there is one description of
a surface layout. PluginPanel had ended up importing both, which is how
obvious this should have been.

The models keep only what is genuinely theirs: the client side items, and a
bitmap size alias derived from the schema's own type with Pick.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZbz3FYcyfrqRFSUUBuuV4
The picker's styles were spread across EditButton.css: the footer strip
nested inside the preview panel block, and the popover's rules stranded at
the bottom of the file because it portals to the body. Neither had anything
to do with the rest of that stylesheet.

They now live in AspectRatioPicker.css, imported by the component, in the
same layer as before (features, by path). The story no longer has to import
the whole feature stylesheet to render one popover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZbz3FYcyfrqRFSUUBuuV4
@Julusian
Julusian marked this pull request as ready for review September 3, 2026 21:19
@Julusian Julusian added this to the v5.1 milestone Sep 3, 2026
@github-project-automation github-project-automation Bot moved this to In Progress in Companion Plan Sep 3, 2026
@Julusian
Julusian merged commit 9b660b5 into main Sep 3, 2026
24 of 25 checks passed
@Julusian
Julusian deleted the claude/surface-button-dimensions-g9ebr1 branch September 3, 2026 21:29
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Companion Plan Sep 3, 2026
@bryce-seifert

Copy link
Copy Markdown
Member

Just saw this and wanted to say it looks great! Nice elegant solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants