Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

pixel2polygon

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.


Features

  • 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 in src/hexagonify_canonique.multi

Project structure

pixel2polygon/
├── src/
│ ├── hexagonify_wasm.multi # WASM module — geometry + mean colour (French multilingual)
│ ├── hexagonify_canonique.multi # Canonical source — full algorithm + KMeans (French multilingual)
│ └── main.multi # Entry point: importer hexagonify_wasm
├── scripts/
│ └── compile_wasm.multi # 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

Architecture

src/hexagonify_wasm.multi (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.


Building the WASM

Prerequisites

pip install -r requirements-build.txt
# installs: multilingualprogramming, wasmtime

Compile

multilingual run scripts/compile_wasm.multi

Outputs:

FileDescription
public/hexagonify.wasmBinary WebAssembly module loaded by the browser
public/hexagonify.watHuman-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.multi

Running the web application

Serve 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 public

Then open http://localhost:8080 in a browser.

Note: opening index.html directly as a file:// URL will block the WASM fetch due to browser CORS restrictions. Always use a local server.


Smoke tests

Run the lightweight frontend smoke suite with plain Node.js:

node tests/smoke.js

The 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.


Source files

src/hexagonify_wasm.multi — WASM module

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)

src/hexagonify_canonique.multi — canonical source

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 via MiniBatchKMeans (scikit-learn)
  • mode_couleur="moyenne" — fast per-channel mean
  • carreler_image() — main entry point equivalent to the original hexagonify.py
  • CLI demo block (si __name__ == "__main__":)

Run canonically with:

multilingual run src/hexagonify_canonique.multi

Requires Pillow, numpy, and optionally scikit-learn:

pip install pillow numpy scikit-learn

scripts/compile_wasm.multi — build script

Written in French multilingual. Mirrors the pattern established by Cellcosmos:

  1. Locates the project root
  2. Reads and bundles src/main.multi + src/hexagonify_wasm.multi
  3. Lexes and parses the bundle with language="fr"
  4. Generates WAT via WATCodeGenerator
  5. Compiles to binary WASM via wasmtime.wat2wasm
  6. Copies source files into public/ alongside the binary

Colour modes

ModeWhere implementedHow
Moyenne (mean)hexagonify_wasm.multi → WASM → browserPer-channel arithmetic mean of all pixels inside the tile
KMeanshexagonify_canonique.multi → PythonMiniBatchKMeans finds the dominant cluster centroid; falls back to mean if scikit-learn is unavailable

The web interface uses moyenne (computed in WASM). The canonical .multi source exposes both modes for offline / batch use.


Tiling geometry

  • 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) % 2 parity grid. Border tiles preserved.

Relation to hexagonify.py

hexagonify_canonique.multi 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.multi is the minimal numeric subset of that algorithm that maps cleanly to WebAssembly.

About

Pixel2Polygon converts images into geometric mosaics by replacing pixels with regular polygon tiles (triangles, squares, hexagons, and more).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages