nucleation 0.3.7

A high-performance Minecraft schematic parser and utility library
Documentation
# Nucleation v0.3.7

- **`Palette.ramp_ids(start, end, steps)`** — ask for pure white → pure
  black in N steps and the engine picks N *distinct* blocks forming the
  smoothest ramp the palette allows: targets evenly spaced along the Oklab
  line, blocks assigned by a minimum-cost monotonic matching (unlike
  `gradient_ids`, which snaps per step and repeats). In every binding as
  `ramp_ids_json`.
- **`RenderConfig.set_sphere_fit(true)`** — rotation-invariant camera
  framing: turntables hold a constant distance instead of pulsing with the
  model's silhouette.
- **`Palette.grayscale()` is now data-driven** — opaque full cubes with
  near-neutral *measured* color (low Oklab chroma) instead of name
  substrings, which caught cream sandstones and patterned glazed
  terracottas while missing neutral blocks named otherwise.

---

# Nucleation v0.3.6

Fixes surfaced by making the library render its own README
(every image at https://github.com/Schem-at/Nucleation is now generated by
`tools/readme-media/generate.py` through the Python binding):

- **`Torus.parameter_at` fixed** — the ring angle was measured from raw
  world components of the radial projection, which is identically zero on
  one axis for the default y-up torus, so parametric `curve_gradient`
  fills collapsed to two colors. The angle is now measured in a proper
  in-plane basis; gradients sweep the full ring on any torus axis.
- **`RenderConfig.set_zoom` is now a real zoom** — it used to scale the
  camera distance (larger = further away). Now larger = closer
  (2.0 = twice as close, 0.5 = twice as far), in both perspective and
  orthographic projections. Invert your values if you used the old
  behavior.
- **JS bindings drop the filesystem methods**`loadFromFile`,
  `saveToFile`, and `saveToFileWithFormat` always threw `Io` under WASM
  (no filesystem); they are no longer in the JS typings. Use
  `fromData(bytes)` and the `to*B64()` exporters.
- **`Sdf.schematicFromSdfAuto(sdf, rules)`** — auto-bounds overload; no
  more six placeholder arguments when the SDF tree bounds itself.
- **`Palette.grayscale()` is full-cubes only** — the name match also
  caught panes/stairs/walls (e.g. `light_gray_stained_glass_pane`),
  which rendered as holes when gradients snapped to them.

---

# Nucleation v0.3.5

**Linux release libraries now target glibc 2.35 (was 2.39).** The native
`.so`s (PHP FFI) and the JVM jar's bundled linux natives (JNA) are built on
ubuntu-22.04 instead of ubuntu-latest, so they load on older-glibc deploy
targets — e.g. Debian bookworm (glibc 2.36), where the v0.3.x libs failed
`FFI::cdef` with "GLIBC_2.38 not found". No API changes.

---

# Nucleation v0.3.4

**meshing and rendering are on the crates.io crate again.** schematic-mesher
is published to crates.io (0.2.0), so the dependency is now dual
version+git: local/git builds use the pinned rev, `cargo publish` keeps the
versioned crate. The published crate no longer strips meshing/rendering —
only `simulation` (MCHPRS) stays git-only.

**The nanobind pin is gone.** The Python wheel accepted only
`nanobind ==2.12.0` because the generated dealloc shim reached into
nanobind's private struct layout (broken in 2.13). The diplomat fork's
nanobind backend now uses nanobind's public low-level instance API, so the
pin is `>=2.12,<3` — verified building and running a create/drop
destruction stress against both 2.12 and 2.13.

**Block data polish** (all from official 26.2 sources):

- `default_state` is now populated for all 1,196 blocks (was empty) — the
  Blocks query API returns real default property maps
- Tile-entity classification comes from the `block_entity_type` registry
  (186 blocks, was 42 by substring) — signs, banners, skulls, shelves, ...
- Light emission uses per-block emit-light data, not name guessing
- Mushroom blocks classify as full cubes

**Automated data refresh**: a weekly workflow checks Mojang's manifest and
opens a PR (regenerated data + new-blocks diff) when a new Minecraft release
ships.

---

# Nucleation v0.3.3

**Block semantics from official data, queryable everywhere.** The data
pipeline now extracts three new facets straight from the Minecraft 26.2 jars:
definition kinds + base-block links (Mojang's own variant data: oak_stairs
knows it is a `minecraft:stair` of `oak_planks`), fully-resolved vanilla
block tags (265 tags — wool, planks, mineable/pickaxe, ...), and
model-derived full-cube geometry for every block. Substring guessing is
retired: `full_blocks_only`, `exclude_transparent`, and the technical-block
exclusion are all metadata-driven now.

New in every language binding:

- **`Blocks` query API**: `get(id)` (kind, base block, tags, geometry,
  color, properties), `byTag`, `byKind`, `variantsOf(base)` (the whole
  family: stairs/slab/fence/button/...), `states(id)` (every property
  combination), `tags()`, `ids()`, `count()`
- **`PaletteBuilder.tag(...)/.excludeTag(...)/.kind(...)`** — palettes from
  real tags and kinds instead of keywords
- **Masked fills**: `BuildingTool.fillOnlyAir(...)` and
  `fillReplacing(shape, brush, targets)` for non-destructive edits
- **SDF gradient materials**: fill rules accept `gradient` (palette +
  from/to color along y or depth, or a lightness ramp) — terrain with block
  gradients from pure JSON
- **Scripting**: `palette_gradient_ids`, `palette_block_ids`,
  `palette_closest_block` in the Lua and JS engines

Java↔Bedrock mappings refreshed from GeyserMC's new NBT format, now at
**Java 26.2 parity**: 32,366 blockstate mappings, full coverage including
the 26.2 blocks, zero fallbacks.

---

# Nucleation v0.3.2

**The block database now lives inside nucleation, current to Minecraft 26.2.**
blockpedia is no longer an external dependency: block facts, Java↔Bedrock
mappings, and texture-derived colors ship in-tree (gzipped, ~330 KB) and are
generated at build time. Data targets **Java 26.2** (Mojang's new versioning),
extracted with Mojang's own data generator — 1,196 blocks including the new
cinnabar/sulfur families — with colors computed from the 26.2 client jar's
default textures (98.4% coverage, plains-biome tints applied). Refreshing for
a future release is two commands with no code changes
(`refresh-block-data` + `fetch-texture-colors`, both `--features mc-data-refresh`).

Palette upgrades for value→block workflows (heatmaps, fractals, pixel art):

- `Palette.sortedByLightness()` — any palette as a dark→light ramp
- `Palette.gradientIdsJson(r1,g1,b1, r2,g2,b2, steps)` — exactly N block ids
  sampling an Oklab gradient snapped to the palette; index by intensity
- `Palette.wood()` — the planks family, a natural wood ramp
- Default palettes exclude technical blocks (portals, fluids, fire, ...)

Also: the npm wasm now includes **simulation and meshing** (in-browser
redstone simulation works again); local Python wheel builds no longer trust a
stale rust lib.

---

# Nucleation v0.3.1

**Fixes broken v0.3.0 native release artifacts.** The v0.3.0 per-platform
libraries were built with the core `bridge` feature only, so every
meshing/simulation/rendering export was missing — PHP's eager `FFI::cdef`
could not even bind the release zip's own bindings. All native artifacts
(platform zips, JVM jar natives) now ship the full `bridge-full` surface,
matching the wheels, and CI now installs and exercises every wheel and the
assembled jar (including a simulation-symbol check) before anything ships.

Also in this release:

- **First-class palettes** in every language: `Palette` (solid / structural /
  decorative / concrete / wool / terracotta / grayscale presets, custom
  palettes from a JSON block-id list, closest-block lookup),
  `PaletteBuilder` (blockpedia filter flags + keyword include/exclude), and
  `Brush.setPalette(...)` on all color/gradient brushes — bindings are no
  longer locked to the built-in all-blocks palette. Default palettes now
  exclude technical blocks (portals, fluids, fire, piston internals).
- **JVM jar is multi-platform**: natives for linux x64/arm64, macOS
  x64/arm64, and Windows x64 are bundled in JNA layout (previously linux
  x64 only).
- **crates.io publishing works again**: the published crate ships without
  the git-only features (`simulation` — MCHPRS; `meshing`/`rendering`  schematic-mesher); use the git dependency for those.

---

# Nucleation v0.3.0

**Breaking: every language binding is now generated from a single source of truth.**

The four hand-written binding layers (C FFI via `#[no_mangle]` externs, WASM via
wasm-bindgen, Python via pyo3, JVM via hand-written JNI) and the experimental
ext-php-rs extension are gone, replaced by Diplomat-generated bindings for
C, C++, JS/WASM, Kotlin (JNA), Python (nanobind), and PHP (ext-ffi) — all generated
from `src/bridge/` by `tools/gen-bindings.sh` into `bindings/`, and regenerated +
diffed in CI so they can never go stale. The regex parity linters are deleted;
coverage vs the old 544-function C surface is enforced by
`tools/check_bridge_coverage.py` against a frozen baseline.

API changes to be aware of:
- One unified error model: every fallible call returns/raises `NucleationError`
  (12 variants). The thread-local `schematic_last_error`, per-function int/null
  sentinels, and error-string returns are gone.
- Constructors are `create`/`from_*`; accessors drop `get_`/`set_` prefixes
  (per-language casing applies, e.g. `getBlockName` in JS/PHP).
- Domain methods moved off the `Schematic` god-object onto their own types
  (`Diff`, `Fingerprint`, `Autostack`, `StoreIo`, `Renderer`, meshing types,
  `SchematicRegions`).
- Binary payloads (litematic/schem/GLB/PNG/…) cross the boundary base64-encoded
  (`*_b64` methods); arrays/lists cross as JSON strings.
- The mesh progress callback is replaced by a polling `MeshJob`
  (start → `poll_progress``take_result`).
- Memory management is generated: no more `free_*` functions anywhere.

See `src/bridge/PORTING.md` for the binding rules and
`tools/bridge_coverage/exclusions.txt` for the audited old→new name map.

**Complete API documentation across all bindings.** Every public function on
the bridge surface (509 total) now carries a doc comment, propagated by the
generator into all seven languages; the 140 previously undocumented functions
(meshing config, simulation value/layout/ordering types, transforms,
definition regions, …) were documented from their implementations, including
defaults, units, and coordinate/rotation conventions.

**Editing-operation performance.**
- `set_block_from_string` now caches parsed block strings (properties + NBT)
  per schematic, and placed block entities Arc-share the cached NBT
  (copy-on-write). Repeatedly placing the same NBT-bearing block (e.g. filled
  chests) is ~41× faster (0.30 → 12.4 M blocks/s); property-bearing blocks
  (e.g. repeaters) are ~3.6× faster (5.7 → 20.6 M blocks/s).
- `copy_region` from a single-region source (the common case) now translates
  palette indices through a precomputed source→target map instead of hashing
  a `BlockState` per block: ~3.8× faster (64 → 242 M blocks/s), same
  resulting content (covered by a fast-vs-slow-path equivalence test).

---

# Nucleation v0.2.18

Maintenance release, no user-facing API changes. The FFI layer
(`src/ffi.rs`, 10k+ lines) is now split into per-domain modules under
`src/ffi/`, matching the existing WASM/Python binding structure —
verified byte-identical exported C symbols across every feature
combination before and after. Format parsing (`src/formats/`,
`src/dataconverter/`) converged onto a proper `thiserror`-based error
type instead of ad-hoc `Box<dyn Error>`/`String` errors; the public
`UniversalSchematic::to_schematic`/`from_schematic` signatures are
unchanged. Also merged in a diff palette-swap-dominance feature that
had been sitting on an unmerged branch, cleared out several stale
branches, ran a full `clippy --fix` pass, and fixed a comparator
custom-IO test that had the wrong block orientation baked in (it now
actually exercises redpiler's IN→wire→OUT signal path instead of
silently testing nothing while ignored).

# Nucleation v0.2.17

JVM: packed bulk block export. Adds a palette + stride-4 int array
encoding for pulling large regions out of the JVM binding in one call,
instead of one JNI round-trip per block.

# Nucleation v0.2.16

SDF (signed distance field) shape and terrain generation, available
across every binding: build a schematic by sampling an SDF JSON tree
against material rules (`from_sdf` / `from_sdf_bounded`, with a
standalone `sdf_eval` for point queries). JVM also picked up
`setBlockEntity` with SNBT write support, and `from_insign` now strips
sign blocks after compiling their annotations instead of leaving them
in the output.

# Nucleation v0.2.15

Small follow-up to v0.2.14: `schematic-mesher` resolves from its
GitHub source again (a crates.io publish had briefly broken that),
plus full binding parity for the datafixer and entity/block-entity
SNBT API introduced in v0.2.14, and a `MeshOutput::from` fix so the
local (non-service) mesher path constructs by value correctly.

# Nucleation v0.2.14

The big one in this range. Relicensed the project from AGPL-3.0-only
to MIT across every file. Landed the streaming world API — constant-
memory parsing, generation, and diffing of world saves without holding
the whole world in memory, plus `.mca`/world-folder docs to match.
Added redstone graph export with integration tests, meshing
performance work (palette-indexed block sources), and merged in a
contributor's fork carrying dataconverter and litematic/entity
improvements.

Also where the JVM binding caught up hard on this window: full
`MchprsWorld` simulation parity with Python, the item-model generation
API, the redstone graph + typed circuit executor API, and a fix for
released fat JARs that had been shipping without `mchprs` compiled in
(simulation now on by default).

# Nucleation v0.2.13

Exposes `footprint()` — a translation-invariant shape fingerprint used
by the fingerprint/classification engine — as a vector across all
bindings, rather than only being reachable through the Rust API.

# Nucleation v0.2.12

New fingerprint & signature engine: canonical `Fingerprint`/`Signature`
types, symmetry-group-aware rigid transforms, an FFT-based
translation-invariant `Footprint`, a rule-based classifier with
shipped rulesets (structural, redstone computational/survival) loaded
from RON, and synthetic-fixture benchmarks. Exposed to WASM as `Diff`
and `Fingerprint` bindings. Also added synchronous Redis and S3 `Store`
backends alongside the existing filesystem one.

# Nucleation v0.2.11

Render background color and orthographic/isometric projection support
for `RenderConfig`, implemented in core and exposed across
Python/WASM/FFI (Python via a `Projection` enum, WASM/FFI via
`orthographic`/`setOrthographic`-style booleans — a documented,
intentional naming divergence, see `api_parity_exclusions.txt`). Also
fixes an `i64` overflow in `Region::coords_to_index` for large
regions.

# Nucleation v0.2.10

Build script fix. v0.2.9's `assemble-jvm-jar` job failed at the
`processResources` step under Gradle 9:

    Entry native/linux-arm64/libnucleation_jvm.so is a duplicate but no
    duplicate handling strategy has been set.

Two compounding sources of the duplicate:

1. `collectNatives` was copying `src/main/resources/native/**/*.{so,
   dylib,dll}` into `build/native-staging/`. Those files were already
   on the default resources classpath, so they got bundled twice.
2. `processResources` had no `duplicatesStrategy` set, which under
   Gradle 9 (strict by default) fails the build instead of warning.

Fixed in `nucleation-jvm/jvm/build.gradle.kts`:
- Dropped the redundant `preStaged` from() in `collectNatives` — pre-
  staged cdylibs reach the JAR through the default resources path
  alone, no need to re-copy them.
- Added `duplicatesStrategy = DuplicatesStrategy.EXCLUDE` to
  `processResources` as a safety net in case the host cargo target and
  a pre-staged cdylib happen to overlap on the same platform.

No source / API changes since v0.2.7.

v0.2.8 retired (deprecated macos-13 runner).
v0.2.9 retired (Gradle 9 duplicate-resources failure).

See v0.2.7 release notes for the feature work.