FOUNDATION 04 · PLAYER-MADE EQUIPMENT

Shape locally, inherit real materials, verify the inputs

The forge is an editable 3D workbench powered by Chunk.js. Players move material pieces, work specific faces with visible tools, combine connected parts, paint cloth, and export a compact NCF1 design. On chain, the backpack program checks the selected material slots and three authoritative capacity totals—not the animation or every triangle.

10 min read
The canonical villager boy hammers a selected side face of a supported multi-material assembly while the villager girl paints a cotton-cloth panel; real forge tools, an XYZ material gizmo, backpack resources, abstract capacity scales, and a gently waving finished item form one game-anime quest scene.

Key points

The material is not just a color

The live workbench draft binds structural components to backpack material records and uses their volume, density, heat, surface preview, and twelve equipment scores. Slot durability and quality remain chain-capacity inputs rather than inherited design scores.

The design travels as NCF1

Chunk.js canonically encodes equipment statistics and component or baked-surface geometry into at most 640 raw bytes, then rebuilds a render mesh from that code.

On-chain scope is deliberately narrow

The program verifies valid material records inside the signer's PDA-validated backpack and checks that selected volume, effective durability, and mass are each greater than or equal to the three NCF1 requirements. Surplus is allowed.

CHUNK.JS WORKBENCH

Editing is a deterministic material operation, not a loose model import

A forge component owns a fixed 14 × 10 × 14 occupancy grid, quantized dimensions and position, one of six NCF1 resource classes, RGB444 color, optional grip, paint surfaces, and workbench-only machining history. Exact backpack slot, item, and recipe-material binding lives beside the component in the live draft. Hammer, saw, hand drill, taper, grip, paint, rotation, and translation operations resolve against the shared grid.

The renderer and transform share hit-to-face snapping inputs—axis, side, plane, and center—so the crosshair and precision coordinates identify the selected construction location. They do not display the full affected-cell mask. Floor and occupied-voxel collision always apply, swept translation prevents tunneling, and deterministic settling is active only in Surface mode with a non-glove construction tool; glove or Object mode keeps pieces where the player positions them.

Machining history preserves holes and kerfs across admissible hammer or normalize deformation and rejects a deformation when the fixed grid can no longer preserve its physical footprint or cell budget. Casting requires positive-area shared occupied-voxel faces, then locks and moves the connected assembly as a group; it does not boolean-union the component masks.

Component grid 14 × 10 × 14

Cutting, drilling, deformation, meshing, occupied bounds, and collision share one finite lattice.

Workbench inputs Up to 24 components

The editor permits 24 structural components, while the chain instruction permits 24 total unique slots including every distinct used dye.

Edit scopes Inspect · Object · Surface

Selection and movement are separated from face-specific construction tools.

WHAT MATERIALS CONTRIBUTE

Used material mass carries properties into the design

The forge maps live smelted material records into workbench profiles. A particular smelt's attributes take priority over the recipe's base profile when available. As cutting and drilling remove occupied cells, the workbench recalculates how much of each input volume remains used. This exact slot and item binding belongs to the draft; NCF1 retains the resource class, RGB444 appearance, geometry, grip, and paint rather than the original recipe-material identity.

The design's twelve equipment scores are inherited with used-volume and density mass weighting. Mass, volume, material breakdown, heat, center-of-mass advice, and grip-torque advice are derived from the same edited components. Current and maximum slot durability plus quality basis points are chain capacity and output inputs, not direct inheritance weights for those twelve scores.

  • Hardness, durability, toughness, ductility, brittleness, and density describe structural character.
  • Heat resistance, corrosion resistance, conductivity, thermal conductivity, magnetism, and workability complete the twelve-score equipment profile.
  • Stable slot and item identity prevents a stale draft from rebinding during client refresh. The transaction commits only slot indexes, so this identity match is client-side preflight rather than an on-chain item-identity assertion.
  • Unused input volume is reported separately; the program later consumes the selected material items as whole backpack slots.

THE DESIGN ENVELOPE

NCF1 is a compact reconstruction recipe

NCF1 version 15 starts with integer equipment data—mass, packed millimetre-scale volume, and twelve compact scores—then carries either editable components or a baked appearance surface. Version 15 is the only accepted format: retired version 14 codes are rejected instead of being migrated or decoded through a legacy fallback. Chunk.js canonical encoding makes equivalent accepted client input resolve to one normalized byte representation. The deployed program later hashes submitted bytes into a compact 32-bit check value; that value is not a collision-resistant content identity.

Before export, the local workbench draft remains the editable source. At submission, Chunk.js can rasterize components into a 24 × 24 × 24 appearance grid and chooses that representation only when it is strictly smaller. If appearance mode wins, the emitted code is appearance-only and cannot reconstruct the original components. Automatic selection keeps any component-cloth design component encoded so its component identity can drive motion; a manually imported appearance-mode cloth design is legal but static.

Format prefix NCF1.

The readable prefix wraps a base64url representation of canonical raw bytes.

Raw byte ceiling 640 bytes

The codec, transaction builder, SDK, and program share the raw ceiling. Full canonical geometry validation happens in the forge page, not in the SDK or on-chain parser.

Runtime cache budget 24 entries · 8 MiB

The shared default cache avoids decoding and rebuilding the same forged mesh every frame or appearance refresh.

EXACT ON-CHAIN CHECKS

The verifier requires valid slots and three sufficient totals

Before submission, the client refreshes the equipped backpack and matches every selected source by slot, item identity, and mutable record fields. The client sends the canonicalized NCF1 bytes plus unique material slot indexes; the identity snapshot itself is not included in the instruction. The program validates the signer, player profile relationships, backpack owner and PDA, selected indexes, and that every indexed record is a live material item with valid metadata and nonzero durability.

From the NCF1 equipment header, the program derives required volume, required effective durability, and output mass. From the selected backpack records, it sums validated volume and mass and calculates effective durability by summing each capped durability times quality basis points before one final division by 10,000. All three capacities must be greater than or equal to the requirements. The owner-derived PlayerSkills account supplies the Forging level; a missing System-owned account means level zero, while malformed present data is rejected.

  1. Question 1: Are these materials in this backpack?

    Every unique index must exist in the validated owner backpack and point to a valid material-category record. Structural inputs and one whole slot for every distinct used dye share the same 24-index limit.

  2. Question 2: Are all three capacities sufficient?

    totalVolumeMm3 ≥ requiredVolumeMm3, totalEffectiveDurability ≥ requiredEffectiveDurability, and totalMassGrams ≥ outputMassGrams.

  3. Consume and append

    After all checks pass, the program creates one immutable ForgedItem PDA containing the complete NCF1 bytes, removes the selected material slots, and appends one forged backpack record pointing to that account. Record volume and mass come from the NCF1 header; durability, grade, item level, and volume-weighted quality come from the selected materials and Forging level. The same transaction updates Profile forging history and synchronizes PlayerSkills.

WHAT CONSENSUS DOES NOT REPLAY

Geometry has identity, but it is not the material gate

The backpack program parses only the first 108 bits—a 4-bit NCF1 version plus a 104-bit equipment header—derives three requirements, enforces the 640-byte envelope, and hashes all submitted bytes. It does not decode the remaining component or baked-surface geometry, enforce canonical encoding, replay hammer swings, re-run mesh generation, or judge a silhouette.

The forged Backpack record stores item code 8, an item ID, a unique item_pda, NCF1-derived volume and mass, material-derived durability, grade, item level and quality, and the 32-bit FNV-1a design hash. The record itself does not contain geometry or material provenance. Its item_pda names a newly created 752-byte immutable ForgedItem account that stores the complete validated NCF1 bytes, creator, origin Backpack, item ID, hash, and timestamps. A fresh client can therefore reconstruct the model from chain state; browser storage is only a cache. The 32-bit hash alone is still not collision-resistant proof of unique content.

MATERIAL LIFE CYCLE

Recipes create materials; the forge edits what already exists

Smelting rules are a separate bounded system that turns recipe inputs into material backpack items. The current cotton-cloth recipe uses four cotton blocks and one dry-grass block. The forge consumes the resulting cloth material; it does not independently invent cloth from raw plants.

Paint can color exposed grid faces of any component with the supported white, yellow, red, blue, or pink palette. One whole live dye slot for every distinct used color joins the structural slots, counts toward the 24-input limit, contributes to capacity and outcome totals, and is consumed. NCF1 stores RGB444 paint quads rather than dye identity.

Component-encoded cloth keeps the identity needed for motion. The workbench shader applies a bounded analytic wind displacement, while the avatar renderer updates deployed cloth vertices on the CPU when the item has a grip for attachment. This is not a full cloth solver with self-collision. Reduced-motion settings lower the animation rather than changing the stored design.

MATERIAL CAPACITY MATH

One compact header sets the requirement; selected slots supply capacity

The first equation is the exact integer-style requirement derived from the NCF1 equipment prefix. The second mirrors the three aggregate comparisons performed before the selected material slots are consumed.

Header-derived volume, effective-durability, and mass requirements

M_req = 5*mass5g; e = encodedVolume >> 13; m = encodedVolume & 8191; V_req = m*2^(4e); D_req = max(1, ceil(3*M_req/20) + 18*isqrt(floor(V_req/1000)) + floor(ceil(126*S/25)*min(V_req,1000000)/1000000))

The parser reads mass5g, the version-15 packed millimetre-volume field, and twelve compact scores from the first 108 bits. S is the saturated integer material score from durability, toughness, hardness, workability, ductility, and a brittleness penalty. Output mass is itself the third required value.

V_req
Required material volume in cubic millimeters.
D_req
Required aggregate effective durability.
M_req
Required output mass in grams and the minimum selected-material mass.
isqrt
Integer square root, matching the program's bounded arithmetic.
S
The integer structural score derived from six of the twelve compact design attributes.

Selected-slot capacity and acceptance

V_cap = sum_i(volume_mm3_i); D_cap = floor(sum_i(min(dur_cur_i,max(1,dur_max_i))*clamp(quality_bps_i,1,10000))/10000); M_cap = sum_i(mass_g_i); accept iff V_cap >= V_req AND D_cap >= D_req AND M_cap >= M_req

Each unique selected slot contributes once; quantity is not a multiplier. The program sums every quality-weighted durability numerator before one final division. Structural materials and every distinct used dye slot enter all applicable totals and are consumed as whole slots after all three comparisons pass.

V_cap
Sum of raw volumeMm3 across selected live material records.
D_cap
Sum of quality-scaled, current-capped durability across selected records.
M_cap
Sum of validated mass in grams across selected material records.
quality_bps_i
The selected slot's quality in basis points, clamped to 1 through 10,000.

The forge page performs full canonical validation before submission

JavaScript forging/forging.js
function verifyChainCode(code) {
  const normalizedCode = String(code ?? "").trim();
  const design = decodeNcf1(normalizedCode, { requireCanonical: true });
  const bytes = encodeNcf1Bytes(design);
  if (bytes.length > NCF1_MAX_RAW_BYTES) throw new RangeError("Forge code exceeds the chain transaction budget.");
  return {
    code: normalizedCode,
    design,
    proof: { ...forgeMaterialRequirements(bytes), byteLength: bytes.length },
  };
}

The browser page fully decodes, canonicalizes, and re-encodes the design. The transaction builder, SDK, and program share the 640-byte raw ceiling but do not replay this full geometry validation.

Capacity is checked before whole selected slots are removed

Rust programs/nicechunk_backpack/src/state.rs
        if let Some(required) = requirements {
            let capacity = forge_material_capacity(&materials)?;
            if !capacity.satisfies(&required) {
                return Err(NicechunkBackpackError::InsufficientForgeMaterialParameters.into());
            }
        }

        let mut outcome = calculate_forge_outcome(&materials, forging_level);
        if let Some(required) = requirements {
            outcome.volume_mm3 = required.required_volume_mm3.min(u32::MAX as u64) as u32;
            outcome.mass_grams = required.output_mass_grams;
        } else {
            outcome.mass_grams = materials
                .iter()
                .filter_map(|material| material.mass_grams().ok())
                .fold(0_u32, u32::saturating_add);
        }
        Self::remove_resources_at(data, owner, indexes, updated_slot)?;
        let mut output = BackpackSlotRecord {
            kind: BACKPACK_SLOT_KIND_ITEM,
            category: BACKPACK_ITEM_CATEGORY_FORGED,
            flags: 0,
            quantity: 1,
            resource: BackpackResourceRecord::default(),
            item_code: BACKPACK_FORGED_ITEM_CODE,
            item_id,
            item_pda: *item_pda,
            volume_mm3: outcome.volume_mm3,
            durability_current: outcome.durability_max,
            durability_max: outcome.durability_max,
            grade: outcome.grade,
            item_level: outcome.item_level,
            quality_bps: outcome.quality_bps,
            metadata: design_hash,
        };
        output.set_mass_grams(outcome.mass_grams)?;
        Self::append_item(data, owner, &output, updated_slot)?;
        Ok(outcome)

A capacity deficit aborts before consumption. Verified geometry replaces provisional output volume and mass before selected material slots are removed and one forged record is appended.

IMPLEMENTATION EVIDENCE

Where these claims come from

Each claim is intentionally scoped to a concrete implementation path. These references are for verification, not decoration.

forging/forging.js

Owns live draft bindings, editing modes, conditional settling, connected assembly casting, dye-slot collection, strict-smaller export selection, and full canonical preflight.

chunk.js/forge/forge-workbench.js

Defines material profiles, component grids, face tools, machining state, collision, gravity, connectivity, inheritance, statistics, and physical advisories.

chunk.js/forge/forge-core.js

Defines canonical NCF1 v15 as the only accepted format, component and appearance encodings, compact selection, design hashes, the three material requirements, and the 640-byte ceiling.

chunk.js/forge/forge-mesher.js

Builds packed render meshes and pick bounds from canonical design geometry.

chunk.js/forge/forge-runtime-cache.js

Restores canonical designs into read-only runtime assets with bounded entry and memory budgets.

chunk.js/renderer/forge-workbench-renderer.js

Renders the workbench, material surfaces, tools, axis gizmos, construction reticles, collision-aware dragging, and procedural cloth wind.

chunk.js/renderer/forge-tool-visuals.js

Provides compact 3D tool models and preview/action poses for hammer, saw, drill, grip, axe, and paint brush.

forging/chain-adapter.js

Maps live backpack materials, preserves stable slot identity, rejects retired or duplicate inputs, and submits canonical material-verifying forge requests.

programs/nicechunk_backpack/src/state.rs

Derives volume, effective-durability, and mass requirements from the NCF1 prefix; sums all three selected-material capacities; consumes whole slots; stores NCF1-derived output volume and mass; and defines the immutable 752-byte ForgedItem layout.

programs/nicechunk_backpack/src/lib.rs

Disables the legacy unverified forge instruction, routes tag 8 through verified design and material processing, creates one unique ForgedItem PDA, records Profile forging history, and participates in the transaction's PlayerSkills synchronization.

src/data/smeltingRules.js

Defines the forge-ready material catalog, attribute profiles, dyes, and the separate cotton-cloth recipe.

chunk.js/renderer/avatar-mesh.js

Reconstructs validated forged designs supplied by chain hydration or browser cache, attaches grip-bound equipment, and updates component-cloth vertices over time with reduced-motion support.