A Chrome/Edge Manifest V3 extension that enables smart cross-viewport synchronization for responsive web demos. Show your app on two displays simultaneously—desktop and mobile viewports—with intelligent scroll and navigation synchronization based on semantic content alignment.
When giving live demos of responsive web applications, you often want to show both desktop and mobile views side-by-side on different screens. This extension solves the challenge of keeping both views synchronized as you scroll and navigate, using smart semantic matching instead of naive pixel-based mirroring.
- ✅ Semantic Content Alignment: Matches content blocks between viewports based on structure, text, and position
- ✅ Automatic Navigation Sync: When you click a link in the master tab, the follower navigates too
- ✅ Automatic Scroll Sync: Scroll in the master tab, follower scrolls to equivalent content
- ✅ Intelligent Fallback Strategy: Gracefully degrades from semantic → document order → global progress
- ✅ Zero App Modifications: Works with any web app without code changes
- ✅ Responsive-Aware: Handles different layouts, heights, and content reflow
- ✅ Loop Prevention: Stable synchronization without feedback loops or jitter
- ✅ Master/Follower Mode: Control which viewport drives the sync
- ✅ Service Worker Resilient: Handles Chrome service worker restarts automatically
- ✅ Session Persistence: Settings persist across page refreshes
Perfect for:
- 🎪 Live product demos
- 📱 Responsive design presentations
- 🎓 Teaching responsive web development
- 🎬 Recording demo videos
- 🖥️ Multi-display presentations
The extension consists of three main components:
-
Background Service Worker
- Maintains sync session state (tab pairs, master/follower)
- Routes messages between tabs
- Handles tab lifecycle events
-
Content Script
- Analyzes DOM to extract semantic content blocks
- Creates fingerprints for each block (text, structure, position)
- Detects currently active block in viewport
- Matches blocks between desktop and mobile views
- Applies scroll synchronization
-
Popup UI
- Simple interface for pairing tabs
- Master/follower selection
- Enable/disable sync
- Status monitoring
The extension uses a multi-stage matching process:
Scans the DOM for semantic content blocks using heuristics:
- HTML5 semantic tags (
section,article,main) - Elements with semantic class names (
section,block,container) - Visual structure (headings, images, buttons)
- Minimum size and text content thresholds
Creates a rich fingerprint for each block:
- Text content and headings
- DOM structure and path
- Element counts (images, links, buttons)
- Normalized position in document
- Semantic score
Maps blocks between desktop and mobile using weighted scoring:
- Heading Similarity (30%): Text overlap in headings
- Order Similarity (25%): Relative position in document
- Text Similarity (20%): Body content overlap
- Structure Similarity (15%): Element composition
- Position Similarity (10%): Normalized vertical position
Determines which block is "in focus" based on:
- Viewport visibility ratio
- Distance from viewport center
- Weighted score combining both factors
When the master scrolls:
- Detect active block and calculate relative progress (0-1)
- Find matching block in follower tab
- Calculate equivalent scroll position
- Apply scroll with loop suppression
The system gracefully handles uncertain matches:
- Semantic Match (confidence ≥ 0.4): Use matched block
- Order Fallback: Use document position as proxy
- Global Progress: Use overall page scroll percentage
-
Download the latest release
- Go to Releases
- Download the latest ZIP file
- Extract the ZIP file
-
Load in Chrome/Edge
- Open
chrome://extensions/(oredge://extensions/) - Enable "Developer mode" (toggle in top right)
- Click "Load unpacked"
- Select the extracted
distfolder - Extension icon should appear in your toolbar
- Open
If you want to modify the extension or contribute:
-
Clone the repository
git clone https://github.com/doruit/browser-viewport-sync-extension.git cd browser-viewport-sync-extension -
Install dependencies
npm install
-
Build the extension
npm run build
For development with auto-rebuild:
npm run watch
-
Load in Chrome/Edge
- Open
chrome://extensions/(oredge://extensions/) - Enable "Developer mode"
- Click "Load unpacked"
- Select the
distfolder - Reload extension when you make changes
- Open
-
Open two tabs with the same website
- Tab 1: Desktop view (normal browser width)
- Tab 2: Mobile view (use DevTools device mode)
-
Set up mobile viewport (on Tab 2):
- Press
F12to open DevTools - Click "Toggle device toolbar" icon or press
Cmd+Shift+M/Ctrl+Shift+M - Select a device from the dropdown (e.g., iPhone 14 Pro, Pixel 7)
- You can hide DevTools afterwards
- Press
-
Configure the extension (click the extension icon):
- On Tab 1: Click "Set Desktop"
- On Tab 2: Click "Set Mobile"
- Click "Enable Sync"
-
Start your demo:
- Scroll in the desktop tab → mobile tab follows automatically
- Click a link in desktop → mobile navigates to the same URL
- Everything stays in sync automatically!
-
Prepare two browser tabs
- Tab 1: Desktop viewport (normal width)
- Tab 2: Mobile viewport (DevTools device mode recommended)
-
Open the same URL in both tabs
-
Open the extension popup (click the extension icon)
-
Assign tabs
- In desktop tab: Click "Set Desktop"
- In mobile tab: Click "Set Mobile"
-
Choose master (optional)
- Default: Desktop is master
- Or click "Mobile is Master" to scroll from mobile
-
Enable sync
- Click "Enable Sync"
- Both tabs will automatically align to the same URL and scroll position
-
Give your demo
- Scroll in the master tab
- Navigate by clicking links
- The follower tab automatically follows
- Set as Desktop/Mobile: Assign current tab to a viewport role
- Desktop/Mobile is Master: Choose which viewport drives the sync
- Enable/Disable Sync: Turn synchronization on/off
- Refresh Page Models: Rebuild block analysis (use after navigation or major DOM changes)
- Use semantic HTML: The algorithm works best with
<section>,<article>, etc. - Include headings: Headings are strong signals for block matching
- Distinct content blocks: Clear visual separation helps block detection
- Refresh on route changes: Click "Refresh Page Models" after navigation
- Test before demo: Try scrolling through the content once to verify sync quality
The extension is designed to handle:
- ✅ Different viewport heights
- ✅ Responsive reordering (grid → stacked list)
- ✅ Blocks that appear/disappear on mobile
- ✅ Lazy-loaded images changing height
- ✅ Sticky headers
- ✅ Single-page app route changes (manual refresh needed)
- ✅ Different scroll containers
- ✅ Rapid scrolling
- ✅ Low-confidence matching scenarios
- Single pair only: Only one desktop/mobile pair can be synced at a time
- Manual model refresh: Doesn't auto-detect route changes (click "Refresh Models" after navigation)
- Heuristic-based: Matching quality depends on page structure
- Same URL required: Both tabs must be on the same application
- No bidirectional sync: Only master → follower (not both directions)
- Auto-detect route changes via History API
- Multiple sync pairs
- Bidirectional sync option
- Machine learning for block matching
- Custom block selectors per domain
- Sync state persistence across sessions
- Performance profiling dashboard
- Confidence threshold tuning UI
present-on-multiple-displays/
├── src/ # Extension source code
│ ├── background/ # Service worker
│ ├── content/ # Content scripts
│ ├── popup/ # Extension popup
│ └── shared/ # Shared utilities
├── public/ # Static assets (manifest, icons)
├── docs/ # Detailed documentation
├── scripts/ # Build and utility scripts
├── examples/ # Example pages for testing
├── dist/ # Build output (generated)
├── package.json
├── tsconfig.json
└── README.md
# Clean build
npm run clean
npm run build
# Development mode with watch
npm run watchThe extension includes comprehensive logging:
- Background: Check the service worker console
- Content Script: Check the page console
- Popup: Right-click popup → Inspect
All logs are prefixed with their source ([Background], [Content], [SyncEngine], etc.)
Edit src/shared/constants.ts to adjust:
- Block detection thresholds
- Matching weights
- Confidence thresholds
- Scroll throttling
- Loop suppression timings
Popup → Background: SET_DESKTOP_TAB, ENABLE_SYNC, etc.
Background → Content: BUILD_PAGE_MODEL, APPLY_SYNC
Content → Background: SCROLL_EVENT, PAGE_MODEL_BUILT
Background → Content (follower): APPLY_SYNC
- User scrolls in master tab
- Content script detects scroll event (throttled)
- Calculates active block and relative progress
- Sends
SCROLL_EVENTto background - Background verifies master/follower roles
- Background forwards
APPLY_SYNCto follower tab - Follower content script:
- Matches source block to local block
- Calculates target scroll position
- Applies scroll with loop suppression
- Block extraction runs once per page load (and on manual refresh)
- Scroll events are throttled to 100ms
- Block matching uses cached fingerprints
- Maximum 100 blocks per page
- Loop suppression prevents feedback cycles
- Check both tabs are assigned (desktop and mobile)
- Verify sync is enabled (green status badge)
- Check master is set correctly
- Try clicking "Refresh Page Models"
- Inspect page structure (does it have semantic blocks?)
- Check for headings in content blocks
- Try adjusting confidence thresholds in constants.ts
- Consider adding more specific block selectors
- Check scroll throttle value (increase if needed)
- Verify loop suppression is working
- Check for nested scroll containers
This is an MVP implementation. Areas for improvement:
- Better block detection heuristics
- Machine learning for matching
- Performance optimizations
- UI enhancements
- Test coverage
MIT
Built with TypeScript, esbuild, and Chrome Extension Manifest V3.
