# Blockbench UV Packer A Blockbench plugin that auto-packs per-face UV models with ML-assisted share-merge suggestions, mirror detection, multi-variant texture support, and pow2 canvas cropping. One button, end-to-end. Originally built for the Decocraft project's bbmodel corpus (~600 models). The ML model in `ml/share_model.json` is trained on that corpus; you can retrain on your own corpus with the scripts in `ml/`. ## What it does When you click **Tools → Pack UVs (Decocraft)**, the plugin: 1. Collects all per-face-UV cubes in the project (skips box-UV cubes; works in mixed-mode projects) 2. **Heuristic share-merge** — faces with the same UV rect (modulo flip) collapse to one packed slot. Median 80% rect dedupe across the training corpus. 3. **ML share-merge suggestions** (if `share_model.json` is loaded) — surfaces candidate merges the heuristic missed. A pixel-similarity gate filters out false positives. Each suggestion shows a thumbnail preview before you accept. 4. **Mirror-orientation detection** — for cross-rect merges, the planner samples each member's pixels in 4 orientations and picks the one that minimizes RGBA diff against the canonical, so mirror-painted symmetric regions stay mirror-correct after merging. 5. **Skyline pack** — biggest-first, top-to-bottom, left-to-right. Outliner-group ordering clusters same-group faces. Auto-expands the working canvas if rects don't fit. 6. **Variant texture rearrangement** — alternate skin textures (any texture in the project with no faces pointing to it) get the same pixel rearrangement as the driver texture, so swapping skins still lines up. 7. **Pow2 crop** — final texture canvas is shrunk to next-power-of-2 of the actual packed bbox. 8. Single Undo entry covers everything. ## Install 1. In Blockbench: **File → Plugins → Load Plugin from File** 2. Pick `decocraft_uv_packer.js` 3. (One-time) **Tools → Load Share Model JSON** → pick both `ml/share_model.json` and `ml/inference_test_cases.json` (multi-select). The model is cached to `localStorage` after first load. The plugin self-tests the JS LightGBM evaluator against the test cases on every load — if it doesn't match LightGBM exactly, it refuses to use the model. ## Workflow - Open a project that uses per-face UVs - **Tools → Pack UVs (Decocraft)** - If the ML model finds candidates, a dialog opens with thumbnails. Uncheck any pair where the previews disagree visually. Click **Accept & Pack** (or **Pack without merging** to skip ML suggestions). - The plugin packs, crops to pow2, and rearranges variants. Toast reports `Packed N faces into M slots · canvas A×B → C×D`. ## Retraining the ML model on your own corpus If you have your own bbmodel collection and want a model trained on its conventions: ```sh # 1. Inspect the corpus statistics (optional) node analyze_uvs.mjs path/to/your/bbmodel/folder # 2. Extract face-pair training data (~250k labeled pairs from ~600 models) node ml/extract_pairs.mjs path/to/your/bbmodel/folder # → produces ml/pairs.csv (~30 MB on a 600-model corpus) # 3. Train (Python: pip install lightgbm pandas scikit-learn) cd ml python train_share_classifier.py # → updates share_model.json, eval_report.txt, inference_test_cases.json # 4. In Blockbench: Tools → Load Share Model JSON → pick the new files ``` The training script splits **by model** (not by pair) for held-out evaluation — so the precision/recall numbers in `eval_report.txt` reflect actual generalization to unseen models, not just unseen pairs from already-seen models. The bundled `share_model.json` was trained on the Decocraft corpus and reaches AUC 0.985 / precision 0.96 @ recall 0.88 on 123 held-out models. ## File layout ``` blockbench-uv-packer/ ├── decocraft_uv_packer.js Blockbench plugin (single file) ├── analyze_uvs.mjs Corpus stats (per-model density, group overlap, share fraction…) └── ml/ ├── extract_pairs.mjs Build pairs.csv from a bbmodel directory ├── train_share_classifier.py LightGBM trainer + eval + JSON export ├── validate_js_eval.mjs Verifies the JS evaluator matches LightGBM bit-for-bit ├── share_model.json Trained model (350 trees, ~2.5 MB) ├── inference_test_cases.json 50 self-test cases for the plugin └── eval_report.txt Precision/recall sweep + feature importance from last train ``` ## Limitations / non-goals - **Per-face UV only.** Cubes set to box-UV mode are skipped (counted in the success toast). - **Same-dimension share-merges only.** The merger collapses faces whose source rects have the same dims (with optional 90°-mirror); it doesn't rotate-to-fit different aspect ratios. - **Reorient-cubes feature was attempted and dropped.** Auto-rotating cubes for tighter packing fights against either Blockbench's `cube.roll()` (which rotates visually, breaking model assemblies) or requires deriving the full per-(perm × slot) D4-symmetry texture transform (which kept hitting subtle bugs across iterations). If you want a cube reoriented, use Blockbench's built-in Transform → Rotate tools manually before running Pack UVs. ## License TBD — add the license your project uses.