
Image-to-Triangle is a JavaScript library that transforms any image into beautiful low-poly triangular art.
It handles all the complex image processing right in the browser, so you don’t need a server or any build steps.
Key Features
- Single function API: Complete triangulation process accessible through one
triangulate()method call. - Resolution separation: Analyze images at low resolution while rendering output at any desired size for performance optimization.
- Advanced preprocessing: Built-in brightness, contrast, saturation, gamma correction, and edge enhancement controls.
- Deterministic output: Seed-based random generation ensures identical results across multiple runs with same parameters.
- Multiple output formats: Generate results as Canvas elements, Image objects, or scalable SVG markup.
- Progressive rendering: Async processing with progress callbacks for smooth user experience during computation.
- Customizable aesthetics: Control triangle wireframes, colors, density patterns, and point distribution algorithms.
How to use it:
1. Download the package and load the ‘image-to-triangle.js’ script in your document.
<script src="/path/to/image-to-triangle.js"></script>
2. The library exposes a single asynchronous function ImageToTriangle.triangulate(options). You pass it an options object and await the result. The minimal implementation requires an image element, which accepts both HTMLImageElement and HTMLCanvasElement.
const result = await ImageToTriangle.triangulate({
image: document.getElementById('sourceImage'),
// more options here
});
document.body.appendChild(result);3. Take more control over the triangulation process with the following preprocessing options and rendering parameters.
image: The sourceHTMLImageElementorHTMLCanvasElementto be triangulated. This is the only required parameter.resolution: A number defining the width for the analysis canvas. The triangulation logic runs at this size. Keeping it consistent ensures the triangle layout remains the same regardless of the final output size.outputResolution: A number for the final render width. The generated triangles are scaled to this dimension, allowing for high-quality exports.format: A string specifying the output format. Your options are'canvas','image'(returns anHTMLImageElement), or'svg'(returns anSVGSVGElement).onProgress: A callback function that receives a single argument: the completion percentage (0-100). It’s useful for updating UI elements like a progress bar.brightness: A number from 0.1 to 3.0 that adjusts the image brightness before analysis.contrast: A number from 0.1 to 3.0 that adjusts the image contrast.saturation: A number from 0.0 to 2.0 to control the color saturation.gamma: A number from 0.1 to 3.0 for gamma correction.blur: A number from 0 to 10 representing the pixel radius for a blur effect applied before processing.invert: A boolean that, iftrue, inverts the image colors.densityMode: A string that determines how point density is calculated. Options are'luma'(brightness),'lumaBoost'(enhanced contrast), or individual channels:'red','green','blue'.edgeBoost: A number from 0.0 to 2.0 that enhances edge detection using a Sobel filter, helping to place points along distinct boundaries.points: The target number of points to distribute across the image, which directly influences the number of triangles and the level of detail.darkStrength: A number from 0.1 to 8.0 that biases point placement towards darker areas of the image. Higher values add more detail to shadows.minDist: A number specifying the minimum distance between points, preventing them from clustering too closely.edgeSamples: A number that defines how many extra points are placed along the image borders to enhance the frame.showWires: A boolean that, iftrue, renders the edges of each triangle.wireColor: A hex string (e.g.,'#ffffff') for the color of the triangle edges.wireWidth: A number for the thickness of the triangle edges.seed: An integer used to initialize the random number generator, ensuring the triangulation is deterministic and reproducible.settingsSpace: A string, either'analysis'or'output', that determines if size-based settings (minDist,wireWidth) should be interpreted relative to theresolutionoroutputResolution.
const result = await ImageToTriangle.triangulate({
image: HTMLCanvasElement | HTMLImageElement,,
// Resolution control
resolution: 800
outputResolution: 1600,
// Image preprocessing
preprocess: {
brightness: 1.0,
contrast: 1.0,
saturation: 1.0,
gamma: 1.0,
blur: 0,
invert: false,
densityMode: 'luma',
edgeBoost: 0.5
},
// Triangulation settings
settings: {
points: 3000,
darkStrength: 4.0,
minDist: 8,
edgeSamples: 20,
showWires: true,
wireColor: '#ffffff',
wireWidth: 1.0,
seed: 1,
settingsSpace: 'analysis'
},
// Output options
format: 'canvas',
onProgress: (percent) => console.log(`${percent}% complete`)
});FAQs
Q: Can I use Image-to-Triangle with images from external domains?
A: Yes, but you need to handle CORS restrictions. Add the crossorigin="anonymous" attribute to your image elements and ensure the image server includes appropriate CORS headers. Without proper CORS configuration, the canvas will be tainted and triangulation will fail.
Q: What happens if I set the point count too high for a small image?
A: The library includes automatic point density limiting based on image dimensions and the minDist parameter. Setting extremely high point values won’t crash the application, but you may not see significant visual improvements beyond the optimal density threshold.
Q: How do I maintain consistent triangle layouts when generating multiple output sizes?
A: Keep the resolution parameter constant while varying outputResolution. This ensures that triangle analysis happens at the same scale, producing identical vertex placement regardless of final render dimensions. We’ve found this approach essential for applications that need thumbnails and full-size versions with matching layouts.
Q: Why do my triangulated results look different each time with the same settings?
A: The algorithm uses random sampling for point placement. Set the seed parameter to any integer value for reproducible results. The same seed will always generate identical triangle patterns with the same configuration parameters.
Q: What’s the difference between ‘luma’ and ‘lumaBoost’ density modes?
A: The ‘luma’ mode uses standard brightness calculations for point placement, while ‘lumaBoost’ applies contrast enhancement to the luminosity values before analysis. This creates more dramatic point clustering in high-contrast areas and often produces more visually striking results.
Q: How do I match wireframe colors to my design system?
A: Set settings: { showWires: true, wireColor: '#your-hex' }. For subtle outlines, use wireWidth: 0.5 and match the wire color to your darkest image tones—this makes edges feel organic rather than artificial.
Q: Why does high edgeBoost sometimes create jagged artifacts?
A: Over-amplifying edges confuses the density map. Cap it at 0.7 for photos, or preprocess with blur: 0.5 to smooth noise.






