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;
}