How I used Canvas to create diagonal split screenshots in one hour
The Problem
While working on my project docs, I wanted to show light/dark theme comparisons. Not just two screenshots side by sideβI wanted that nice diagonal split effect.
My options:
- Photoshop - tedious to repeat every time
- Online tools - mostly paid, and you have to upload images
- Manual stitching - doesn't look professional
Couldn't find a good free tool, so I built one.
What I Built
Try it: https://tageecc.github.io/theme-merge/
Features:
- Upload two images (light/dark theme)
- Diagonal split with adjustable angle
- Paste from clipboard (Ctrl+V)
- Everything runs locally in your browser
- Free and open source
Tech Stack
Kept it simple:
- HTML5 Canvas for image manipulation
- Vanilla JavaScript (no frameworks)
- GitHub Pages for hosting
Goal was to make something you can just open and use. No install, no signup.
How It Works
The Core Algorithm
The diagonal split uses Canvas's clip() method:
function drawMergedImage() {
// Draw dark theme as base
ctx.drawImage(darkImg, 0, 0);
// Save state
ctx.save();
// Create diagonal clipping path
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(canvas.width, 0);
ctx.lineTo(x1, y1); // rotated endpoints
ctx.lineTo(x2, y2);
ctx.lineTo(0, canvas.height);
ctx.closePath();
// Apply clip and draw light theme
ctx.clip();
ctx.drawImage(lightImg, 0, 0);
ctx.restore();
}
Angle Calculation
My math isn't great, so this part took some trial and error:
const angle = parseFloat(angleSlider.value);
const angleRad = (angle * Math.PI) / 180;
const diagonal = Math.sqrt(canvas.width ** 2 + canvas.height ** 2);
const baseAngle = Math.atan2(canvas.height, canvas.width);
// Calculate rotated diagonal endpoints
const x1 = canvas.width + diagonal * Math.cos(baseAngle + angleRad);
const y1 = -diagonal * Math.sin(baseAngle + angleRad);
const x2 = -diagonal * Math.cos(baseAngle + angleRad);
const y2 = canvas.height + diagonal * Math.sin(baseAngle + angleRad);
Formula looks complicated, but the logic is: base diagonal + angle offset = new diagonal position.
UX Improvements
Started with basic file upload, then added enhancements:
Click left/right to upload
Detect which side of the diagonal was clicked:
function isPointOnLightSide(x, y) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const dx = x - centerX;
const dy = y - centerY;
// Rotate coordinate system
const rotatedX = dx * Math.cos(-angleRad) - dy * Math.sin(-angleRad);
const rotatedY = dx * Math.sin(-angleRad) + dy * Math.cos(-angleRad);
return rotatedY < rotatedX * baseSlope;
}
Clipboard paste
Added this later because saving screenshots then uploading was annoying:
document.addEventListener('paste', (e) => {
const items = e.clipboardData?.items;
for (let i = 0; i < items.length; i++) {
if (items[i].type.startsWith('image/')) {
const file = items[i].getAsFile();
loadImageToSide(file, determineSide());
break;
}
}
});
Now you can screenshot and Ctrl+V directly. Much faster.
Gotchas
Issue 1: Canvas Size
Initially set canvas size via CSS. Images came out blurry. Turns out:
- CSS controls display size
- width/height attributes control actual resolution
Issue 2: Large Image Performance
4K images made pixel-by-pixel calculation slow. Solution: use Canvas's native clip() and let the browser handle it. Much faster.
Issue 3: Mobile Responsiveness
Canvas would overflow on mobile. Added max-width/height CSS:
canvas {
max-width: 90vw;
max-height: 70vh;
width: auto;
height: auto;
}
Scales display while keeping original resolution for download.
Use Cases
Perfect for:
- Documentation - showing feature differences
- Portfolios - displaying design work
- Blog posts - creating comparison images
- READMEs - showcasing project themes
What's Next
Current version works for my needs, but could add:
- Vertical split mode
- More export formats (JPG, WebP)
- Batch processing
- Preset angle templates
Try It Out
Live demo: https://tageecc.github.io/theme-merge/
Source code: https://github.com/tageecc/theme-merge
Took about an hour to build, less than 500 lines of code. Canvas clip() works really well for this.
If you need something similar, feel free to fork and modify. Issues and PRs welcome!
What would you add?
Have ideas for features? Drop a comment below or open an issue on GitHub!
Originally published on my blog. Follow me for more web dev tips and tools.
Tags: #webdev #javascript #canvas #opensource #tools

Top comments (0)