support pasting image data from clipboard

Hunter
Wednesday, April 1st, 2026 at 12:40 PM

readme.md+1-1
script.js+39 

readme.md
31  
32  ### controls
33  
   -- after opening memori in your web browser, drag one or more images from your desktop onto the grid.<br>
34 +- after opening memori in your web browser, drag one or more images from your desktop onto the grid (or press `⌘ + v` to paste image data from your clipboard)<br>
35  <img src="readme_images/drag_n_drop.gif">
36  
37  - click and drag images to move them<br>
script.js
294  	}
295  }
296  
297 +// Track mouse position for paste placement
298 +let lastMouseX = -1;
299 +let lastMouseY = -1;
300 +document.addEventListener('mousemove', (e) => {
301 +	lastMouseX = e.clientX;
302 +	lastMouseY = e.clientY;
303 +});
304 +
305 +// Clipboard paste support
306 +document.addEventListener('paste', async (e) => {
307 +	const items = e.clipboardData?.items;
308 +	if (!items) return;
309 +
310 +	const imageFiles = [];
311 +	for (const item of items) {
312 +		if (item.type.startsWith('image/')) {
313 +			const file = item.getAsFile();
314 +			if (file) imageFiles.push(file);
315 +		}
316 +	}
317 +
318 +	if (imageFiles.length === 0) {
319 +		if (!isUsingSafari) showPopup('No image found in clipboard');
320 +		return;
321 +	}
322 +
323 +	// Use last known mouse position relative to grid, fall back to (0, 0)
324 +	const gridRect = grid.getBoundingClientRect();
325 +	const mouseXInGrid = lastMouseX - gridRect.left;
326 +	const mouseYInGrid = lastMouseY - gridRect.top;
327 +	const isOnGrid = mouseXInGrid >= 0 && mouseYInGrid >= 0 &&
328 +		mouseXInGrid <= gridRect.width && mouseYInGrid <= gridRect.height;
329 +
330 +	const dropX = isOnGrid ? mouseXInGrid : 0;
331 +	const dropY = isOnGrid ? mouseYInGrid : 0;
332 +
333 +	await processAndAddImages(imageFiles, dropX, dropY);
334 +});
335 +
336  // Prevent default drag behavior on entire document
337  document.addEventListener('dragover', (e) => {
338  	e.preventDefault();