Collaborative-pixel-art/scripts/start-dev.js
martin 3ce5a97422 Modernize collaborative pixel art platform to production-ready architecture
Major refactor from simple HTML/JS app to modern full-stack TypeScript application:

## Architecture Changes
- Migrated to monorepo structure with workspaces (backend, frontend, shared)
- Backend: Node.js + Express + TypeScript + Socket.IO
- Frontend: Next.js 15.5 + React 19 + TypeScript + Tailwind CSS
- Shared: Common types and utilities across packages

## Key Features Implemented
- Real-time WebSocket collaboration via Socket.IO
- Virtual canvas with chunked loading for performance
- Modern UI with dark mode and responsive design
- Mock database system for easy development (Redis/PostgreSQL compatible)
- Comprehensive error handling and rate limiting
- User presence and cursor tracking
- Infinite canvas support with zoom/pan controls

## Performance Optimizations
- Canvas virtualization - only renders visible viewport
- Chunked pixel data loading (64x64 pixel chunks)
- Optimized WebSocket protocol
- Memory-efficient state management with Zustand

## Development Experience
- Full TypeScript support across all packages
- Hot reload for both frontend and backend
- Docker support for production deployment
- Comprehensive linting and formatting
- Automated development server startup

## Fixed Issues
- Corrected start script paths
- Updated environment configuration
- Fixed ESLint configuration issues
- Ensured all dependencies are properly installed
- Verified build process works correctly
2025-08-22 19:28:05 +02:00

128 lines
No EOL
3.4 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
const { spawn, exec } = require('child_process');
const path = require('path');
const util = require('util');
const execPromise = util.promisify(exec);
console.log('🎨 Starting GaPlace Development Environment...\n');
// Function to check if port is in use
async function isPortInUse(port) {
try {
const { stdout } = await execPromise(`netstat -ano | findstr :${port}`);
return stdout.trim().length > 0;
} catch (error) {
return false;
}
}
// Function to kill process on port
async function killPort(port) {
try {
await execPromise(`npx kill-port ${port}`);
console.log(`✅ Cleared port ${port}`);
} catch (error) {
console.log(` Port ${port} was already free`);
}
}
// Function to start a process and handle output
function startProcess(name, command, args, cwd, color) {
console.log(`${color}[${name}]${'\x1b[0m'} Starting: ${command} ${args.join(' ')}`);
const isWindows = process.platform === 'win32';
const proc = spawn(command, args, {
cwd,
stdio: 'pipe',
shell: true,
windowsHide: true
});
proc.stdout.on('data', (data) => {
const lines = data.toString().split('\n').filter(line => line.trim());
lines.forEach(line => {
console.log(`${color}[${name}]${'\x1b[0m'} ${line}`);
});
});
proc.stderr.on('data', (data) => {
const lines = data.toString().split('\n').filter(line => line.trim());
lines.forEach(line => {
console.log(`${color}[${name}]${'\x1b[0m'} ${line}`);
});
});
proc.on('close', (code) => {
if (code !== 0) {
console.log(`${color}[${name}]${'\x1b[0m'} ❌ Process exited with code ${code}`);
}
});
proc.on('error', (error) => {
console.log(`${color}[${name}]${'\x1b[0m'} ❌ Error: ${error.message}`);
});
return proc;
}
async function startDevelopment() {
try {
// Clear ports first
console.log('🧹 Clearing ports...');
await killPort(3001);
await killPort(3000);
// Wait a moment for ports to be fully cleared
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('🔧 Starting backend server...');
const backend = startProcess(
'Backend',
'npm',
['run', 'dev'],
path.join(__dirname, '..', 'backend'),
'\x1b[34m' // Blue
);
// Wait for backend to start
await new Promise(resolve => setTimeout(resolve, 3000));
console.log('🎨 Starting frontend server...');
const frontend = startProcess(
'Frontend',
'npm',
['run', 'dev'],
path.join(__dirname, '..', 'frontend'),
'\x1b[32m' // Green
);
console.log('\n📱 Frontend: http://localhost:3000');
console.log('🔌 Backend: http://localhost:3001');
console.log('🩺 Health Check: http://localhost:3001/health');
console.log('💡 Press Ctrl+C to stop all servers\n');
// Handle Ctrl+C
process.on('SIGINT', async () => {
console.log('\n🛑 Shutting down development servers...');
backend.kill('SIGTERM');
frontend.kill('SIGTERM');
// Wait a moment then force kill if needed
setTimeout(() => {
backend.kill('SIGKILL');
frontend.kill('SIGKILL');
process.exit(0);
}, 2000);
});
// Keep the script running
setInterval(() => {}, 1000);
} catch (error) {
console.error('❌ Failed to start development environment:', error.message);
process.exit(1);
}
}
startDevelopment();