{"id":30807397,"url":"https://github.com/davidedc/swcanvas","last_synced_at":"2025-09-06T02:08:31.163Z","repository":{"id":311219615,"uuid":"1037215588","full_name":"davidedc/SWCanvas","owner":"davidedc","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-22T20:44:37.000Z","size":1293,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-22T22:46:49.906Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://davidedc.github.io/SWCanvas/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davidedc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-13T08:34:35.000Z","updated_at":"2025-08-22T20:44:41.000Z","dependencies_parsed_at":"2025-08-22T22:46:53.272Z","dependency_job_id":"c20d56cd-847f-4167-a69d-095d616a692f","html_url":"https://github.com/davidedc/SWCanvas","commit_stats":null,"previous_names":["davidedc/swcanvas"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/davidedc/SWCanvas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidedc%2FSWCanvas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidedc%2FSWCanvas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidedc%2FSWCanvas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidedc%2FSWCanvas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davidedc","download_url":"https://codeload.github.com/davidedc/SWCanvas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davidedc%2FSWCanvas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273847264,"owners_count":25178647,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-06T02:00:13.247Z","response_time":2576,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-06T02:08:26.139Z","updated_at":"2025-09-06T02:08:31.151Z","avatar_url":"https://github.com/davidedc.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SWCanvas\n\nA deterministic 2D Javascript raster engine with Canvas-like API, cross-browser and Node.js.\n\n**🎨 [Demo](examples/showcase.html)** • **🧪 [Tests](tests/browser/index.html)** • **📊 [Minimal Example](tests/browser/minimal-example.html)**\n\n## Features\n\n- **Cross-platform Deterministic Rendering**: Identical results across all browsers and Node.js\n- **HTML5 Canvas Compatibility**: Drop-in replacement with familiar API  \n- **Object-Oriented Design**: Clean ES6 classes following effective OO principles\n- **Geometric Path Hit Testing**: Complete `isPointInPath` and `isPointInStroke` implementation with accurate geometric calculation\n- **Memory Efficient Clipping**: Stencil-based clipping system with proper intersection support\n- **Sub-pixel Stroke Rendering**: Thin strokes render with proportional opacity, works with all paint sources\n- **Full Porter-Duff Compositing**: Complete `globalCompositeOperation` support with all 10 standard operations working correctly\n- **Comprehensive Test Coverage**: 36 core tests + 138 visual tests\n- **Immutable Value Objects**: Point, Rectangle, Transform2D, Color prevent mutation bugs\n- **Cross-Platform**: Works in Node.js and browsers\n- **No Dependencies**: Pure JavaScript implementation\n\n## Not Supported\n\nSWCanvas focuses on deterministic 2D graphics primitives and does not implement several HTML5 Canvas features:\n\n- **Text Rendering / Advanced Typography**: No `fillText()`, `strokeText()`, `measureText()` or font handling, no text baseline, direction, or complex text layout\n- **Image Loading**: No built-in image loading from URLs or files (use ImageLike objects with raw pixel data)\n- **Video/Media**: No video frame rendering or media stream support\n- **Filter Effects**: No CSS-style filters or convolution matrices\n- **Canvas-to-Canvas Blitting**: Limited `drawImage()` support (works with ImageLike objects, not arbitrary Canvas elements)\n- **Pixel Manipulation Beyond ImageData**: No advanced pixel-level operations beyond `getImageData()/putImageData()`\n\n### Performance Limitations\n\n**⚠️ Important Performance Note**: SWCanvas prioritized cross-platform rendering consistency, educational and debugging purposes, and is **not optimized for**:\n- Real-time animations or games\n- High-frequency updates (\u003e30 FPS)\n- Complex scenes with many elements\n- Performance-critical applications\n\nFor animations beyond very basic drawings, expect significant performance limitations. The rendering engine uses CPU-based pixel manipulation in Javascript without GPU acceleration, making it unsuitable for intensive animated content.\n\n## Quick Start\n\n### Building\n\n```bash\nnpm run build      # Build the library\nnpm run minify     # Create minified version\nnpm run build:prod # Build + minify in one command\n```\n\nThis generates:\n- `dist/swcanvas.js` - Complete library for development\n- `dist/swcanvas.min.js` - Minified library for production (71% smaller)\n- `dist/swcanvas.min.js.map` - Source map for debugging\n- `tests/dist/core-functionality-tests.js` from 36 individual test files in `/tests/core/`\n- `tests/dist/visual-rendering-tests.js` from 138 individual test files in `/tests/visual/`\n\n### Node.js Usage\n\n```javascript\nconst SWCanvas = require('./dist/swcanvas.js');\n\n// Create surface with immutable dimensions\nconst surface = SWCanvas.Core.Surface(800, 600);\nconst ctx = new SWCanvas.Core.Context2D(surface);\n\n// Use Canvas 2D API\nctx.setFillStyle(255, 0, 0, 255); // Red\nctx.fillRect(10, 10, 100, 50);\n\n// Advanced: Use OO classes directly\nconst transform = new SWCanvas.Core.Transform2D()\n    .translate(100, 100)\n    .rotate(Math.PI / 4);\n\nconst point = new SWCanvas.Point(50, 75);\nconst rect = new SWCanvas.Rectangle(0, 0, 200, 150);\nconst color = new SWCanvas.Core.Color(255, 128, 0, 200);\n\n// Export as PNG (recommended - preserves transparency)\nconst pngData = SWCanvas.Core.PngEncoder.encode(surface);\n// Or export as BMP (legacy - composites with white background)  \nconst bmpData = SWCanvas.Core.BitmapEncoder.encode(surface);\n```\n\n### Browser Usage\n\n```html\n\u003cscript src=\"dist/swcanvas.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n// Create surface and context\nconst surface = SWCanvas.Core.Surface(800, 600);\nconst ctx = new SWCanvas.Core.Context2D(surface);\n\n// Standard Canvas 2D operations\nctx.setFillStyle(255, 0, 0, 255); // Red\nctx.fillRect(10, 10, 100, 50);\n\n// Path operations including ellipses\nctx.beginPath();\nctx.ellipse(400, 200, 80, 40, Math.PI / 4, 0, 2 * Math.PI);\nctx.fill();\n\n// Use immutable geometry classes\nconst center = new SWCanvas.Point(400, 300);\nconst bounds = new SWCanvas.Rectangle(100, 100, 600, 400);\nif (bounds.contains(center)) {\n    console.log('Center is within bounds');\n}\n\n// Transform operations\nctx.save();\nconst rotTransform = SWCanvas.Core.Transform2D.rotation(Math.PI / 6);\nctx.setTransform(rotTransform.a, rotTransform.b, rotTransform.c, rotTransform.d, rotTransform.e, rotTransform.f);\nctx.fillRect(50, 50, 100, 100);\nctx.restore();\n\u003c/script\u003e\n```\n\n## Examples\n\n### Feature Showcase\n\nOpen `examples/showcase.html` in a web browser for a comprehensive demonstration of SWCanvas capabilities:\n\n- **Interactive Demo**: All major features demonstrated on a single 800x600 canvas\n- **Live Features**: Redraw button, animation demo, BMP download functionality  \n- **Production Build**: Uses minified version (`swcanvas.min.js`) with automatic fallback\n- **Performance Metrics**: Real-time render timing display\n\n**Features Demonstrated:**\n- Basic shapes, gradients, and patterns\n- Transformations and clipping operations\n- Various stroke styles and line dashing\n- Alpha blending and complex paths\n- Sub-pixel rendering accuracy\n\n```bash\n# View the example\nopen examples/showcase.html\n```\n\nSee [examples/README.md](examples/README.md) for additional examples and usage instructions.\n\n## Testing\n\n### Run All Tests\n\n```bash\nnpm test\n```\n\nThis runs:\n- 36 modular core functionality tests (automatically uses built tests from `/tests/core/`)\n- 138 visual rendering tests generating PNG files in `tests/output/`\n\n### Browser Tests\n\nOpen `tests/browser/index.html` in a web browser for:\n- Side-by-side HTML5 Canvas vs SWCanvas comparisons  \n- Interactive visual tests\n- All 138 visual rendering tests comparisons (automatically uses built modular tests)\n- PNG/BMP download functionality\n\n### Test Architecture\n\n- **Core Functionality Tests** (36): Individual test files in `/tests/core/` - API correctness, edge cases, mathematical accuracy\n- **Visual Rendering Tests** (138): Individual test files in `/tests/visual/` - Rendering verification with PNG generation  \n- **Browser Tests**: Interactive visual comparison tools using built test suites with HTML5 Canvas vs SWCanvas side-by-side\n\nThe modular architecture allows individual test development while maintaining build-time concatenation for performance.\n\nSee [tests/README.md](tests/README.md) for detailed test documentation.\n\n## API Documentation\n\nSWCanvas provides **dual API architecture** for maximum flexibility:\n\n### HTML5 Canvas-Compatible API (Recommended for Portability)\n\nDrop-in replacement for HTML5 Canvas with familiar API:\n\n```javascript\n// Create canvas element (works in Node.js and browsers)\nconst canvas = SWCanvas.createCanvas(800, 600);\nconst ctx = canvas.getContext('2d');\n\n// Standard HTML5 Canvas API\nctx.fillStyle = 'red';\nctx.fillRect(10, 10, 100, 50);\n\nctx.strokeStyle = '#0066cc';\nctx.lineWidth = 2;\nctx.strokeRect(20, 20, 80, 30);\n\n// Line dashing\nctx.setLineDash([5, 5]);       // Dashed line pattern\nctx.lineDashOffset = 0;        // Starting offset\nctx.beginPath();\nctx.moveTo(10, 70);\nctx.lineTo(100, 70);\nctx.stroke();\n\n// Shadows\nctx.shadowColor = 'rgba(0, 0, 0, 0.5)';  // Semi-transparent black\nctx.shadowBlur = 5;                      // 5px blur radius\nctx.shadowOffsetX = 3;                   // 3px right offset\nctx.shadowOffsetY = 3;                   // 3px down offset\nctx.fillStyle = 'red';\nctx.fillRect(120, 10, 50, 30);          // Rectangle with shadow\n\n// Rounded corners with arcTo\nctx.beginPath();\nctx.moveTo(50, 100);\nctx.lineTo(150, 100);\nctx.arcTo(200, 100, 200, 150, 25); // 25px radius rounded corner\nctx.lineTo(200, 200);\nctx.stroke();\n\n// Path hit testing\nctx.beginPath();\nctx.rect(10, 120, 100, 60);\nctx.fillStyle = 'blue';\nctx.fill();\n\n// Test if points are inside the filled rectangle\nif (ctx.isPointInPath(60, 150)) {\n    console.log('Point (60, 150) is inside the rectangle');\n}\nif (ctx.isPointInPath(60, 150, 'evenodd')) {\n    console.log('Point is inside using evenodd fill rule');\n}\n\n// Test if points are on the stroke outline\nctx.lineWidth = 5;\nctx.stroke();\nif (ctx.isPointInStroke(48, 150)) { // On stroke edge\n    console.log('Point (48, 150) is on the stroke outline');\n}\n\n// Composite operations (Porter-Duff blending)\nctx.fillStyle = 'red';\nctx.fillRect(30, 30, 40, 40);\n\nctx.globalCompositeOperation = 'destination-over'; // Draw behind existing content\nctx.fillStyle = 'blue';\nctx.fillRect(50, 50, 40, 40);\n\n// All Porter-Duff operations supported:\n// Source-bounded operations: source-over (default), destination-over, destination-out, xor\n// Canvas-wide operations: destination-atop, destination-in, source-atop, source-in, source-out, copy\n\n// ImageData API for pixel manipulation\nconst imageData = ctx.createImageData(100, 100);\n// ... modify imageData.data ...\nctx.putImageData(imageData, 50, 50);\n\n// Extract pixel data\nconst pixelData = ctx.getImageData(60, 60, 10, 10);\n\n// Factory method for ImageData objects\nconst blankImage = SWCanvas.createImageData(50, 50);\n```\n\n### Core API (Recommended for Performance)\n\nDirect access to core classes with explicit RGBA values:\n\n```javascript\n// Create surface and context directly  \nconst surface = SWCanvas.Core.Surface(width, height);\nconst ctx = new SWCanvas.Core.Context2D(surface);\n\n// Explicit RGBA values (0-255)\nctx.setFillStyle(255, 0, 0, 255);    // Red\nctx.setStrokeStyle(0, 102, 204, 255); // Blue\n```\n\n### Drawing Operations\n```javascript\n// Rectangle filling\nctx.fillRect(x, y, width, height);\n\n// Path operations\nctx.beginPath();\nctx.moveTo(x, y);\nctx.lineTo(x2, y2);\nctx.arc(cx, cy, radius, startAngle, endAngle, counterclockwise);\nctx.ellipse(cx, cy, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise);\nctx.arcTo(x1, y1, x2, y2, radius); // Rounded corners between lines\nctx.fill();\nctx.stroke();\n\n// Path testing  \nconst isInside = ctx.isPointInPath(x, y, fillRule); // Test if point is inside current path\nconst isOnStroke = ctx.isPointInStroke(x, y); // Test if point is on stroke outline\n\n// Transforms\nctx.translate(x, y);\nctx.scale(x, y);\nctx.rotate(angle);\n\n// Clipping\nctx.clip();\n\n// State management\nctx.save();\nctx.restore();\n\n// Image rendering\nctx.drawImage(imagelike, dx, dy);                    // Basic positioning\nctx.drawImage(imagelike, dx, dy, dw, dh);            // With scaling\nctx.drawImage(imagelike, sx, sy, sw, sh, dx, dy, dw, dh); // With source rectangle\n\n// Line dashing\nctx.setLineDash([10, 5]);        // Set dash pattern: 10px dash, 5px gap\nctx.lineDashOffset = 2;          // Starting offset into pattern\nconst pattern = ctx.getLineDash(); // Get current pattern: [10, 5]\n\n// Shadow properties\nctx.shadowColor = 'rgba(0, 0, 0, 0.3)'; // Shadow color with transparency\nctx.shadowBlur = 8;                     // Blur radius in pixels\nctx.shadowOffsetX = 4;                  // Horizontal shadow offset\nctx.shadowOffsetY = 4;                  // Vertical shadow offset\n\n// Drawing with shadows (works with all drawing operations)\nctx.fillStyle = 'blue';\nctx.fillRect(50, 50, 100, 60);          // Rectangle with shadow\nctx.strokeStyle = 'green';\nctx.lineWidth = 3;\nctx.strokeRect(50, 120, 100, 60);       // Stroked rectangle with shadow\n\n// Shadows work with paths and complex shapes\nctx.beginPath();\nctx.arc(300, 100, 40, 0, Math.PI * 2);\nctx.fillStyle = 'orange';\nctx.fill();                             // Circle with shadow\n\n// Turn off shadows\nctx.shadowColor = 'transparent';        // Or set to 'rgba(0,0,0,0)'\n```\n\n### Color Setting\n```javascript\nctx.setFillStyle(r, g, b, a);    // 0-255 values\nctx.setStrokeStyle(r, g, b, a);  // 0-255 values\n\n// Shadow properties (Core API uses explicit RGBA values)\nctx.setShadowColor(0, 0, 0, 128);    // Semi-transparent black shadow\nctx.shadowBlur = 5;                  // 5px blur radius\nctx.shadowOffsetX = 3;               // 3px horizontal offset\nctx.shadowOffsetY = 3;               // 3px vertical offset\n\n// Or use Color objects directly\nconst color = new SWCanvas.Core.Color(255, 128, 0, 200);\nctx.setFillStyle(color.r, color.g, color.b, color.a);\n\nconst shadowColor = new SWCanvas.Core.Color(0, 0, 0, 100);\nctx.setShadowColor(shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);\n```\n\n### Gradients and Patterns\n\nSWCanvas supports HTML5 Canvas-compatible gradients and patterns for advanced fill and stroke operations:\n\n#### HTML5 Canvas-Compatible API\n```javascript\nconst canvas = SWCanvas.createCanvas(400, 300);\nconst ctx = canvas.getContext('2d');\n\n// Linear gradients\nconst linearGrad = ctx.createLinearGradient(0, 0, 200, 0);\nlinearGrad.addColorStop(0, 'red');\nlinearGrad.addColorStop(0.5, 'yellow');\nlinearGrad.addColorStop(1, 'blue');\nctx.fillStyle = linearGrad;\nctx.fillRect(10, 10, 200, 100);\n\n// Radial gradients  \nconst radialGrad = ctx.createRadialGradient(150, 75, 0, 150, 75, 50);\nradialGrad.addColorStop(0, '#ff0000');\nradialGrad.addColorStop(1, '#0000ff');\nctx.fillStyle = radialGrad;\nctx.fillRect(100, 50, 100, 100);\n\n// Conic gradients (CSS conic-gradient equivalent)\nconst conicGrad = ctx.createConicGradient(Math.PI / 4, 200, 150);\nconicGrad.addColorStop(0, 'red');\nconicGrad.addColorStop(0.25, 'yellow');\nconicGrad.addColorStop(0.5, 'lime');\nconicGrad.addColorStop(0.75, 'aqua');\nconicGrad.addColorStop(1, 'red');\nctx.fillStyle = conicGrad;\nctx.fillRect(150, 100, 100, 100);\n\n// Patterns with ImageLike objects\nconst patternImage = ctx.createImageData(20, 20);\n// ... fill patternImage.data with pattern ...\nconst pattern = ctx.createPattern(patternImage, 'repeat');\nctx.fillStyle = pattern;\nctx.fillRect(50, 150, 150, 100);\n\n// Gradients work with strokes too, including sub-pixel strokes\nctx.strokeStyle = linearGrad;\nctx.lineWidth = 5;\nctx.strokeRect(250, 50, 100, 100);\n\n// Sub-pixel strokes work with all paint sources\nctx.strokeStyle = radialGrad;\nctx.lineWidth = 0.5; // 50% opacity stroke\nctx.strokeRect(250, 150, 100, 100);\n\n// Shadows work with all paint sources\nctx.shadowColor = 'rgba(0, 0, 0, 0.4)';\nctx.shadowBlur = 6;\nctx.shadowOffsetX = 4;\nctx.shadowOffsetY = 4;\nctx.fillStyle = conicGrad;\nctx.fillRect(300, 10, 80, 80);           // Gradient fill with shadow\n```\n\n#### Core API (Performance)\n```javascript\nconst surface = SWCanvas.Core.Surface(400, 300);\nconst ctx = new SWCanvas.Core.Context2D(surface);\n\n// Linear gradients\nconst linearGrad = ctx.createLinearGradient(0, 0, 200, 0);\nlinearGrad.addColorStop(0, new SWCanvas.Core.Color(255, 0, 0, 255));\nlinearGrad.addColorStop(1, new SWCanvas.Core.Color(0, 0, 255, 255));\nctx.setFillStyle(linearGrad);\nctx.fillRect(10, 10, 200, 100);\n\n// Radial gradients\nconst radialGrad = ctx.createRadialGradient(150, 75, 0, 150, 75, 50);\nradialGrad.addColorStop(0, new SWCanvas.Core.Color(255, 255, 0, 255));\nradialGrad.addColorStop(1, new SWCanvas.Core.Color(255, 0, 255, 255));\nctx.setStrokeStyle(radialGrad);\nctx.lineWidth = 8;\nctx.beginPath();\nctx.arc(150, 75, 40);\nctx.stroke();\n\n// Conic gradients\nconst conicGrad = ctx.createConicGradient(0, 200, 150);\nconicGrad.addColorStop(0, new SWCanvas.Core.Color(255, 0, 0, 255));\nconicGrad.addColorStop(0.33, new SWCanvas.Core.Color(0, 255, 0, 255));\nconicGrad.addColorStop(0.66, new SWCanvas.Core.Color(0, 0, 255, 255));\nconicGrad.addColorStop(1, new SWCanvas.Core.Color(255, 0, 0, 255));\nctx.setFillStyle(conicGrad);\nctx.fillRect(150, 100, 100, 100);\n\n// Patterns with sub-pixel strokes\nconst imagelike = { width: 10, height: 10, data: new Uint8ClampedArray(400) };\n// ... fill imagelike.data ...\nconst pattern = ctx.createPattern(imagelike, 'repeat-x');\nctx.setStrokeStyle(pattern);\nctx.lineWidth = 0.25; // 25% opacity stroke  \nctx.strokeRect(50, 200, 200, 50);\n\n// Shadows work with all paint sources (Core API)\nctx.setShadowColor(0, 0, 0, 100);        // RGBA shadow color\nctx.shadowBlur = 4;\nctx.shadowOffsetX = 2;\nctx.shadowOffsetY = 2;\nctx.setFillStyle(conicGrad);\nctx.fillRect(300, 200, 80, 80);          // Conic gradient fill with shadow\n```\n\n#### Pattern Repetition Modes\n- `'repeat'` - Tile in both directions (default)\n- `'repeat-x'` - Tile horizontally only\n- `'repeat-y'` - Tile vertically only  \n- `'no-repeat'` - Display once at pattern origin\n\n#### Gradient Types\n- **LinearGradient**: `createLinearGradient(x0, y0, x1, y1)` - Linear color transition\n- **RadialGradient**: `createRadialGradient(x0, y0, r0, x1, y1, r1)` - Radial color transition\n- **ConicGradient**: `createConicGradient(startAngle, centerX, centerY)` - Conic sweep transition\n\n### Core API Classes\n\nSWCanvas provides rich OO classes for advanced operations through the Core API:\n\n```javascript\n// Immutable geometry classes\nconst point = new SWCanvas.Core.Point(100, 50);\nconst rect = new SWCanvas.Core.Rectangle(10, 20, 100, 80);\nconst center = rect.center; // Returns Point(60, 60)\n\n// Immutable transformation matrix\nconst transform = new SWCanvas.Core.Transform2D()\n    .translate(100, 100)\n    .scale(2, 2)\n    .rotate(Math.PI / 4);\n\n// Apply to points\nconst transformed = transform.transformPoint(point);\n\n// Bit manipulation utility (used by mask classes)\nconst bitBuffer = new SWCanvas.Core.BitBuffer(100, 100, 0); // Default to 0s\nbitBuffer.setPixel(50, 50, true);\nconsole.log(bitBuffer.getPixel(50, 50)); // true\n\n// Bounds tracking utility (used by SourceMask and ShadowBuffer)\nconst boundsTracker = new SWCanvas.Core.BoundsTracker();\nboundsTracker.updateBounds(50, 75);\nconsole.log(boundsTracker.getBounds()); // { minX: 50, maxX: 50, minY: 75, maxY: 75, isEmpty: false }\n\n// Mask classes (use BitBuffer and BoundsTracker composition internally)\nconst clipMask = new SWCanvas.Core.ClipMask(800, 600);\nconst sourceMask = new SWCanvas.Core.SourceMask(800, 600);\n\n// Image processing utilities\nconst validImage = SWCanvas.Core.ImageProcessor.validateAndConvert(imageData);\n\n// Composite operations utilities\nconst supportedOps = SWCanvas.Core.CompositeOperations.getSupportedOperations();\nconst isSupported = SWCanvas.Core.CompositeOperations.isSupported('xor');\n\n// Path processing utilities\nconst polygons = SWCanvas.Core.PathFlattener.flattenPath(path2d);\nconst strokePolys = SWCanvas.Core.StrokeGenerator.generateStrokePolygons(path2d, strokeProps);\n\n// Color parsing utilities (for CSS color strings)\nconst color = SWCanvas.Core.ColorParser.parse('#FF0000');\n\n// BMP encoding configuration\nconst encodingOptions = SWCanvas.Core.BitmapEncodingOptions.withGrayBackground(128);\n```\n\n### Image Rendering\n\nSWCanvas supports drawing ImageLike objects with nearest-neighbor sampling:\n\n```javascript\n// ImageLike interface: { width, height, data: Uint8ClampedArray }\nconst imagelike = {\n    width: 10,\n    height: 10,\n    data: new Uint8ClampedArray(10 * 10 * 4) // RGBA\n};\n\n// RGB images auto-convert to RGBA\nconst rgbImage = {\n    width: 5,\n    height: 5, \n    data: new Uint8ClampedArray(5 * 5 * 3) // RGB → RGBA with alpha=255\n};\n\n// Basic usage\nctx.drawImage(imagelike, 10, 10);                    // Draw at position\nctx.drawImage(imagelike, 10, 10, 20, 20);            // Draw with scaling\nctx.drawImage(imagelike, 0, 0, 5, 5, 10, 10, 10, 10); // Source rectangle\n\n// Works with transforms and clipping\nctx.translate(50, 50);\nctx.rotate(Math.PI / 4);\nctx.drawImage(imagelike, 0, 0);\n```\n\n### Image Export\n\n#### PNG Export (Recommended - Supports Transparency)\n```javascript\nconst pngData = SWCanvas.Core.PngEncoder.encode(surface);\n// Returns ArrayBuffer containing PNG file data\n// Preserves transparency without background compositing\n\n// PNG with custom options\nconst pngOptions = SWCanvas.Core.PngEncodingOptions.withTransparency();\nconst pngData = SWCanvas.Core.PngEncoder.encode(surface, pngOptions);\n```\n\n#### BMP Export (Legacy - Background Compositing)\n```javascript\nconst bmpData = SWCanvas.Core.BitmapEncoder.encode(surface);\n// Returns ArrayBuffer containing BMP file data\n// Transparent pixels composited with white background (default)\n\n// Custom background colors for transparent pixel compositing\nconst grayOptions = SWCanvas.Core.BitmapEncodingOptions.withGrayBackground(128);\nconst bmpData = SWCanvas.Core.BitmapEncoder.encode(surface, grayOptions);\n\n// Pre-defined background options\nconst blackBmp = SWCanvas.Core.BitmapEncoder.encode(surface, \n    SWCanvas.Core.BitmapEncodingOptions.withBlackBackground());\n```\n\n## Architecture\n\n### Core Components (Object-Oriented Design)\n\n- **Surface**: Memory buffer for pixel data\n- **Context2D**: Drawing API and state management\n- **Transform2D**: Transformation mathematics (immutable value object)\n- **SWPath2D**: Path definition and flattening\n- **Rasterizer**: Low-level pixel operations\n- **Color**: Immutable color handling with premultiplied alpha support\n- **Gradients**: Paint source objects for linear, radial, and conic gradients with color stops\n- **Pattern**: Paint source objects for repeating image patterns with repetition modes\n- **Geometry**: Point and Rectangle value objects\n- **BitBuffer**: 1-bit per pixel utility for efficient bit manipulation (composition component)\n- **BoundsTracker**: Reusable bounds tracking utility for optimization (composition component)\n- **ClipMask**: 1-bit clipping buffer using BitBuffer composition\n- **SourceMask**: 1-bit source coverage tracking using BitBuffer and BoundsTracker composition\n- **DrawingState**: Context state stack management\n- **PolygonFiller**: Scanline-based polygon filling with paint source support\n- **StrokeGenerator**: Geometric stroke generation (static methods)  \n- **PathFlattener**: Path-to-polygon conversion (static methods)\n- **PngEncoder**: PNG file format export with transparency support (static methods)\n- **PngEncodingOptions**: Immutable PNG encoding configuration (Joshua Bloch pattern)\n- **BitmapEncoder**: BMP file format export (static methods)  \n- **BitmapEncodingOptions**: Immutable BMP encoding configuration (Joshua Bloch pattern)\n\n### Key Features\n\n#### Stencil-Based Clipping\n- 1-bit per pixel memory efficiency\n- Proper clip intersection with AND operations\n- Supports complex nested clipping scenarios\n- Matches HTML5 Canvas behavior exactly\n\n#### Deterministic Rendering\n- Fixed-point arithmetic for transforms\n- Consistent rasterization algorithms\n- Identical results across platforms\n- No floating-point precision issues\n\n#### Premultiplied sRGB\n- Consistent alpha blending\n- Matches HTML5 Canvas color handling\n- Proper transparency composition\n\n## Development\n\n**Debug Utilities**: See `debug/README.md` for debugging scripts, templates, and investigation workflows.\n\n### Project Structure (Object-Oriented Architecture)\n\n```\nsrc/              # Source files (ES6 Classes)\n├── Context2D.js     # Main drawing API (class)\n├── Surface.js       # Memory management (ES6 class) \n├── Transform2D.js   # Transform mathematics (immutable class)\n├── Rasterizer.js    # Low-level rendering (ES6 class)\n├── Color.js         # Immutable color handling (class)\n├── Point.js         # Immutable 2D point operations (class)\n├── Rectangle.js     # Immutable rectangle operations (class)\n├── Gradient.js      # Gradient paint sources (linear, radial, conic)\n├── Pattern.js       # Pattern paint sources with repetition modes\n├── ClipMask.js      # 1-bit clipping buffer (class)\n├── ImageProcessor.js # ImageLike validation and conversion (static methods)\n├── PolygonFiller.js # Scanline polygon filling with paint sources (static methods)\n├── StrokeGenerator.js # Stroke generation (static methods)\n├── PathFlattener.js # Path to polygon conversion (static methods)\n├── BitmapEncoder.js # BMP file encoding (static methods)\n├── BitmapEncodingOptions.js # BMP encoding configuration (immutable options)\n├── ColorParser.js   # CSS color string parsing (static methods)\n└── SWPath2D.js      # Path definition (class)\n\ntests/            # Test suite\n├── core-functionality-tests.js # Core functionality tests\n├── visual-rendering-tests.js    # 138+ visual tests\n└── run-tests.js            # Node.js test runner\n\ntests/browser/    # Browser tests\n├── index.html       # Main visual comparison tool (moved from examples/)\n├── minimal-example.html # Minimal usage example\n└── browser-test-helpers.js # Interactive test utilities\n\ndist/             # Built library\n└── swcanvas.js      # Concatenated distribution file\n```\n\n## Test Architecture\n\nSWCanvas uses a comprehensive dual test system:\n- **36 core functionality tests**: Programmatic API verification with assertions\n- **138 visual rendering tests**: PNG (lossless) generation and comparison\n- **Modular architecture**: Individual test files auto-concatenated at build time\n\nSee [tests/README.md](tests/README.md) for complete test documentation, adding tests, and build utilities.\n\n**Test Count Maintenance**: The `npm run update-test-counts` command automatically updates test count references across all documentation files to match the actual filesystem. This ensures documentation accuracy as tests are added or removed.\n\n### Build Process\n\nThe build script (`build.sh`) concatenates source files in dependency order, following OO architecture:\n\n**Phase 1: Foundation Classes**\n1. Color - Immutable color handling\n2. Point - Immutable 2D point operations\n3. Rectangle - Immutable rectangle operations\n4. Transform2D - Transformation mathematics\n5. SWPath2D - Path definitions\n6. Surface - Memory buffer management\n\n**Phase 2: Service Classes**\n7. BitmapEncodingOptions - BMP encoding configuration (immutable options)\n8. BitmapEncoder - BMP file encoding (static methods)\n9. PathFlattener - Path-to-polygon conversion (static methods)\n10. PolygonFiller - Scanline filling with paint sources (static methods)\n11. StrokeGenerator - Stroke generation (static methods) \n12. BitBuffer - 1-bit per pixel utility (composition component)\n13. BoundsTracker - Reusable bounds tracking utility (composition component)\n14. ClipMask - 1-bit stencil buffer management (class)\n15. SourceMask - 1-bit source coverage tracking (class)\n16. ShadowBuffer - Sparse shadow alpha storage (class)\n17. ImageProcessor - ImageLike validation and conversion (static methods)\n18. ColorParser - CSS color string parsing (static methods)\n\n**Phase 2.5: Paint Sources**\n19. Gradient - Linear, radial, and conic gradient paint sources\n20. Pattern - Repeating image pattern paint sources\n\n**Phase 3: Rendering Classes**\n21. Rasterizer - Rendering pipeline (class)\n22. Context2D - Main drawing API (class)\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Contributing\n\n1. **Build**: `npm run build`\n2. **Test**: `npm test` \n3. **Visual Test**: Open `tests/browser/index.html` in browser\n4. **Add Tests**: Create individual test files in `/tests/core/` or `/tests/visual/` (see renumbering utility for advanced organization)\n5. **Verify**: Ensure identical results in both Node.js and browser\n\nThe comprehensive test suite ensures any changes maintain compatibility/similarity with HTML5 Canvas.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidedc%2Fswcanvas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavidedc%2Fswcanvas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidedc%2Fswcanvas/lists"}