A collaborative pixel art platform built with Lightning Network payments. Create, share, and monetize pixel art on a decentralized canvas.
- Collaborative Canvas: Real-time pixel art creation with multiple users
- Lightning Network Integration: Pay-per-pixel with instant Bitcoin payments via NakaPay
- QR Code Payments: Scan QR codes with any Lightning wallet
- WebSocket Real-time Updates: Live canvas updates for all connected users
- Professional Payment UI: Polished modal with invoice display and error handling
- Responsive Design: Works on desktop and mobile devices
- Development Ready: Hot reload, TypeScript, and modern tooling
- Comprehensive Testing: TDD approach with extensive test coverage
A collaborative pixel art platform built with Lightning Network payments. Create, share, and monetize pixel art on a decentralized canvas.
- Collaborative Canvas: Real-time pixel art creation with multiple users
- Lightning Network Integration: Pay-per-pixel with instant Bitcoin payments via NakaPay
- QR Code Payments: Scan QR codes with any Lightning wallet
- WebSocket Real-time Updates: Live canvas updates for all connected users
- Professional Payment UI: Polished modal with invoice display and error handling
- Responsive Design: Works on desktop and mobile devices
- Development Ready: Hot reload, TypeScript, and modern tooling
- Comprehensive Testing: TDD approach with extensive test coverage
- Framework: Node.js + Express + TypeScript
- Real-time: Socket.IO for WebSocket connections
- Database: SQLite with better-sqlite3
- Payments: Lightning Network integration via Nakapay
- Development: Hot reload with tsx
- Framework: Next.js + React 19 + TypeScript
- State Management: Zustand
- Real-time: Socket.IO client
- Styling: Tailwind CSS + shadcn/ui
- Development: Next.js development server with hot reload
- Node.js 22+ (recommended, see .nvmrc)
- pnpm (recommended) or npm
- Git
-
Clone the repository
git clone <your-repo-url> cd lnpixels
-
Install dependencies
pnpm install
-
Start development servers
# Start both API and App servers pnpm run dev:all # Or start individually: pnpm run dev:api # API server on port 3000 pnpm run dev:app # App server on port 3002
-
Access the application
- API: http://localhost:3000
- App: http://localhost:3002
lnpixels/
βββ api/ # Backend API server
β βββ src/
β β βββ server.ts # Main Express server
β β βββ database.ts # SQLite database setup
β β βββ payments.ts # Lightning payment integration
β β βββ pricing.ts # Pixel pricing logic
β β βββ routes.ts # API route handlers
β β βββ socket.ts # WebSocket server setup
β βββ test/ # API tests
β βββ package.json
β βββ tsconfig.json
βββ lnpixels-app/ # Frontend Next.js app
β βββ app/ # Next.js app router
β β βββ globals.css # Global styles
β β βββ layout.tsx # Root layout
β β βββ page.tsx # Home page
β βββ components/ # React components
β β βββ pixel-canvas.tsx # Main canvas component
β β βββ payment-modal.tsx # Payment interface
β β βββ color-picker.tsx # Color selection
β β βββ ui/ # shadcn/ui components
β βββ hooks/ # Custom React hooks
β βββ lib/ # Utility functions
β βββ package.json
β βββ next.config.mjs # Next.js configuration
β βββ tsconfig.json
βββ ops/ # Operations and docs
β βββ design.md # Project design document
βββ ecosystem.config.example.js # PM2 process manager config
βββ README.md # This file
# Install all dependencies
pnpm install
# Start development servers
pnpm run dev:all # Start both API and App
pnpm run dev:api # Start API server only
pnpm run dev:app # Start App server only
# Run tests
pnpm run test # Run all tests
# Build for production
pnpm run build # Build both API and App
The application uses development defaults and doesn't require additional environment variables for basic functionality.
# Run all tests
pnpm run test
# Run API tests only
cd api && pnpm run test
# Run App tests only
cd lnpixels-app && pnpm run test
# Run tests in watch mode
pnpm run test -- --watch
# Run tests with coverage
cd api && pnpm run test -- --coverage
cd lnpixels-app && pnpm run test:coverage
- API Tests: β Complete coverage for pricing, validation, and payment flows
- App Tests: β PaymentModal, ColorPicker, Canvas integration, and component tests
- Integration Tests: β End-to-end payment flows and WebSocket communication
- TDD Approach: β All features developed with red-green-refactor cycles
The project includes PM2 configuration for easy deployment:
# Install PM2 globally
npm install -g pm2
# Start applications with PM2
pm2 start ecosystem.config.example.js
# Save PM2 configuration for auto-restart
pm2 save
# View application status
pm2 status
# View logs
pm2 logs
-
Build the applications
pnpm run build
-
Configure nginx (see nginx configuration in ecosystem.config.example.js)
-
Set up SSL (using Let's Encrypt/Certbot)
-
Configure domain and DNS
The ecosystem.config.example.js
file contains:
- API server on port 3000
- App server on port 3002
- Auto-restart on file changes
- Memory and CPU monitoring
The nginx configuration provides:
- Reverse proxy for both API and Web
- WebSocket support for Socket.IO
- SSL termination
- Gzip compression
- Security headers
The LNPixels API provides RESTful endpoints for canvas management, payment processing, and real-time updates via WebSocket.
http://localhost:3000/api
Currently, no authentication is required for read operations. Payment operations are handled via Lightning Network invoices.
Retrieve pixel data within a specified rectangle area.
Endpoint: GET /api/pixels
Query Parameters:
x1
(number, required): Left coordinate of rectangley1
(number, required): Top coordinate of rectanglex2
(number, required): Right coordinate of rectangley2
(number, required): Bottom coordinate of rectangle
Example Request:
curl "https://ln.pixel.xx.kg/api/pixels?x1=0&y1=0&x2=10&y2=10"
Response (200 OK):
{
"pixels": [
{"x": 0, "y": 0, "color": "#FF0000", "type": "color", "letter": null},
{"x": 1, "y": 0, "color": "#000000", "type": "basic", "letter": null},
{"x": 2, "y": 0, "color": "#FFFFFF", "type": "letter", "letter": "P"}
],
"total": 3
}
Error Responses:
400 Bad Request
: Invalid coordinates500 Internal Server Error
: Database error
Retrieve API version and available endpoints.
Endpoint: GET /api/
Example Request:
curl "https://ln.pixel.xx.kg/api/"
Response (200 OK):
{
"name": "LNPixels API",
"version": "1.0.0",
"endpoints": [
"GET /api/",
"GET /api/pixels",
"POST /api/invoices",
"POST /api/invoices/bulk",
"GET /api/activity",
"GET /api/verify/:eventId",
"POST /api/payments/webhook"
]
}
Generate a Lightning invoice for purchasing a single pixel.
Endpoint: POST /api/invoices
Request Body:
{
"x": 100,
"y": 50,
"color": "#FF5733",
"type": "color"
}
Parameters:
x
(number, required): X coordinate (0-999)y
(number, required): Y coordinate (0-999)color
(string, required): Hex color code (#RRGGBB)type
(string, required): Pixel type ("basic", "color", or "letter")
Example Request:
curl -X POST "https://ln.pixel.xx.kg/api/invoices" \
-H "Content-Type: application/json" \
-d '{"x": 100, "y": 50, "color": "#FF5733", "type": "color"}'
Response (200 OK):
{
"invoice": "lnbc10n1pjg6q8hpp5...",
"amount": 10,
"description": "Purchase color pixel at (100, 50)",
"payment_hash": "a1b2c3d4...",
"expires_at": 1640995200
}
Generate a Lightning invoice for purchasing multiple pixels in a rectangle.
Endpoint: POST /api/invoices/bulk
Request Body:
{
"x1": 100,
"y1": 50,
"x2": 110,
"y2": 60,
"color": "#FF5733",
"type": "color"
}
Example Request:
curl -X POST "https://ln.pixel.xx.kg/api/invoices/bulk" \
-H "Content-Type: application/json" \
-d '{"x1": 100, "y1": 50, "x2": 110, "y2": 60, "color": "#FF5733", "type": "color"}'
Response (200 OK):
{
"invoice": "lnbc100n1pjg7q9hpp5...",
"amount": 100,
"pixel_count": 121,
"description": "Purchase 121 color pixels in rectangle (100,50) to (110,60)",
"payment_hash": "e5f6g7h8...",
"expires_at": 1640995200
}
Handle payment confirmations from Lightning Network.
Endpoint: POST /api/payments/webhook
Headers:
X-Nakapay-Signature
: Webhook signature for verificationContent-Type
: application/json
Request Body:
{
"payment_hash": "a1b2c3d4...",
"amount": 10,
"status": "completed",
"timestamp": 1640995200
}
Response (200 OK):
{
"status": "processed",
"pixels_updated": 1
}
Retrieve recent canvas activity and purchases.
Endpoint: GET /api/activity
Query Parameters:
limit
(number, optional): Number of activities to return (default: 50, max: 100)offset
(number, optional): Pagination offset (default: 0)
Example Request:
curl "https://ln.pixel.xx.kg/api/activity?limit=10"
Response (200 OK):
{
"activities": [
{
"id": 12345,
"type": "pixel_purchase",
"x": 100,
"y": 50,
"color": "#FF5733",
"pixel_type": "color",
"amount": 10,
"timestamp": 1640995200,
"payment_hash": "a1b2c3d4..."
},
{
"id": 12344,
"type": "bulk_purchase",
"x1": 200,
"y1": 100,
"x2": 205,
"y2": 105,
"color": "#00FF00",
"pixel_type": "basic",
"pixel_count": 36,
"amount": 36,
"timestamp": 1640995100,
"payment_hash": "e5f6g7h8..."
}
],
"total": 2
}
Verify the authenticity of a Nostr event related to canvas activity.
Endpoint: GET /api/verify/:eventId
Path Parameters:
eventId
(string, required): Nostr event ID to verify
Example Request:
curl "https://ln.pixel.xx.kg/api/verify/a1b2c3d4e5f6..."
Response (200 OK):
{
"verified": true,
"event": {
"id": "a1b2c3d4e5f6...",
"pubkey": "npub1...",
"created_at": 1640995200,
"kind": 1,
"tags": [],
"content": "Just purchased pixels on LNPixels!",
"sig": "signature..."
}
}
The API also provides real-time updates via WebSocket for live canvas synchronization.
WebSocket URL: ws://localhost:3000
Connection Example:
const socket = io('https://ln.pixel.xx.kg');
// Listen for pixel updates
socket.on('pixelUpdate', (data) => {
console.log('Pixel updated:', data);
// data: { x: 100, y: 50, color: '#FF5733', type: 'color' }
});
// Listen for bulk updates
socket.on('bulkUpdate', (data) => {
console.log('Bulk pixels updated:', data);
// data: { pixels: [...], payment_hash: '...' }
});
All API endpoints return standardized error responses:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid pixel coordinates",
"details": {
"x": "Must be between 0 and 999",
"y": "Must be between 0 and 999"
}
}
}
Common Error Codes:
VALIDATION_ERROR
: Invalid request parametersPAYMENT_ERROR
: Payment processing failedDATABASE_ERROR
: Internal database errorRATE_LIMITED
: Too many requestsNOT_FOUND
: Resource not found
- Canvas Queries: 100 requests per minute per IP
- Invoice Creation: 10 requests per minute per IP
- Activity Feed: 30 requests per minute per IP
- Verification: 50 requests per minute per IP
Rate limit headers are included in responses:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1640995260
- Canvas: Interactive pixel art canvas with pan/zoom
- PurchasePanel: Pixel selection and pricing interface
- PaymentModal: Professional payment interface with QR codes
- ActivityFeed: Real-time activity updates
- ColorPicker: Advanced color selection with presets
- MobileTabs: Mobile-responsive navigation
- Canvas State: Current pixel data and user interactions
- Payment State: Invoice management and payment flow
- WebSocket State: Real-time updates and connections
- Selection State: Rectangle and pixel selection management
- Select Pixels: Use rectangle selection or click individual pixels
- Choose Pixel Type: Basic (1 sat), Color (10 sats), or Letter (100 sats)
- Click "Purchase Pixels": Opens professional payment modal
- Scan QR Code: Use any Lightning wallet to scan and pay
- Automatic Confirmation: Payment confirmed via webhook, pixels updated in real-time
- Lightning Network: Instant Bitcoin payments via NakaPay
- QR Codes: Easy wallet integration with scannable codes
- Invoice Display: Copyable Lightning invoice text
- Real-time Status: Live payment confirmation updates
- Error Handling: Comprehensive error messages and retry options
- Input Validation: All user inputs are validated and sanitized
- Payment Security: Lightning Network payment verification via NakaPay
- API Key Protection: Server-side only API key handling
- Webhook Verification: Payment confirmation signature validation
- WebSocket Security: Connection limits and rate limiting
- CORS: Proper cross-origin resource sharing configuration
- Payment Integration: Full Lightning Network support with NakaPay
- Real-time Updates: WebSocket communication for live canvas updates
- Professional UI: Polished payment modal with QR codes and error handling
- Mobile Responsive: Works seamlessly on all device sizes
- Comprehensive Testing: Extensive test coverage with TDD approach
- Security: Payment verification and input sanitization
- Performance: Optimized for real-time collaboration
- Backend: Node.js + Express + TypeScript + Socket.IO + SQLite
- Frontend: Next.js + React 19 + TypeScript + Tailwind CSS + shadcn/ui
- Payments: Lightning Network via NakaPay SDK
- Real-time: Socket.IO for WebSocket communication
- Testing: Vitest for both backend and frontend
- Package Management: pnpm workspaces for monorepo management
- β Updated Documentation: Fixed project structure and technology references
- β Next.js Migration: Frontend migrated from Vite to Next.js with React 19
- β Monorepo Setup: Proper pnpm workspace configuration
- β Enhanced API Docs: Comprehensive API documentation with examples
- β Deployment Config: Updated PM2 configuration for current structure
- Code Splitting: Dynamic imports for better loading
- Caching: Browser caching for static assets
- Compression: Gzip compression for all responses
- WebSocket Optimization: Efficient real-time updates
Happy-DOM Dependency Conflicts
# If you encounter happy-dom issues in web tests
cd web
rm -rf node_modules
npm install
# Alternative: Use jsdom for testing
npm install --save-dev jsdom
# Update vitest.config.js to use jsdom instead of happy-dom
WebSocket Connection Issues
# Test WebSocket connectivity
curl -I http://localhost:3000
curl -I http://localhost:3002
# Check if ports are available
netstat -an | findstr :3000
netstat -an | findstr :3002
Database Connection Issues
# Check SQLite database
ls -la api/*.db
# Reset database if corrupted
cd api
rm -f *.db
npm run migrate # If migration script exists
Payment Integration Issues
# Test NakaPay API connection
curl -X GET "https://api.nakapay.app/health"
# Verify webhook endpoint
curl -X POST http://localhost:3000/api/payments/webhook \
-H "Content-Type: application/json" \
-d '{"test": "webhook"}'
Build Failures
# Clear all caches
pnpm run clean
rm -rf node_modules api/node_modules lnpixels-app/node_modules
# Reinstall dependencies
pnpm install
# Build step by step
cd api && pnpm run build
cd ../lnpixels-app && pnpm run build
PM2 Deployment Issues
# Check PM2 status
pm2 status
# View logs
pm2 logs lnpixels-api
pm2 logs lnpixels-app
# Restart services
pm2 restart ecosystem.config.example.js
Environment Configuration Issues
# Verify environment files
cat api/.env
cat lnpixels-app/.env
# Check environment variable loading
cd api && node -e "console.log(process.env.NAKAPAY_API_KEY)"
Slow Canvas Rendering
# Check browser developer tools
# Look for WebSocket connection issues
# Monitor memory usage in browser
# Optimize canvas settings
# Reduce pixel update frequency if needed
High Memory Usage
# Monitor Node.js processes
top -p $(pgrep -f "node")
# Check for memory leaks
# Use Chrome DevTools memory profiler
Database Performance
# Analyze SQLite performance
sqlite3 pixels.db ".schema"
sqlite3 pixels.db "ANALYZE;"
# Check database file size
ls -lh api/*.db
Test Coverage Problems
# Run tests with coverage
cd api && npm run test -- --coverage
# Check coverage report
open api/coverage/index.html
Integration Test Failures
# Start API server for integration tests
cd api && npm run dev
# In another terminal, run integration tests
npm run test:integration
Debug Information to Include When reporting issues, please provide:
- Operating system and version
- Node.js version (
node --version
) - npm version (
npm --version
) - Browser and version (for web issues)
- Full error messages and stack traces
- Steps to reproduce the issue
- Environment configuration (without sensitive keys)
Community Support
- Open issues on the LNPixels repository
- Check existing issues for similar problems
- Provide minimal reproduction cases
- Include screenshots for UI issues
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
- Follow the existing code style
- Write tests for new features
- Update documentation as needed
- Use TypeScript for type safety
- Follow the TDD approach outlined in
design.md
This project is licensed under the MIT License - see the LICENSE file for details.
- Lightning Network for enabling instant payments
- Socket.IO for real-time communication
- React ecosystem for excellent developer experience
- Vite for fast development and building
For support, please open an issue on GitHub or contact the development team.
Happy pixelating! π¨β‘