Factory function to create Voxel Jewel Chest in your world.

export function createAsset(THREE, options = {}) {
  const group = new THREE.Group();
  group.name = 'voxel_jewel_chest';

  const scale = options.scale == null ? 1 : Number(options.scale);
  const woodColor = options.woodColor || '#4a2418';
  const goldColor = options.goldColor || '#f2b84b';
  const gemPalette = options.gemPalette || 'rainbow';
  const showKeyhole = options.showKeyhole !== false;

  group.scale.setScalar(scale);

  function makeMaterial(name, color, roughness, metalness) {
    const material = new THREE.MeshStandardMaterial({
      color: new THREE.Color(color),
      roughness: roughness,
      metalness: metalness
    });
    material.name = name;
    return material;
  }

  function makeBox(name, partId, size, position, material) {
    const mesh = new THREE.Mesh(new THREE.BoxGeometry(size[0], size[1], size[2]), material);
    mesh.name = name;
    mesh.position.set(position[0], position[1], position[2]);
    mesh.userData.partId = partId;
    return mesh;
  }

  const wood = makeMaterial('dark_wood', woodColor, 0.74, 0.02);
  const woodShadow = makeMaterial('wood_shadow', '#2a130f', 0.82, 0.01);
  const gold = makeMaterial('soft_gold', goldColor, 0.36, 0.72);
  const hingeGold = makeMaterial('warm_hinge_gold', '#d99b30', 0.42, 0.76);
  const keyholeDark = makeMaterial('keyhole_dark', '#21110b', 0.68, 0.08);
  const sparkleGold = makeMaterial('sparkle_gold', '#fff4a8', 0.2, 0.18);

  const base = new THREE.Group();
  base.name = 'base';
  base.userData.partId = 'base';
  base.userData.selection = { id: 'base', kind: 'scene', label: 'Chest Base' };
  group.add(base);

  base.add(makeBox('base_wood_block', 'base', [2.2, 0.78, 1.28], [0, 0.38, 0], wood));
  base.add(makeBox('base_front_shadow', 'base', [2.24, 0.16, 0.08], [0, 0.12, 0.68], woodShadow));
  base.add(makeBox('front_top_gold_rail', 'base', [2.28, 0.12, 0.1], [0, 0.72, 0.69], gold));
  base.add(makeBox('front_bottom_gold_rail', 'base', [2.28, 0.1, 0.1], [0, 0.08, 0.69], gold));
  base.add(makeBox('left_base_gold_band', 'base', [0.16, 0.86, 1.38], [-0.78, 0.43, 0], gold));
  base.add(makeBox('right_base_gold_band', 'base', [0.16, 0.86, 1.38], [0.78, 0.43, 0], gold));
  base.add(makeBox('left_gold_foot', 'base', [0.34, 0.16, 0.26], [-0.72, -0.02, 0.42], gold));
  base.add(makeBox('right_gold_foot', 'base', [0.34, 0.16, 0.26], [0.72, -0.02, 0.42], gold));

  const lid = new THREE.Group();
  lid.name = 'lid';
  lid.position.set(0, 0.82, -0.62);
  lid.userData.partId = 'lid';
  lid.userData.selection = { id: 'lid', kind: 'scene', label: 'Rear Pivot Lid' };
  group.add(lid);

  lid.add(makeBox('lid_wood_slab', 'lid', [2.24, 0.34, 1.2], [0, 0.13, 0.55], wood));
  lid.add(makeBox('lid_front_gold_lip', 'lid', [2.28, 0.22, 0.14], [0, 0, 1.16], gold));
  lid.add(makeBox('lid_top_gold_rail', 'lid', [2.28, 0.12, 0.12], [0, 0.34, 0.56], gold));
  lid.add(makeBox('left_lid_gold_band', 'lid', [0.16, 0.44, 1.22], [-0.78, 0.14, 0.56], gold));
  lid.add(makeBox('right_lid_gold_band', 'lid', [0.16, 0.44, 1.22], [0.78, 0.14, 0.56], gold));
  lid.add(makeBox('rear_lid_hinge_bar', 'lid', [1.72, 0.14, 0.12], [0, 0.12, 0.02], hingeGold));

  const lock = new THREE.Group();
  lock.name = 'lock';
  lock.position.set(0, 0.54, 0.73);
  lock.userData.partId = 'lock';
  lock.userData.selection = { id: 'lock', kind: 'scene', label: 'Gold Lock Plate' };
  group.add(lock);
  lock.add(makeBox('lock_plate', 'lock', [0.42, 0.48, 0.12], [0, 0, 0], gold));
  lock.add(makeBox('lock_top_cap', 'lock', [0.28, 0.1, 0.14], [0, 0.25, 0], hingeGold));
  if (showKeyhole) {
    lock.add(makeBox('keyhole_slot', 'lock', [0.1, 0.22, 0.14], [0, -0.03, 0.03], keyholeDark));
    lock.add(makeBox('keyhole_dot', 'lock', [0.16, 0.12, 0.14], [0, 0.11, 0.03], keyholeDark));
  }

  const leftHinge = new THREE.Group();
  leftHinge.name = 'left_hinge';
  leftHinge.position.set(-0.66, 0.82, -0.72);
  leftHinge.userData.partId = 'left_hinge';
  leftHinge.userData.selection = { id: 'left_hinge', kind: 'scene', label: 'Left Hinge' };
  group.add(leftHinge);
  leftHinge.add(makeBox('left_hinge_block', 'left_hinge', [0.42, 0.22, 0.18], [0, 0, 0], hingeGold));
  leftHinge.add(makeBox('left_hinge_pin', 'left_hinge', [0.5, 0.08, 0.08], [0, 0, -0.02], gold));

  const rightHinge = new THREE.Group();
  rightHinge.name = 'right_hinge';
  rightHinge.position.set(0.66, 0.82, -0.72);
  rightHinge.userData.partId = 'right_hinge';
  rightHinge.userData.selection = { id: 'right_hinge', kind: 'scene', label: 'Right Hinge' };
  group.add(rightHinge);
  rightHinge.add(makeBox('right_hinge_block', 'right_hinge', [0.42, 0.22, 0.18], [0, 0, 0], hingeGold));
  rightHinge.add(makeBox('right_hinge_pin', 'right_hinge', [0.5, 0.08, 0.08], [0, 0, -0.02], gold));

  const gemColors = gemPalette === 'cool'
    ? ['#55d6ff', '#8a7cff', '#71f2b0', '#ffffff']
    : gemPalette === 'warm'
      ? ['#ff6b8a', '#ffb33d', '#ffe066', '#ff8c42']
      : ['#55d6ff', '#ff5ca8', '#ffe066', '#71f2b0', '#a887ff'];

  const gems = new THREE.Group();
  gems.name = 'gems';
  gems.position.set(0, 0.93, 0.03);
  gems.userData.partId = 'gems';
  gems.userData.selection = { id: 'gems', kind: 'scene', label: 'Colorful Gems' };
  group.add(gems);

  const gemPositions = [[-0.48, 0, 0.02], [-0.22, 0.04, 0.22], [0.06, 0, -0.03], [0.34, 0.03, 0.18], [0.56, 0, -0.12]];
  for (let i = 0; i < gemPositions.length; i++) {
    const gemMaterial = makeMaterial('gem_' + i, gemColors[i % gemColors.length], 0.24, 0.08);
    const gem = makeBox('voxel_gem_' + (i + 1), 'gems', [0.2, 0.18 + (i % 2) * 0.06, 0.2], gemPositions[i], gemMaterial);
    gem.rotation.y = i * 0.45;
    gems.add(gem);
  }
  gems.add(makeBox('sparkle_pixel_top', 'gems', [0.08, 0.08, 0.08], [0.18, 0.34, 0.04], sparkleGold));
  gems.add(makeBox('sparkle_pixel_left', 'gems', [0.06, 0.06, 0.06], [-0.36, 0.26, 0.28], sparkleGold));

  return group;
}