poetry / index.html
salmanarshad's picture
Add 2 files
1c5fe99 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ink Poetry Canvas</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.paper {
background-color: #f8f4e8;
background-image: linear-gradient(#e5e5e5 1px, transparent 1px);
background-size: 100% 32px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
.control-panel {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.handwriting-canvas {
touch-action: none;
background-color: transparent;
}
.btn-primary {
background-color: #2563eb;
transition: all 0.2s ease;
}
.btn-primary:hover {
background-color: #1d4ed8;
}
.btn-primary:disabled {
background-color: #93c5fd;
cursor: not-allowed;
}
.ink-sample {
width: 24px;
height: 24px;
border-radius: 50%;
cursor: pointer;
border: 2px solid transparent;
transition: transform 0.2s;
}
.ink-sample:hover {
transform: scale(1.1);
}
.ink-sample.active {
border-color: #333;
transform: scale(1.1);
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
.loading-dots {
display: inline-block;
margin-left: 4px;
}
.loading-dots span {
display: inline-block;
width: 4px;
height: 4px;
border-radius: 50%;
background-color: currentColor;
margin: 0 1px;
animation: bounce 1.4s infinite ease-in-out both;
}
.loading-dots span:nth-child(1) {
animation-delay: -0.32s;
}
.loading-dots span:nth-child(2) {
animation-delay: -0.16s;
}
@keyframes bounce {
0%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-6px);
}
}
</style>
</head>
<body class="bg-gray-50 min-h-screen flex flex-col items-center py-8 px-4">
<div class="max-w-3xl w-full space-y-6">
<div class="text-center">
<h1 class="text-3xl font-light text-gray-800 mb-1">Ink Poetry Canvas</h1>
<p class="text-gray-600">Experience the art of handwritten poetry</p>
</div>
<div class="control-panel bg-white p-5">
<div class="mb-4">
<label for="poetry-input" class="block text-sm font-medium text-gray-700 mb-2">Your Poetry</label>
<textarea
id="poetry-input"
rows="6"
class="w-full px-4 py-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition"
placeholder="She walks in beauty, like the night
Of cloudless climes and starry skies;
And all that's best of dark and bright
Meet in her aspect and her eyes..."></textarea>
</div>
<div class="flex flex-wrap items-center justify-between gap-4">
<div class="flex items-center gap-3">
<button id="generate-btn" class="btn-primary text-white px-5 py-2 rounded-md flex items-center">
<i class="fas fa-pen-nib mr-2"></i>
<span>Generate</span>
<span class="loading-dots hidden"><span></span><span></span><span></span></span>
</button>
<div class="flex items-center gap-2">
<button id="clear-btn" class="border border-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-50">
<i class="fas fa-eraser"></i>
</button>
</div>
</div>
<div class="flex items-center gap-2">
<span class="text-sm text-gray-600">Ink Color:</span>
<div class="flex items-center gap-1">
<div class="ink-sample active" style="background-color: #2563eb;" data-color="#2563eb"></div>
<div class="ink-sample" style="background-color: #1e293b;" data-color="#1e293b"></div>
<div class="ink-sample" style="background-color: #7c2d12;" data-color="#7c2d12"></div>
<div class="ink-sample" style="background-color: #6b21a8;" data-color="#6b21a8"></div>
</div>
</div>
<button id="download-btn" class="border border-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-50 hidden">
<i class="fas fa-download mr-2"></i>
<span>Save as Image</span>
</button>
</div>
</div>
<div class="relative">
<div class="paper p-8 relative overflow-hidden">
<canvas id="handwriting-canvas" class="handwriting-canvas w-full"></canvas>
<div id="placeholder" class="absolute inset-0 flex items-center justify-center text-gray-400 pointer-events-none">
<div class="text-center">
<i class="fas fa-pen-fancy text-4xl mb-4 opacity-30"></i>
<p>Your handwritten masterpiece will appear here</p>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const poetryInput = document.getElementById('poetry-input');
const generateBtn = document.getElementById('generate-btn');
const downloadBtn = document.getElementById('download-btn');
const clearBtn = document.getElementById('clear-btn');
const canvas = document.getElementById('handwriting-canvas');
const ctx = canvas.getContext('2d');
const placeholder = document.getElementById('placeholder');
const loadingDots = document.querySelector('.loading-dots');
const inkSamples = document.querySelectorAll('.ink-sample');
let currentInkColor = '#2563eb'; // Default blue ink
let isDrawing = false;
let lastX = 0;
let lastY = 0;
let currentLine = [];
let allLines = [];
// Set up canvas
function setupCanvas() {
const container = canvas.parentElement;
const width = container.clientWidth;
const height = 600; // Fixed height for better experience
canvas.width = width;
canvas.height = height;
// Paper texture
ctx.fillStyle = '#f8f4e8';
ctx.fillRect(0, 0, width, height);
}
// Handle ink color selection
inkSamples.forEach(sample => {
sample.addEventListener('click', function() {
inkSamples.forEach(s => s.classList.remove('active'));
this.classList.add('active');
currentInkColor = this.dataset.color;
});
});
// Simulate handwriting with canvas
function drawPoetry() {
const text = poetryInput.value.trim();
if (!text) return;
// Show loading state
generateBtn.disabled = true;
loadingDots.classList.remove('hidden');
// Hide placeholder
placeholder.classList.add('hidden');
// Clear previous drawing
clearCanvas();
// Split text into lines
const lines = text.split('\n');
const lineHeight = 36;
let x = 50;
let y = 60;
// Generate handwriting line by line
let lineIndex = 0;
function drawNextLine() {
if (lineIndex >= lines.length) {
// Drawing complete
generateBtn.disabled = false;
loadingDots.classList.add('hidden');
downloadBtn.classList.remove('hidden');
return;
}
const line = lines[lineIndex];
if (line.trim() === '') {
lineIndex++;
y += lineHeight;
setTimeout(drawNextLine, 100);
return;
}
// For each line, draw each character with slight variations
const words = line.split(' ');
let wordIndex = 0;
function drawNextWord() {
if (wordIndex >= words.length) {
lineIndex++;
y += lineHeight;
setTimeout(drawNextLine, 200);
return;
}
const word = words[wordIndex];
if (word === '') {
wordIndex++;
x += 15; // Space between words
setTimeout(drawNextWord, 0);
return;
}
// Break words longer than 10 characters to simulate realistic line breaking
const chunks = [];
const chunkSize = 5 + Math.floor(Math.random() * 5);
for (let i = 0; i < word.length; i += chunkSize) {
chunks.push(word.substring(i, i + chunkSize));
}
let charIndex = 0;
function drawNextChunk(chunk) {
if (charIndex >= chunk.length) {
wordIndex++;
x += 15; // Space between words
setTimeout(drawNextWord, 0);
return;
}
const char = chunk[charIndex];
// Random variations for natural feel
const sizeVariation = 0.8 + Math.random() * 0.4;
const baseFontSize = 28;
const fontSize = baseFontSize * sizeVariation;
const angle = (Math.random() - 0.5) * 15;
const lean = 0; // Math.random() * 30 - 15;
const inkOpacity = 0.8 + Math.random() * 0.2;
// Draw the character with variations
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle * Math.PI / 180);
ctx.font = `${fontSize}px 'Sacramento', cursive, sans-serif`;
ctx.fillStyle = currentInkColor;
// Simulate ink flow - darker at start of stroke
if (Math.random() > 0.7) {
const gradient = ctx.createLinearGradient(0, -fontSize/2, 0, fontSize/2);
gradient.addColorStop(0, currentInkColor);
gradient.addColorStop(1, lightenColor(currentInkColor, 40));
ctx.fillStyle = gradient;
}
// Add ink blot at random points
if (Math.random() > 0.9) {
ctx.beginPath();
ctx.arc(x, y, 1 + Math.random() * 2, 0, Math.PI * 2);
ctx.fillStyle = currentInkColor;
ctx.fill();
}
ctx.fillText(char, 0, 0);
ctx.restore();
// Some characters might connect (cursive effect)
const charWidth = ctx.measureText(char).width * sizeVariation;
x += charWidth - (charWidth * 0.3 * Math.random());
charIndex++;
// Random delay between characters (20-100ms)
setTimeout(() => drawNextChunk(chunk), 20 + Math.random() * 80);
}
// Start drawing first chunk
drawNextChunk(chunks.shift());
// If there are remaining chunks, move to next line
if (chunks.length > 0) {
x = 50;
y += lineHeight * (0.8 + Math.random() * 0.4);
}
}
// Start drawing first word
drawNextWord();
}
// Start drawing
drawNextLine();
}
// Helper function to lighten/darken colors
function lightenColor(color, percent) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * percent);
const R = (num >> 16) + amt;
const G = (num >> 8 & 0x00FF) + amt;
const B = (num & 0x0000FF) + amt;
return `#${(
0x1000000 +
(R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
(B < 255 ? B < 1 ? 0 : B : 255)
).toString(16).slice(1)}`;
}
// Clear canvas
function clearCanvas() {
ctx.fillStyle = '#f8f4e8';
ctx.fillRect(0, 0, canvas.width, canvas.height);
allLines = [];
placeholder.classList.remove('hidden');
downloadBtn.classList.add('hidden');
}
// Download canvas as image
function downloadCanvas() {
const link = document.createElement('a');
link.download = 'handwritten-poetry.png';
link.href = canvas.toDataURL('image/png');
link.click();
}
// Event listeners
generateBtn.addEventListener('click', drawPoetry);
downloadBtn.addEventListener('click', downloadCanvas);
clearBtn.addEventListener('click', clearCanvas);
// Initialize
setupCanvas();
window.addEventListener('resize', setupCanvas);
// Load sample poem (for demo purposes)
poetryInput.value = `She walks in beauty, like the night
Of cloudless climes and starry skies;
And all that's best of dark and bright
Meet in her aspect and her eyes;
Thus mellowed to that tender light
Which heaven to gaudy day denies.`;
});
</script>
<!-- Load cursive-like font -->
<link href="https://fonts.googleapis.com/css2?family=Sacramento&display=swap" rel="stylesheet">
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=salmanarshad/poetry" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>