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.
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.
- 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.
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:
- Discovers monitors โ enumerates all connected displays via Win32 and reads resolutions, pixel positions, and physical panel dimensions from EDID data.
- Calibrates physical layout โ guides you through an interactive on-screen alignment using colored overlay lines drawn directly on your monitors (scale step + gap step).
- 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.
Dragon image source from Unsplash.
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:
Spanright 53:9 crop of dragon picture:
Standard crop set as my wallpaper in my real setup (see the unaligned neck/head):
Spanright result working in my real setup:

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)
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.
- 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
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.
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.
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.
Display arrangement depends on your desktop environment:
- GNOME: Settings > Displays
- KDE Plasma: System Settings > Display and Monitor > Display Configuration
- Command line:
xrandr --query(X11) orwlr-randr(Wayland/wlroots)
- 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")
- Download the generated image
- Open Settings > Personalization > Background
- Set "Choose a fit" to Span
- Select the downloaded image
Important: Make sure your Windows display arrangement (Settings > Display) matches the physical layout you configured in Spanright.
macOS has no native "Span" wallpaper mode. To use the Spanright output:
- Download the generated image
- Open it in Preview or an image editor and crop each monitor's region individually
- Open System Settings > Wallpaper (or right-click desktop > Change Wallpaper)
- 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 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 | 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 |
| 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 |
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.
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 = 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 matches the virtual desktop bounding box of your virtual layout. For each monitor:
- Physical layout determines what portion of the source image that monitor sees.
- Virtual layout (pixel positions) determines where the monitor sits in the output image.
- The source image is cropped and scaled to the monitor's native resolution (PPI-correct).
- Each monitor is drawn at its
(pixelX, pixelY)position in the output. This supports side-by-side, stacked vertical, and mixed layouts. - 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).
- React 19 + TypeScript
- Konva / react-konva for canvas rendering
- Tailwind CSS 4 for styling
- Vite 7 for build tooling
- No backend โ all processing is client-side
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)
- Node.js 18+ (LTS recommended)
- npm, yarn, or pnpm
git clone https://github.com/your-username/spanright.git
cd spanright
npm installnpm run devOpens at http://localhost:5173 by default.
npm run buildOutput is in the dist/ folder, ready for static hosting (e.g., Vercel, Netlify, GitHub Pages).
npm run preview