A web application that turns raster images into geometric mosaics by tiling them with regular polygons — hexagons, squares, or equilateral triangles — and filling each tile with a representative colour.
All geometry computation runs in WebAssembly compiled from French Multilingual sources. The browser relies entirely on the WASM binary.
- Three tiling modes: hexagon (pointy-top, staggered rows), square, equilateral triangle
- Tile size configurable from 5 px to 120 px
- Optional tile outlines with adjustable colour and opacity
- Drag-and-drop / click / paste image upload
- Before-and-after canvas view with one-click PNG download
- Geometry (
sommet_hex_x,espacement_horiz,hauteur_tri,couleur_moyenne, …) exported from WASM with French identifiers - Full canonical implementation — including KMeans dominant-colour mode via
MiniBatchKMeans— available insrc/hexagonify_canonique.ml
pixel2polygon/
├── src/
│ ├── hexagonify_wasm.ml # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.ml # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.ml # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.ml # Build script (French multilingual)
├── public/
│ ├── index.html # Web UI
│ ├── style.css # Dark-theme stylesheet
│ ├── app.js # JavaScript frontend (WASM-only, no fallback)
│ ├── hexagonify.wasm # Compiled binary ← generated by build
│ └── hexagonify.wat # WAT text format ← generated by build
└── requirements-build.txt # Python build dependencies
src/hexagonify_wasm.ml (French multilingual)
│
▼
Lexer / Parser
│
▼
WATCodeGenerator ──► hexagonify.wat
│
▼
wasmtime.wat2wasm ──► hexagonify.wasm
│
▼
Browser loads WASM, calls French exports:
sommet_hex_x / sommet_hex_y
espacement_horiz / espacement_vert
hauteur_tri / sommet_tri_x / sommet_tri_y
couleur_moyenne
The JavaScript frontend (public/app.js) calls these exports directly. If the WASM binary is absent or invalid, the application is disabled and the build command is shown.
pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtimemultilingual run scripts/compile_wasm.mlOutputs:
| File | Description |
|---|---|
public/hexagonify.wasm |
Binary WebAssembly module loaded by the browser |
public/hexagonify.wat |
Human-readable WAT (WebAssembly Text) for inspection |
To point the build script at a local development checkout of the multilingual runtime:
MULTILINGUAL_DEV_PATH=/path/to/multilingual multilingual run scripts/compile_wasm.mlServe the public/ directory with any static file server that sets the correct MIME type for .wasm files (application/wasm):
# Python (built-in)
python -m http.server 8080 --directory public
# Node.js (npx serve)
npx serve publicThen open http://localhost:8080 in a browser.
Note: opening
index.htmldirectly as afile://URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.
Run the lightweight frontend smoke suite with plain Node.js:
node tests/smoke.jsThe smoke tests validate that the main UI controls are present, the shape selector triggers a render, studio/source tab switching works, and every supported tiling method produces at least one tile.
Written in French multilingual. Exports pure numeric functions that the JavaScript frontend calls per tile:
| Export (French) | Description |
|---|---|
sommet_hex_x(cx, cy, a, idx) |
x-coordinate of vertex idx (0–5) of a pointy-top hexagon |
sommet_hex_y(cx, cy, a, idx) |
y-coordinate of the same vertex |
espacement_horiz(a) |
Horizontal stride: √3 · a |
espacement_vert(a) |
Vertical stride: 1.5 · a |
hauteur_tri(a) |
Triangle height: √3/2 · a |
sommet_tri_x(x, a, idx, vers_haut) |
x-coordinate of triangle vertex idx |
sommet_tri_y(y, a, idx, vers_haut) |
y-coordinate of triangle vertex idx |
couleur_moyenne(total, compte) |
Per-channel colour mean: round(total / compte) |
methode_hexagone() / methode_carre() / methode_triangle() |
Method codes (0 / 1 / 2) |
Written in French multilingual. Implements the complete algorithm as a Python-compiled program, including:
- PIL/NumPy polygon masks and bounding-box sampling
mode_couleur="kmeans"— dominant colour viaMiniBatchKMeans(scikit-learn)mode_couleur="moyenne"— fast per-channel meancarreler_image()— main entry point equivalent to the originalhexagonify.py- CLI demo block (
si __name__ == "__main__":)
Run canonically with:
multilingual run src/hexagonify_canonique.mlRequires Pillow, numpy, and optionally scikit-learn:
pip install pillow numpy scikit-learnWritten in French multilingual. Mirrors the pattern established by Cellcosmos:
- Locates the project root
- Reads and bundles
src/main.ml+src/hexagonify_wasm.ml - Lexes and parses the bundle with
language="fr" - Generates WAT via
WATCodeGenerator - Compiles to binary WASM via
wasmtime.wat2wasm - Copies source files into
public/alongside the binary
| Mode | Where implemented | How |
|---|---|---|
| Moyenne (mean) | hexagonify_wasm.ml → WASM → browser |
Per-channel arithmetic mean of all pixels inside the tile |
| KMeans | hexagonify_canonique.ml → Python |
MiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable |
The web interface uses moyenne (computed in WASM). The canonical .ml source exposes both modes for offline / batch use.
- Hexagons — pointy-top orientation, staggered rows (offset every other row by half the horizontal pitch). Partial tiles at all four borders are preserved.
- Squares — axis-aligned grid, top-left anchored. Border tiles clipped to image dimensions.
- Triangles — alternating upward/downward equilateral triangles on a
(row + col) % 2parity grid. Border tiles preserved.
hexagonify_canonique.ml is a faithful French-multilingual translation of the original hexagonify.py algorithm, preserving the same geometry helpers, mask generation, and KMeans colour logic. hexagonify_wasm.ml is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.