Skip to content

andresjmorales/spanright

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

126 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Spanright โ€” Multi-Monitor Wallpaper Alignment Tool

Spanright is a single-page web app that lets you create pixel-perfect spanning wallpapers for non-standard multi-monitor setups. Most operating systems concatenate monitors by pixel resolution when spanning wallpapers, ignoring physical size differences โ€” Spanright solves this by letting you model your physical desk layout, position a source image across it, and export a stitched wallpaper that looks seamless across all your screens. Works for Windows, macOS, and Linux.

The Problem

If you have monitors of different sizes or resolutions (e.g., a 15.6" laptop next to a 27" QHD desktop), spanning a single wallpaper produces misaligned images. The image gets split based on raw pixel counts, not physical dimensions. A mountain peak that should flow across both screens ends up with a jarring offset.

Spanright operates in physical space (inches/cm), so you arrange monitors as they actually sit on your desk. It then renders each monitor's portion of the source image at the correct PPI, producing one output image that your OS can span correctly.

Features

  • Physical-space monitor layout โ€” Arrange monitors on a canvas using real-world dimensions (calculated from diagonal size + resolution). A 27" monitor appears physically larger than a 15.6" laptop, exactly as on your desk.
  • Drag-and-drop presets โ€” Choose from 18+ built-in monitor presets (laptops, standard monitors, ultrawides, super ultrawides) grouped into collapsible sections, and drag them directly onto the canvas.
  • Custom monitors โ€” Define any monitor by diagonal size, aspect ratio, and resolution. Supports preset resolutions filtered by aspect ratio, or fully custom width/height with an optional Maintain aspect ratio toggle that keeps custom resolutions aligned to the selected ratio. The last several custom monitors you add are kept in a collapsible Custom preset category (stored in your browser only, up to 24 entries, removable from the list). Diagonal is limited to 5"โ€“120"; aspect ratio is limited to 10:1 or less (no ultra-thin "line" monitors). Validation warnings appear when limits are exceeded; Add is disabled until fixed.
  • Monitor rotation โ€” Rotate any monitor 90ยฐ (portrait/landscape) via the โ†ป button or right-click context menu. Resolution is swapped (e.g. 1080ร—1920 when rotated); rotation is saved in saved layouts and reflected in output and the Virtual Layout view.
  • Right-click or kebab menu โ€” Right-click any monitor, or when a monitor is selected click the โ‹ฎ (kebab) button next to the โœ• delete button, for Set Bezels, Rename, Rotate 90ยฐ, Duplicate, and Delete. Bezels are optional per-edge borders (in mm) that extend outward from the display area; they help with alignment and matching real bezels, and Align Assist snaps to outer bezel edges when set. Duplicate copies the monitor (preset/size, bezels, rotation, name with " - Copy 1" appended) and places the copy offset so you can drag it easily.
  • Image placement โ€” Upload a source image and drag/scale it behind the monitor layout. Semi-transparent monitor overlays let you see exactly what portion of the image each screen will display. Vertical images (height > width) default to 6 ft tall; horizontal ones default to 6 ft wide.
  • Smart image recommendations โ€” Calculates the minimum source image resolution needed based on your layout's physical size and the highest-PPI monitor.
  • Accurate output generation โ€” Crops and scales the source image per-monitor at each screen's native PPI, then stitches at each monitor's virtual layout position (side-by-side, stacked, or mixed). Gaps in the layout use a configurable fill: solid color (default black), blurred edge extension, or transparent (PNG only).
  • Preview & download โ€” Live preview of the final stitched wallpaper with one-click PNG/JPEG export.
  • Canvas controls โ€” Scroll to pan, Ctrl+Scroll to zoom (up to 400%), right-click drag to pan. Custom scrollbars, Align Assist guides/snapping, and fit-to-view. Optional inches/cm display for grid, rulers, and dimension labels (toggle in | cm next to zoom, bottom-right). Diagonal sizes remain in inches.
  • Saved Layouts โ€” Save and load monitor layouts (names, positions, rotation, bezels). When the virtual layout has been customized (i.e. is not the default top-aligned arrangement), it is also saved with the layout and restored on load. Saving a layout also stores the current image position when an image is loaded; loading a layout and then uploading an image applies that saved position (with aspect-ratio adaptation). Layouts are stored in your browser (localStorage); you can keep several setups (e.g. desk vs laptop-only) and switch between them. Export downloads all saved layouts as a JSON file; Import uploads a JSON file (same format), validates it (monitor rules: diagonal 5"โ€“120", aspect ratio โ‰ค10:1, etc.), and adds layouts to your list (up to the 24-layout limit). Optional Quick layouts (preloaded in code) appear at the bottom of the Saved Layouts dropdown when configured. The Saved Layouts control sits on the right side of the toolbar, to the left of Share Layout.
  • Image position bookmark โ€” Right-click the source image for Bookmark image position, Apply bookmarked position, and Clear bookmarked position. The bookmark is stored per layout name (or "_default" when no layout is active) so you can pin a preferred image position independently of saving the full layout.
  • Share Layout link โ€” Share encodes the monitor arrangement, optional image position, and when customized, the virtual layout (Windows arrangement pixel positions). Opening a shared link restores the full layout โ€” including any custom virtual arrangement โ€” and image position so the next image you upload is placed where the shared layout had it (with aspect-ratio adaptation). This means a link from Spanright Calibrate with "Include virtual layout" checked will preserve the exact Windows pixel coordinates.
  • Cross-platform โ€” Works in any modern browser. Output can be applied as a spanned wallpaper on Windows (Span/Tile mode), macOS (per-monitor crop), and Linux (varies by DE โ€” GNOME, KDE, feh, swaybg, etc.).
  • Video demo โ€” A โ€œWatch a video demoโ€ link appears in the How It Works dialog and at the end of the Quick Start guide.
  • Responsive layout โ€” On tablet (768pxโ€“1024px) the preset sidebar becomes a slide-out drawer (default collapsed) and the header/toolbar wrap or shorten. On phone (<768px) an informational view explains the app and shows a read-only summary of shared layout URLs, with an option to open the full editor.

Companion Tool: Spanright Calibrate

Spanright Calibrate is a Windows desktop app that visually calibrates the physical arrangement of your multi-monitor setup and exports an accurate layout directly into Spanright. Instead of manually measuring gaps and offsets between your monitors, Calibrate:

  1. Discovers monitors โ€” enumerates all connected displays via Win32 and reads resolutions, pixel positions, and physical panel dimensions from EDID data.
  2. Calibrates physical layout โ€” guides you through an interactive on-screen alignment using colored overlay lines drawn directly on your monitors (scale step + gap step).
  3. Exports to Spanright โ€” generates a configuration matching Spanright's format and can open your calibrated layout directly in the Spanright editor via a compressed URL. With Include virtual layout checked, the exact Windows pixel coordinates are embedded so Spanright reproduces any imprecise offsets (e.g. one monitor at Y=85 instead of Y=0) without manual adjustment.

Download the latest release from the Spanright Calibrate releases page.

Example

Dragon image source from Unsplash.

Physical Layout & Editor Canvas

dragonfire-canvas-zoomed

Virtual Layout

dragonfire-windows

Preview & Export

dragonfire-preview

Result

Spanright's output wallpaper (6400x1080) displayed on a 14" 1080p laptop, a 24" 1080p monitor, and 34" 2560x1080 ultrawide monitor. The total resolution of this setup is (1920 + 1920 + 2560) x (1080) = 6400x1080. And the total aspect ratio of this setup would be (16 + 16 + 21) / (9) = 53:9. The image will only look good when Spanright modifies the image to take account of the physical monitor dimensions and spacing as well. Even though the preview looks disjointed, it actually aligns perfectly when used as the wallpaper.

Standard 53:9 crop of dragon picture: dragonfire-lazy-53-9 Spanright 53:9 crop of dragon picture: spanright-dragonfire-6400x1080-demo-jpg Standard crop set as my wallpaper in my real setup (see the unaligned neck/head): dragonfire-demo-bad-crop Spanright result working in my real setup: dragonfire-demo-real

Directions

1. Add Monitors

Use the sidebar on the left to add monitors to the canvas:

  • Click a preset to add it at a default position
  • Drag a preset directly onto the canvas to place it where you want
  • Collapse/expand preset categories: Use the triangle next to a category header (e.g. Laptops, Standard Monitors, Ultrawides)
  • Custom monitors: Click "+ Custom Monitor" to define a monitor by diagonal size, aspect ratio, and resolution (diagonal 5"โ€“120", aspect ratio โ‰ค 10:1)

2. Arrange Your Layout

Drag monitors on the canvas to match your physical desk arrangement:

  • Position your laptop screen lower-left, your main monitor centered, etc.
  • The canvas uses physical dimensions โ€” a 27" monitor will appear larger than a 13" laptop
  • Right-click a monitor, or select it and click the โ‹ฎ kebab next to the โœ•, for the context menu: Set Bezels, Rename, Rotate 90ยฐ, Duplicate, or Delete. Bezels extend outward from the display area; Align Assist snaps to outer bezel edges when bezels are set.
  • When the source image is selected, use the โ‹ฎ kebab or right-click the image for Size image to fit, Bookmark image position, Apply bookmarked position (when a bookmark exists), Clear bookmarked position, and Remove image.
  • Use Align Assist (canvas menu) for dynamic edge/center alignment guides while dragging monitors
  • Use the โ†ป (rotate) button on a monitor, or Rotate 90ยฐ from the right-click menu, to switch between landscape and portrait
  • Click a monitor and press Delete (or use the context menu) to remove it
  • Press F to fit all monitors in view
  • Use Saved Layouts (right side of toolbar, left of Share Layout) to save or load monitor layouts; layouts are stored in your browser and include bezel settings. Use Export to download all saved layouts as JSON and Import to add layouts from a previously exported JSON file. Quick layouts can be preloaded in src/preloadedLayouts.ts.
  • Windows users: Use Spanright Calibrate to visually measure physical gaps between monitors and import the calibrated layout directly into Spanright.

3. Upload & Position Your Image

  • Drag and drop an image file onto the canvas, or use the upload button in the toolbar
  • The image appears behind the monitors with 70% opacity. If you loaded a layout that had a saved image position, the next image you upload is automatically positioned from that layout (with aspect-ratio adaptation); a toast confirms "Image positioned from saved layout"
  • Drag the image to reposition it
  • Click the image and use the corner handles to resize it
  • Use Size image to fit from the canvas menu (top-right โ‹ฎ) or from the โ‹ฎ kebab / right-click menu on the source image. The canvas menu also has Editor shortcuts โ€” opens a dialog listing all keyboard shortcuts (nudge, undo/redo, fit, pan/zoom, etc.).
  • Right-click the image for Bookmark image position, Apply bookmarked position, or Clear bookmarked position
  • With Align Assist enabled, image drag/resize shows green alignment guides against monitor edges/centers
  • Check the recommended image size banner in the toolbar โ€” green means your image is large enough, yellow/red means it may appear pixelated

4. Virtual Layout (optional)

The Virtual Layout tab (next to Physical Layout) lets you match how your OS sees your displays. The OS arrangement defines the virtual desktop: where the cursor and windows move between monitors (e.g. one display above the other means the cursor crosses at the shared top edge; side-by-side at the vertical edge). Use the Virtual Layout tab if your display order or positions don't match a simple left-to-right layout. This concept applies on all platforms โ€” Windows, macOS, and Linux all maintain their own display arrangement.

The output image has the same bounding box. The OS paints the wallpaper from the top-left; each monitor only displays the rectangle of the image at its position. So any empty area in the image (gaps from different resolutions or offsets) lies outside every monitor's rectangle and is never shown on any screen.

Windows

Open Settings > System > Display to see how Windows arranges your monitors. If the order matches a simple left-to-right layout, you can skip this step.

Warning: Changing Windows Display Settings (position, order, resolution) can get messy. For best results, keep all monitors top-aligned or bottom-aligned in Windows; other alignments may produce unwanted visible empty area in the spanned wallpaper.

macOS

Open System Settings > Displays > Arrange to see your display arrangement. Drag the display rectangles to match your physical layout.

Note: Retina/HiDPI displays report logical pixels (e.g. "looks like 1440ร—900"), not the actual hardware resolution (e.g. 2880ร—1800). When adding monitors in Spanright, always use the actual pixel resolution โ€” otherwise the output will be undersized and blurry on Retina screens.

Linux

Display arrangement depends on your desktop environment:

  • GNOME: Settings > Displays
  • KDE Plasma: System Settings > Display and Monitor > Display Configuration
  • Command line: xrandr --query (X11) or wlr-randr (Wayland/wlroots)

5. Preview & Export

  • The bottom panel shows a live preview of the final stitched wallpaper
  • When the output has empty area (e.g. vertical offsets or different strip heights), use Empty area options to choose how to fill it: Solid color (with color picker and eyedropper to sample from the source image), Blurred edge extension, or Transparent (PNG only)
  • Click Download to save as PNG or JPEG (transparent fill forces PNG)
  • The output dimensions are displayed (e.g., "7280 x 1440")

6. Set Your Wallpaper

Windows

  1. Download the generated image
  2. Open Settings > Personalization > Background
  3. Set "Choose a fit" to Span
  4. Select the downloaded image

Important: Make sure your Windows display arrangement (Settings > Display) matches the physical layout you configured in Spanright.

macOS

macOS has no native "Span" wallpaper mode. To use the Spanright output:

  1. Download the generated image
  2. Open it in Preview or an image editor and crop each monitor's region individually
  3. Open System Settings > Wallpaper (or right-click desktop > Change Wallpaper)
  4. Set each monitor's wallpaper individually using its cropped portion

Tip: Third-party tools like Multi Monitor Wallpaper can automate spanning a single image across all displays.

Linux

Linux wallpaper handling varies by desktop environment:

  • GNOME: Settings > Background, then select the image. Use gsettings set org.gnome.desktop.background picture-options 'spanned' to span across monitors.
  • KDE Plasma: Right-click desktop > Configure Desktop > Wallpaper. Some versions support spanning directly.
  • feh (X11): feh --bg-scale /path/to/wallpaper.png
  • nitrogen (X11): Select the image and choose "Scaled" or "Zoomed" fitting.
  • swaybg (Wayland/Sway): swaybg -i /path/to/wallpaper.png -m fill
  • Hyprpaper (Hyprland): Configure in ~/.config/hypr/hyprpaper.conf

Note: Exact steps vary by distribution and desktop environment. If your tool doesn't support spanning, crop per-monitor regions from the output (like macOS) and set each individually.

Platform Support

Platform Span Mode Display Settings Notes
Windows Built-in (Span or Tile fit mode) Settings > System > Display Best native support โ€” Span mode applies one image across all monitors automatically
macOS No native span mode System Settings > Displays > Arrange Crop per-monitor from the Spanright output and set each individually. Retina displays report logical pixels โ€” use actual hardware resolution in Spanright
Linux Varies by DE GNOME Settings, KDE System Settings, xrandr, etc. GNOME supports spanned picture option. Other DEs/WMs may require per-monitor cropping or tools like feh, nitrogen, or swaybg

Canvas Controls

Action Control
Pan Scroll wheel / Right-click drag
Horizontal pan Shift + Scroll
Zoom Ctrl + Scroll (up to 400%)
Fit view Press F / click Fit button
Select monitor Click on it
Monitor context menu Right-click monitor or select + โ‹ฎ kebab โ†’ Set Bezels, Rename, Rotate 90ยฐ, Duplicate, Delete
Delete monitor Select + Delete or Backspace, or right-click โ†’ Delete
Deselect Escape or click empty space
Rulers & grid in cm **in
Full shortcuts list Canvas menu (top-right โ‹ฎ) โ†’ Editor shortcuts

How It Works

In the app, open How It Works from the header to read a step-by-step explanation and use the โ€œWatch a video demoโ€ link. The Quick Start modal (first-time welcome) also ends with the same link.

Coordinate Spaces

Spanright operates in two coordinate spaces:

  • Physical space (inches) โ€” The canvas grid and layout. 1 canvas unit = 1 physical inch. You can switch the grid and ruler to display in cm (in | cm toggle next to zoom, bottom-right). Dimension labels in the toolbar and preset cards follow the chosen unit; diagonal sizes remain in inches.
  • Pixel space โ€” Each monitor's native resolution. The output image lives here.

PPI Calculation

PPI = sqrt(resolutionXยฒ + resolutionYยฒ) / diagonalInches
physicalWidth = resolutionX / PPI
physicalHeight = resolutionY / PPI

For example, a 27" QHD (2560x1440) monitor:

  • PPI = sqrt(2560ยฒ + 1440ยฒ) / 27 โ‰ˆ 109
  • Physical width = 2560 / 109 โ‰ˆ 23.5"
  • Physical height = 1440 / 109 โ‰ˆ 13.2"

Output Generation

Output matches the virtual desktop bounding box of your virtual layout. For each monitor:

  1. Physical layout determines what portion of the source image that monitor sees.
  2. Virtual layout (pixel positions) determines where the monitor sits in the output image.
  3. The source image is cropped and scaled to the monitor's native resolution (PPI-correct).
  4. Each monitor is drawn at its (pixelX, pixelY) position in the output. This supports side-by-side, stacked vertical, and mixed layouts.
  5. Output dimensions = bounding box of all monitors (maxX โˆ’ minX ร— maxY โˆ’ minY). Any unfilled area uses the chosen fill mode: solid color (default black), blurred edge extension, or transparent (PNG only).

Tech Stack

Project Structure

src/
โ”œโ”€โ”€ App.tsx                    # Main layout
โ”œโ”€โ”€ main.tsx                   # Entry point
โ”œโ”€โ”€ store.tsx                  # Global state (useReducer + Context)
โ”œโ”€โ”€ types.ts                   # TypeScript interfaces
โ”œโ”€โ”€ utils.ts                   # PPI calculations, coordinate math
โ”œโ”€โ”€ presets.ts                 # Monitor preset definitions
โ”œโ”€โ”€ canvasConstants.ts         # Canvas bounds (inches) and center for preloaded layouts
โ”œโ”€โ”€ urlLayout.ts               # Encode/decode layout for share URL (LZ-compressed for shorter links)
โ”œโ”€โ”€ viewportConstants.ts       # Breakpoints for responsive (phone/tablet/desktop)
โ”œโ”€โ”€ useViewport.ts             # Hook for viewport size and isPhone/isTablet/isDesktop
โ”œโ”€โ”€ preloadedLayouts.ts       # Optional quick-layout presets (centered at canvas center)
โ”œโ”€โ”€ icons.tsx                  # Shared SVG icon components
โ”œโ”€โ”€ generateOutput.ts          # Wallpaper stitching logic
โ”œโ”€โ”€ index.css                  # Tailwind imports
โ””โ”€โ”€ components/
    โ”œโ”€โ”€ EditorCanvas.tsx           # Physical layout canvas
    โ”œโ”€โ”€ WindowsArrangementCanvas.tsx  # Virtual layout canvas
    โ”œโ”€โ”€ MonitorPresetsSidebar.tsx   # Preset list + custom form
    โ”œโ”€โ”€ Toolbar.tsx                 # Top toolbar controls
    โ”œโ”€โ”€ PreviewPanel.tsx            # Output preview + download
    โ”œโ”€โ”€ ImageUpload.tsx             # File upload component
    โ”œโ”€โ”€ ConfigManager.tsx            # Saved layouts + quick layouts (save/load)
    โ”œโ”€โ”€ ShareButton.tsx             # Copy share link to clipboard
    โ”œโ”€โ”€ MobileShell.tsx             # Phone informational view (hero, read-only layout, open editor)
    โ”œโ”€โ”€ InfoDialog.tsx              # App info / keyboard shortcuts
    โ””โ”€โ”€ TroubleshootingGuide.tsx     # Wallpaper troubleshooting

scripts/
โ””โ”€โ”€ center-preloaded-layouts.mjs   # Dev script: center layout strings at canvas center (run when adding preloaded layouts)

Running locally

Prerequisites

  • Node.js 18+ (LTS recommended)
  • npm, yarn, or pnpm

Installation

git clone https://github.com/your-username/spanright.git
cd spanright
npm install

Development

npm run dev

Opens at http://localhost:5173 by default.

Build for Production

npm run build

Output is in the dist/ folder, ready for static hosting (e.g., Vercel, Netlify, GitHub Pages).

Preview Production Build

npm run preview

About

Spanright: Multi-Monitor Wallpaper Alignment Tool ๐Ÿ’ป๐Ÿ–ฅ๏ธ๐Ÿ–ฅ๏ธ

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors