VibeCodingStudio's picture
Initial DeepSite commit
1dc93d8 verified
Raw
History Blame Contribute Delete
33.5 kB
<!DOCTYPE html>
<html lang="en" class="scroll-smooth">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Phantom Digital - AI Workspace</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
900: '#1e3a8a',
}
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
body { font-family: 'Inter', sans-serif; }
.glass-effect {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.dark .glass-effect {
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.model-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
}
.chat-bubble {
max-width: 80%;
word-wrap: break-word;
}
.chat-bubble-user {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: white;
border-radius: 18px 18px 4px 18px;
}
.chat-bubble-ai {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 18px 18px 18px 4px;
}
.canvas-grid {
background-image:
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
background-size: 20px 20px;
}
.typing-indicator span {
animation: typing 1.4s infinite;
display: inline-block;
width: 6px;
height: 6px;
background: currentColor;
border-radius: 50%;
margin: 0 2px;
}
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(-6px); }
}
</style>
</head>
<body class="bg-slate-900 text-white h-screen overflow-hidden">
<!-- Header -->
<header class="h-14 border-b border-slate-700 bg-slate-900/95 backdrop-blur-md flex items-center justify-between px-4 z-50">
<div class="flex items-center gap-3">
<div class="w-8 h-8 bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
<i data-lucide="zap" class="text-white w-5 h-5"></i>
</div>
<span class="font-bold text-lg">Phantom Digital</span>
<span class="text-xs bg-blue-600/20 text-blue-400 px-2 py-0.5 rounded-full border border-blue-600/30">Beta</span>
</div>
<div class="flex items-center gap-4">
<button onclick="toggleDarkMode()" class="p-2 rounded-lg hover:bg-slate-800 transition-colors">
<i data-lucide="sun" class="hidden dark:block w-5 h-5 text-yellow-400"></i>
<i data-lucide="moon" class="block dark:hidden w-5 h-5 text-slate-400"></i>
</button>
<a href="index.html" class="flex items-center gap-2 text-sm text-slate-400 hover:text-white transition-colors">
<i data-lucide="home" class="w-4 h-4"></i>
Exit
</a>
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center text-xs font-bold">
JD
</div>
</div>
</header>
<!-- Main Content -->
<div class="flex h-[calc(100vh-56px)]">
<!-- Left Chat Panel (1/3 width) -->
<aside class="w-1/3 min-w-[350px] max-w-[450px] border-r border-slate-700 flex flex-col bg-slate-900">
<!-- Model Selector -->
<div class="p-4 border-b border-slate-700">
<label class="text-xs text-slate-400 uppercase tracking-wider font-semibold mb-2 block">Select AI Model</label>
<div class="relative">
<button onclick="toggleModelMenu()" class="w-full flex items-center justify-between p-3 rounded-xl bg-slate-800 border border-slate-700 hover:border-blue-500 transition-colors text-left">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-gradient-to-br from-green-500 to-emerald-600 flex items-center justify-center" id="currentModelIcon">
<i data-lucide="cpu" class="w-4 h-4 text-white"></i>
</div>
<div>
<div class="font-semibold text-sm" id="currentModelName">Groq Llama 3.3 70B</div>
<div class="text-xs text-slate-400">Fastest inference</div>
</div>
</div>
<i data-lucide="chevron-down" class="w-5 h-5 text-slate-400"></i>
</button>
<!-- Model Dropdown -->
<div id="modelMenu" class="hidden absolute top-full left-0 right-0 mt-2 bg-slate-800 border border-slate-700 rounded-xl shadow-2xl z-50 max-h-96 overflow-y-auto">
<div class="p-2">
<div class="text-xs text-slate-500 uppercase tracking-wider font-semibold px-3 py-2">Free Tier Models</div>
<!-- Groq -->
<button onclick="selectModel('groq', 'Groq Llama 3.3 70B', 'Fastest inference', 'cpu', 'from-green-500 to-emerald-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">Groq Llama 3.3 70B</span>
<span class="text-xs bg-green-500/20 text-green-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">Lightning fast • 800+ tokens/sec</div>
</button>
<button onclick="selectModel('groq-mixtral', 'Groq Mixtral 8x7B', 'Multilingual expert', 'globe', 'from-green-500 to-emerald-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">Groq Mixtral 8x7B</span>
<span class="text-xs bg-green-500/20 text-green-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">MOE architecture • 32k context</div>
</button>
<!-- Cerebras -->
<button onclick="selectModel('cerebras', 'Cerebras Llama 3.1 70B', 'Wafer-scale compute', 'chip', 'from-orange-500 to-red-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">Cerebras Llama 3.1 70B</span>
<span class="text-xs bg-orange-500/20 text-orange-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">Wafer-scale engine • 16K batch</div>
</button>
<!-- SambaNova -->
<button onclick="selectModel('sambanova', 'SambaNova Llama 3.1 405B', 'Enterprise grade', 'server', 'from-purple-500 to-indigo-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">SambaNova Llama 3.1 405B</span>
<span class="text-xs bg-purple-500/20 text-purple-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">DataScale SN40L • RDU architecture</div>
</button>
<!-- DeepSeek -->
<button onclick="selectModel('deepseek', 'DeepSeek V3', 'Reasoning champion', 'brain', 'from-blue-500 to-cyan-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">DeepSeek V3</span>
<span class="text-xs bg-blue-500/20 text-blue-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">671B parameters • MOE</div>
</button>
<button onclick="selectModel('deepseek-chat', 'DeepSeek Chat V2.5', 'Chinese & English', 'message-square', 'from-blue-500 to-cyan-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">DeepSeek Chat V2.5</span>
<span class="text-xs bg-blue-500/20 text-blue-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">Bilingual expert • 128K context</div>
</button>
<!-- Google -->
<button onclick="selectModel('google', 'Gemini 2.0 Flash', 'Multimodal wonder', 'sparkles', 'from-yellow-500 to-orange-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">Gemini 2.0 Flash</span>
<span class="text-xs bg-yellow-500/20 text-yellow-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">Native multimodal • 1M context</div>
</button>
<button onclick="selectModel('google-pro', 'Gemini 1.5 Pro', 'Advanced reasoning', 'star', 'from-yellow-500 to-orange-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">Gemini 1.5 Pro</span>
<span class="text-xs bg-yellow-500/20 text-yellow-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">Complex tasks • 2M context</div>
</button>
<!-- OpenRouter -->
<button onclick="selectModel('openrouter', 'OpenRouter Auto', 'Best model routing', 'route', 'from-pink-500 to-rose-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">OpenRouter Auto</span>
<span class="text-xs bg-pink-500/20 text-pink-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">Intelligent routing • Multiple providers</div>
</button>
<!-- Mistral -->
<button onclick="selectModel('mistral', 'Mistral Large 2', 'European excellence', 'mountain', 'from-teal-500 to-cyan-600')" class="w-full p-3 rounded-lg hover:bg-slate-700 transition-colors text-left group">
<div class="flex items-center justify-between mb-1">
<span class="font-medium text-sm">Mistral Large 2</span>
<span class="text-xs bg-teal-500/20 text-teal-400 px-2 py-0.5 rounded">Free</span>
</div>
<div class="text-xs text-slate-400">123B parameters • Code expert</div>
</button>
</div>
</div>
</div>
</div>
<!-- Chat Messages -->
<div id="chatContainer" class="flex-1 overflow-y-auto p-4 space-y-4">
<!-- Welcome Message -->
<div class="flex gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex-shrink-0 flex items-center justify-center">
<i data-lucide="bot" class="w-4 h-4 text-white"></i>
</div>
<div class="chat-bubble chat-bubble-ai p-4 text-sm leading-relaxed">
<p class="mb-2">👋 Welcome to <strong>Phantom Digital</strong>!</p>
<p class="mb-2">I'm your AI assistant powered by the world's best free-tier models. Select your preferred model from the dropdown above and start creating.</p>
<p>I can help you with:</p>
<ul class="list-disc list-inside mt-1 text-slate-300 space-y-0.5">
<li>Code generation & debugging</li>
<li>Creative writing & content</li>
<li>Data analysis & visualization</li>
<li>Image & video concepts</li>
<li>3D modeling guidance</li>
</ul>
</div>
</div>
</div>
<!-- Typing Indicator (Hidden by default) -->
<div id="typingIndicator" class="hidden px-4 py-2">
<div class="flex gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex-shrink-0 flex items-center justify-center">
<i data-lucide="bot" class="w-4 h-4 text-white"></i>
</div>
<div class="chat-bubble chat-bubble-ai p-3 flex items-center gap-1">
<div class="typing-indicator text-slate-400">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
<!-- Input Area -->
<div class="p-4 border-t border-slate-700 bg-slate-900">
<div class="relative">
<textarea
id="messageInput"
rows="1"
placeholder="Ask anything... (Shift+Enter for new line)"
class="w-full bg-slate-800 border border-slate-700 rounded-xl px-4 py-3 pr-12 text-sm resize-none focus:outline-none focus:border-blue-500 transition-colors max-h-32"
onkeydown="handleKeyDown(event)"
oninput="autoResize(this)"
></textarea>
<button
onclick="sendMessage()"
class="absolute right-2 bottom-2 p-2 bg-blue-600 hover:bg-blue-700 rounded-lg transition-colors text-white"
id="sendButton"
>
<i data-lucide="send" class="w-4 h-4"></i>
</button>
</div>
<div class="flex items-center justify-between mt-2 text-xs text-slate-500">
<span id="modelStatus">Groq • 70B • Free tier</span>
<span>Enter to send</span>
</div>
</div>
</aside>
<!-- Main Canvas Area (2/3 width) -->
<main class="flex-1 relative bg-slate-950 canvas-grid overflow-hidden">
<!-- Canvas Toolbar -->
<div class="absolute top-4 left-4 right-4 flex items-center justify-between z-10">
<div class="flex items-center gap-2 glass-effect rounded-lg p-1.5">
<button onclick="setTool('select')" class="p-2 rounded-md hover:bg-white/10 transition-colors text-blue-400" title="Select" id="tool-select">
<i data-lucide="mouse-pointer-2" class="w-4 h-4"></i>
</button>
<button onclick="setTool('pen')" class="p-2 rounded-md hover:bg-white/10 transition-colors text-slate-400" title="Pen" id="tool-pen">
<i data-lucide="pen-tool" class="w-4 h-4"></i>
</button>
<button onclick="setTool('rectangle')" class="p-2 rounded-md hover:bg-white/10 transition-colors text-slate-400" title="Rectangle" id="tool-rectangle">
<i data-lucide="square" class="w-4 h-4"></i>
</button>
<button onclick="setTool('circle')" class="p-2 rounded-md hover:bg-white/10 transition-colors text-slate-400" title="Circle" id="tool-circle">
<i data-lucide="circle" class="w-4 h-4"></i>
</button>
<button onclick="setTool('text')" class="p-2 rounded-md hover:bg-white/10 transition-colors text-slate-400" title="Text" id="tool-text">
<i data-lucide="type" class="w-4 h-4"></i>
</button>
<div class="w-px h-6 bg-white/20 mx-1"></div>
<button onclick="clearCanvas()" class="p-2 rounded-md hover:bg-red-500/20 transition-colors text-red-400" title="Clear">
<i data-lucide="trash-2" class="w-4 h-4"></i>
</button>
<button onclick="downloadCanvas()" class="p-2 rounded-md hover:bg-white/10 transition-colors text-slate-400" title="Download">
<i data-lucide="download" class="w-4 h-4"></i>
</button>
</div>
<div class="glass-effect rounded-lg px-4 py-2 text-xs font-medium">
<span id="canvasSize">1200 x 800 px</span>
</div>
</div>
<!-- Canvas Container -->
<div id="canvasContainer" class="absolute inset-0 flex items-center justify-center p-8">
<canvas id="mainCanvas" class="bg-white dark:bg-slate-900 rounded-lg shadow-2xl cursor-crosshair" width="1200" height="800"></canvas>
</div>
<!-- Zoom Controls -->
<div class="absolute bottom-4 right-4 glass-effect rounded-lg p-1.5 flex items-center gap-1">
<button onclick="zoomCanvas(-0.1)" class="p-2 rounded-md hover:bg-white/10 transition-colors">
<i data-lucide="minus" class="w-4 h-4"></i>
</button>
<span id="zoomLevel" class="text-xs font-medium w-12 text-center">100%</span>
<button onclick="zoomCanvas(0.1)" class="p-2 rounded-md hover:bg-white/10 transition-colors">
<i data-lucide="plus" class="w-4 h-4"></i>
</button>
</div>
<!-- Help Tooltip -->
<div class="absolute bottom-4 left-4 glass-effect rounded-lg p-3 max-w-xs text-xs text-slate-400">
<p class="font-medium text-white mb-1">Canvas Tips:</p>
<ul class="space-y-1 list-disc list-inside">
<li>Use tools to draw shapes</li>
<li>AI can generate code from your drawings</li>
<li>Export as PNG or SVG</li>
</ul>
</div>
</main>
</div>
<script>
// Initialize Lucide Icons
lucide.createIcons();
// Dark Mode
function toggleDarkMode() {
const html = document.documentElement;
if (html.classList.contains('dark')) {
html.classList.remove('dark');
localStorage.setItem('theme', 'light');
} else {
html.classList.add('dark');
localStorage.setItem('theme', 'dark');
}
}
if (localStorage.getItem('theme') === 'dark' || (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
// Model Selection
let currentModel = 'groq';
function toggleModelMenu() {
const menu = document.getElementById('modelMenu');
menu.classList.toggle('hidden');
}
function selectModel(id, name, desc, icon, gradient) {
currentModel = id;
document.getElementById('currentModelName').textContent = name;
document.getElementById('modelStatus').textContent = name.split(' ')[0] + ' • Free tier';
const iconDiv = document.getElementById('currentModelIcon');
iconDiv.className = `w-8 h-8 rounded-lg bg-gradient-to-br ${gradient} flex items-center justify-center`;
toggleModelMenu();
// Add system message about model change
addSystemMessage(`Switched to ${name}`);
}
function addSystemMessage(text) {
const container = document.getElementById('chatContainer');
const div = document.createElement('div');
div.className = 'flex justify-center';
div.innerHTML = `
<span class="text-xs text-slate-500 bg-slate-800 px-3 py-1 rounded-full">${text}</span>
`;
container.appendChild(div);
container.scrollTop = container.scrollHeight;
}
// Close model menu when clicking outside
document.addEventListener('click', (e) => {
const menu = document.getElementById('modelMenu');
const button = e.target.closest('button');
if (!button || !button.onclick || button.onclick.toString().includes('toggleModelMenu')) {
if (!e.target.closest('#modelMenu')) {
menu.classList.add('hidden');
}
}
});
// Chat Functionality
let isTyping = false;
function handleKeyDown(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
}
function autoResize(textarea) {
textarea.style.height = 'auto';
textarea.style.height = Math.min(textarea.scrollHeight, 128) + 'px';
}
function sendMessage() {
const input = document.getElementById('messageInput');
const message = input.value.trim();
if (!message || isTyping) return;
// Add user message
addMessage(message, 'user');
input.value = '';
input.style.height = 'auto';
// Show typing indicator
showTyping();
// Simulate AI response
setTimeout(() => {
hideTyping();
generateAIResponse(message);
}, 1500 + Math.random() * 1500);
}
function addMessage(text, sender) {
const container = document.getElementById('chatContainer');
const div = document.createElement('div');
div.className = 'flex gap-3 ' + (sender === 'user' ? 'flex-row-reverse' : '');
if (sender === 'user') {
div.innerHTML = `
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex-shrink-0 flex items-center justify-center text-xs font-bold">
You
</div>
<div class="chat-bubble chat-bubble-user p-4 text-sm leading-relaxed">
${escapeHtml(text)}
</div>
`;
} else {
div.innerHTML = `
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex-shrink-0 flex items-center justify-center">
<i data-lucide="bot" class="w-4 h-4 text-white"></i>
</div>
<div class="chat-bubble chat-bubble-ai p-4 text-sm leading-relaxed text-slate-200">
${text}
</div>
`;
}
container.appendChild(div);
container.scrollTop = container.scrollHeight;
lucide.createIcons();
}
function showTyping() {
isTyping = true;
document.getElementById('typingIndicator').classList.remove('hidden');
document.getElementById('chatContainer').scrollTop = document.getElementById('chatContainer').scrollHeight;
}
function hideTyping() {
isTyping = false;
document.getElementById('typingIndicator').classList.add('hidden');
}
function generateAIResponse(userMessage) {
const responses = {
'groq': "Using Groq's ultra-fast inference, I can process that instantly. The Llama 3.3 70B model provides excellent reasoning capabilities with blazing speed.",
'cerebras': "Cerebras' wafer-scale compute allows me to handle complex computations efficiently. Their CS-3 system delivers unmatched training and inference performance.",
'sambanova': "SambaNova's DataScale system with RDU architecture is processing your request using the massive 405B parameter model for maximum accuracy.",
'deepseek': "DeepSeek V3's MoE architecture with 671B parameters is analyzing your request with deep reasoning capabilities.",
'google': "Gemini's native multimodal capabilities allow me to understand and process complex requests across text, code, and visual contexts.",
'default': "I've processed your request using " + currentModel + ". The canvas on the right can be used to visualize concepts or sketch ideas. Would you like me to generate code based on a drawing, or help you create something specific?"
};
const lowerMsg = userMessage.toLowerCase();
let response = responses['default'];
if (lowerMsg.includes('hello') || lowerMsg.includes('hi')) {
response = "Hello! I'm ready to help you create. You can draw on the canvas and I'll analyze it, or ask me to generate code, content, or ideas.";
} else if (lowerMsg.includes('code') || lowerMsg.includes('program')) {
response = "I can generate code in any language. Based on your current project, would you like me to create:\n\n• React/Vue components\n• Python scripts for data analysis\n• CSS animations\n• API endpoints\n• Or something else?\n\nJust describe what you need!";
} else if (lowerMsg.includes('draw') || lowerMsg.includes('canvas')) {
response = "The canvas supports drawing shapes, freehand sketching, and text. Use the toolbar at the top to select tools. I can analyze your drawings and convert them to code or provide feedback!";
} else if (responses[currentModel]) {
response = responses[currentModel] + " How can I assist with your project today?";
}
// Format with markdown-like styling
response = response.replace(/\n/g, '<br>').replace(/•/g, '&bull;');
addMessage(response, 'ai');
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Canvas Functionality
const canvas = document.getElementById('mainCanvas');
const ctx = canvas.getContext('2d');
let currentTool = 'select';
let isDrawing = false;
let startX, startY;
let zoom = 1;
function setTool(tool) {
currentTool = tool;
document.querySelectorAll('[id^="tool-"]').forEach(btn => {
btn.classList.remove('text-blue-400');
btn.classList.add('text-slate-400');
});
document.getElementById('tool-' + tool).classList.remove('text-slate-400');
document.getElementById('tool-' + tool).classList.add('text-blue-400');
canvas.style.cursor = tool === 'select' ? 'default' : 'crosshair';
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function downloadCanvas() {
const link = document.createElement('a');
link.download = 'phantom-canvas-' + Date.now() + '.png';
link.href = canvas.toDataURL();
link.click();
}
function zoomCanvas(delta) {
zoom = Math.max(0.5, Math.min(2, zoom + delta));
document.getElementById('zoomLevel').textContent = Math.round(zoom * 100) + '%';
canvas.style.transform = `scale(${zoom})`;
}
// Canvas Drawing Events
canvas.addEventListener('mousedown', (e) => {
if (currentTool === 'select') return;
isDrawing = true;
const rect = canvas.getBoundingClientRect();
startX = (e.clientX - rect.left) / zoom;
startY = (e.clientY - rect.top) / zoom;
ctx.beginPath();
ctx.strokeStyle = document.documentElement.classList.contains('dark') ? '#60a5fa' : '#2563eb';
ctx.lineWidth = 2;
ctx.fillStyle = document.documentElement.classList.contains('dark') ? 'rgba(96, 165, 250, 0.1)' : 'rgba(37, 99, 235, 0.1)';
});
canvas.addEventListener('mousemove', (e) => {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
const x = (e.clientX - rect.left) / zoom;
const y = (e.clientY - rect.top) / zoom;
if (currentTool === 'pen') {
ctx.lineTo(x, y);
ctx.stroke();
}
});
canvas.addEventListener('mouseup', (e) => {
if (!isDrawing) return;
isDrawing = false;
const rect = canvas.getBoundingClientRect();
const x = (e.clientX - rect.left) / zoom;
const y = (e.clientY - rect.top) / zoom;
if (currentTool === 'rectangle') {
const w = x - startX;
const h = y - startY;
ctx.fillRect(startX, startY, w, h);
ctx.strokeRect(startX, startY, w, h);
} else if (currentTool === 'circle') {
const radius = Math.sqrt(Math.pow(x - startX, 2) + Math.pow(y - startY, 2));
ctx.beginPath();
ctx.arc(startX, startY, radius, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
ctx.closePath();
});
// Initialize canvas with dark mode check
function initCanvas() {
if (document.documentElement.classList.contains('dark')) {
canvas.style.backgroundColor = '#0f172a';
} else {
canvas.style.backgroundColor = '#ffffff';
}
}
initCanvas();
</script>
</body>
</html>