import React, { useRef, useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { ArrowLeftIcon, TrashIcon, DownloadSimpleIcon, PaintBrushIcon, PaletteIcon, } from '@phosphor-icons/react'; import Seo from '../../components/Seo'; import BreadcrumbTitle from '../../components/BreadcrumbTitle'; const PaperInkPage = () => { const canvasRef = useRef(null); const [isDrawing, setIsDrawing] = useState(false); const [lastPoint, setLastPoint] = useState(null); const [brushColor, setBrushColor] = useState('#1a1a1a'); useEffect(() => { const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); // Set canvas size const resize = () => { const tempImage = ctx.getImageData(0, 0, canvas.width, canvas.height); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx.putImageData(tempImage, 0, 0); }; window.addEventListener('resize', resize); resize(); return () => window.removeEventListener('resize', resize); }, []); const getDistance = (p1, p2) => Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)); const startDrawing = (e) => { const rect = canvasRef.current.getBoundingClientRect(); const point = { x: (e.clientX || e.touches[0].clientX) - rect.left, y: (e.clientY || e.touches[0].clientY) - rect.top, }; setIsDrawing(true); setLastPoint(point); }; const draw = (e) => { if (!isDrawing) return; const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); const rect = canvas.getBoundingClientRect(); const currentPoint = { x: (e.clientX || (e.touches && e.touches[0].clientX)) - rect.left, y: (e.clientY || (e.touches && e.touches[0].clientY)) - rect.top, }; if (lastPoint) { const dist = getDistance(lastPoint, currentPoint); const speed = Math.max(0.1, Math.min(dist / 10, 10)); // Dynamic thickness based on speed (Inverted for ink look: faster = thinner) const thickness = Math.max(1, 15 - speed); ctx.beginPath(); ctx.moveTo(lastPoint.x, lastPoint.y); ctx.lineTo(currentPoint.x, currentPoint.y); ctx.strokeStyle = brushColor; ctx.lineWidth = thickness; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; // Add subtle "ink" blur ctx.shadowBlur = thickness * 0.2; ctx.shadowColor = brushColor; ctx.stroke(); // Bleed effect (random small dots when moving slow) if (speed < 2 && Math.random() > 0.8) { ctx.beginPath(); ctx.arc( currentPoint.x + (Math.random() - 0.5) * 5, currentPoint.y + (Math.random() - 0.5) * 5, Math.random() * 2, 0, Math.PI * 2, ); ctx.fillStyle = brushColor; ctx.fill(); } } setLastPoint(currentPoint); }; const stopDrawing = () => { setIsDrawing(false); setLastPoint(null); }; const clearCanvas = () => { const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); }; const downloadImage = () => { const canvas = canvasRef.current; const link = document.createElement('a'); link.download = 'ink-sketch.png'; link.href = canvas.toDataURL(); link.click(); }; return (
{/* Rice Paper Texture Overlay */}
{/* Canvas */} {/* UI Controls */}
EXIT
{['#1a1a1a', '#2c3e50', '#c0392b', '#27ae60', '#2980b9'].map((c) => (
{/* Floating Instructions */}

Paper & Ink

Swift strokes are narrow, slow ones are deep.

{/* Visual Indicator of current brush */}
Flow State Active
); }; export default PaperInkPage;