/** * archFactories — реестр стартовых арок GD по эпохам. * * 10 эпох × 5 вариантов = 50 арок. Каждая фабрика строит арку: * - две вертикальные «колонны» (cylinder/box) высотой ~4м. * - горизонтальная «балка» сверху. * - надпись «СТАРТ» (DynamicTexture на plane) посередине балки. * - подсветка/glow в стиле эпохи. * * Возвращает (scene, id) => { root: TransformNode, dispose() }. * Габариты: ширина ~3.5м, высота ~4м, центр в (0, 0, 0). */ import { MeshBuilder, StandardMaterial, Color3, Vector3, TransformNode, DynamicTexture, } from '@babylonjs/core'; // ========================================================================= // УТИЛИТЫ // ========================================================================= function makeMat(scene, name, opts = {}) { const m = new StandardMaterial(name, scene); m.diffuseColor = new Color3(...(opts.diffuse || [1, 1, 1])); m.emissiveColor = new Color3(...(opts.emissive || [0, 0, 0])); m.specularColor = new Color3(...(opts.specular || [0.2, 0.2, 0.2])); if (opts.specPower != null) m.specularPower = opts.specPower; if (opts.alpha != null) m.alpha = opts.alpha; if (opts.disableLighting) m.disableLighting = true; return m; } function makeColumn(scene, name, opts = {}) { const { height = 3.5, diameter = 0.5, shape = 'cylinder', // 'cylinder' | 'box' diffuse = [0.4, 0.3, 0.2], emissive = [0.05, 0.04, 0.03], specular, specPower, } = opts; let mesh; if (shape === 'box') { mesh = MeshBuilder.CreateBox(name, { width: diameter, height, depth: diameter }, scene); } else { mesh = MeshBuilder.CreateCylinder(name, { diameter, height, tessellation: 12, }, scene); } mesh.position.y = height / 2; mesh.material = makeMat(scene, `${name}_mat`, { diffuse, emissive, specular, specPower }); return mesh; } function makeBeam(scene, name, opts = {}) { const { width = 3.5, height = 0.5, depth = 0.5, diffuse = [0.4, 0.3, 0.2], emissive = [0.05, 0.04, 0.03], specular, specPower, } = opts; const beam = MeshBuilder.CreateBox(name, { width, height, depth }, scene); beam.material = makeMat(scene, `${name}_mat`, { diffuse, emissive, specular, specPower }); return beam; } /** Табличка с надписью «СТАРТ» (DynamicTexture на plane). */ function makeSignText(scene, name, text, opts = {}) { const { width = 2.4, height = 0.7, bgColor = '#0a1428', textColor = '#22ff66', fontSize = 96, fontFamily = 'sans-serif', emissive = [0.2, 1.0, 0.4], } = opts; const TW = 512, TH = 128; const dt = new DynamicTexture(`${name}_tex`, { width: TW, height: TH }, scene, true); const ctx = dt.getContext(); ctx.fillStyle = bgColor; ctx.fillRect(0, 0, TW, TH); ctx.fillStyle = textColor; ctx.font = `bold ${fontSize}px ${fontFamily}`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(text, TW / 2, TH / 2); dt.hasAlpha = false; dt.update(); const plane = MeshBuilder.CreatePlane(name, { width, height }, scene); const mat = new StandardMaterial(`${name}_mat`, scene); mat.diffuseTexture = dt; mat.emissiveTexture = dt; mat.emissiveColor = new Color3(...emissive); mat.disableLighting = true; mat.backFaceCulling = false; plane.material = mat; return plane; } /** Сферическая «лампочка»-glow (для гирлянд/неона). */ function makeBulb(scene, name, x, y, z, color, scale = 1) { const bulb = MeshBuilder.CreateSphere(name, { diameter: 0.18, segments: 8 }, scene); bulb.position.set(x, y, z); bulb.scaling.set(scale, scale, scale); const mat = makeMat(scene, `${name}_mat`, { diffuse: color, emissive: color, disableLighting: true }); bulb.material = mat; return bulb; } // ========================================================================= // ФАБРИКИ АРОК ПО ЭПОХАМ (по 5 на эпоху) // ========================================================================= // ----------------------------------------- Эпоха I — Лес ----- function archForestWood(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.6, GAP = 3.0; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.55, diffuse: [0.40, 0.25, 0.13], emissive: [0.10, 0.07, 0.04] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.55, diffuse: [0.40, 0.25, 0.13], emissive: [0.10, 0.07, 0.04] }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.7, height: 0.45, depth: 0.45, diffuse: [0.45, 0.28, 0.15], emissive: [0.10, 0.07, 0.04], }); beam.position.y = COL_H + 0.225; beam.parent = root; // листва — зелёная сферка над балкой for (let i = 0; i < 5; i++) { const leaf = MeshBuilder.CreateSphere(`${id}_leaf_${i}`, { diameter: 0.7 }, scene); leaf.position.set(-1.4 + i * 0.7, COL_H + 0.7, 0); const mat = makeMat(scene, `${id}_leaf_mat_${i}`, { diffuse: [0.2, 0.55, 0.25], emissive: [0.06, 0.18, 0.08], }); leaf.material = mat; leaf.parent = root; } const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { width: 2.4, height: 0.7, textColor: '#22ff66', }); sign.position.set(0, COL_H - 0.3, 0.26); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archForestStone(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.4, GAP = 3.0; const stoneDif = [0.55, 0.55, 0.50]; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.7, shape: 'box', diffuse: stoneDif, emissive: [0.10, 0.10, 0.09] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.7, shape: 'box', diffuse: stoneDif, emissive: [0.10, 0.10, 0.09] }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.9, height: 0.55, depth: 0.55, diffuse: stoneDif, emissive: [0.10, 0.10, 0.09], }); beam.position.y = COL_H + 0.275; beam.parent = root; // мох сверху for (let i = 0; i < 7; i++) { const moss = MeshBuilder.CreateSphere(`${id}_moss_${i}`, { diameter: 0.35 }, scene); moss.position.set(-1.7 + i * 0.55, COL_H + 0.55, 0); moss.material = makeMat(scene, `${id}_moss_mat_${i}`, { diffuse: [0.25, 0.5, 0.20], emissive: [0.07, 0.15, 0.05] }); moss.parent = root; } const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#88dd55' }); sign.position.set(0, COL_H - 0.3, 0.31); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archForestVine(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.6, GAP = 3.0; // тонкие колонны-ветки const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.35, diffuse: [0.32, 0.22, 0.12], emissive: [0.08, 0.05, 0.03] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.35, diffuse: [0.32, 0.22, 0.12], emissive: [0.08, 0.05, 0.03] }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; // тонкая балка const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.4, height: 0.25, depth: 0.25, diffuse: [0.32, 0.22, 0.12], emissive: [0.08, 0.05, 0.03], }); beam.position.y = COL_H + 0.125; beam.parent = root; // лианы — много зелёных мелких сфер for (let i = 0; i < 12; i++) { const x = -1.8 + i * 0.32; const dropY = 0.5 + Math.abs(Math.sin(i * 1.3)) * 0.8; for (let j = 0; j < 4; j++) { const leaf = MeshBuilder.CreateSphere(`${id}_v_${i}_${j}`, { diameter: 0.25 }, scene); leaf.position.set(x, COL_H + 0.2 - j * 0.25, 0); leaf.material = makeMat(scene, `${id}_vm_${i}_${j}`, { diffuse: [0.15 + (j % 2) * 0.1, 0.55 - j * 0.05, 0.15], emissive: [0.05, 0.18, 0.05] }); leaf.parent = root; } } const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#aaff66' }); sign.position.set(0, COL_H - 0.5, 0.16); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archForestLanterns(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.6, GAP = 3.0; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.50, diffuse: [0.30, 0.18, 0.08], emissive: [0.06, 0.04, 0.02] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.50, diffuse: [0.30, 0.18, 0.08], emissive: [0.06, 0.04, 0.02] }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.6, height: 0.35, depth: 0.35, diffuse: [0.30, 0.18, 0.08], emissive: [0.06, 0.04, 0.02], }); beam.position.y = COL_H + 0.175; beam.parent = root; // тёплые лампочки-гирлянда const colors = [[1.0, 0.85, 0.30], [1.0, 0.55, 0.20], [1.0, 0.95, 0.65]]; for (let i = 0; i < 9; i++) { const bulb = makeBulb(scene, `${id}_b_${i}`, -1.6 + i * 0.4, COL_H + 0.18 - Math.abs(Math.sin(i * 1.7)) * 0.3, 0, colors[i % colors.length], 0.9 ); bulb.parent = root; } const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#ffd76b', bgColor: '#1f1408', emissive: [0.7, 0.55, 0.15], }); sign.position.set(0, COL_H - 0.4, 0.21); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archForestRustic(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.5, GAP = 2.8; // кривые колонны (две box со слегка разным масштабом) const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.6, shape: 'box', diffuse: [0.42, 0.28, 0.16], emissive: [0.10, 0.07, 0.04] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.6, shape: 'box', diffuse: [0.42, 0.28, 0.16], emissive: [0.10, 0.07, 0.04] }); colL.position.x = -GAP / 2; colL.rotation.z = -0.05; colR.position.x = GAP / 2; colR.rotation.z = 0.05; colL.parent = root; colR.parent = root; // балка — две, на разной высоте (как ферма) const beam1 = makeBeam(scene, `${id}_beam1`, { width: GAP + 0.5, height: 0.35, depth: 0.35, diffuse: [0.45, 0.30, 0.18], emissive: [0.10, 0.07, 0.04], }); beam1.position.y = COL_H + 0.175; beam1.parent = root; const beam2 = makeBeam(scene, `${id}_beam2`, { width: GAP, height: 0.25, depth: 0.25, diffuse: [0.45, 0.30, 0.18], emissive: [0.10, 0.07, 0.04], }); beam2.position.y = COL_H - 0.5; beam2.parent = root; // X-перекрестье из досок const dr1 = makeBeam(scene, `${id}_dr1`, { width: 2.6, height: 0.18, depth: 0.18, diffuse: [0.40, 0.25, 0.13], emissive: [0.08, 0.05, 0.03], }); dr1.position.y = COL_H * 0.5; dr1.rotation.z = Math.PI / 5; dr1.parent = root; const dr2 = dr1.clone(`${id}_dr2`); dr2.rotation.z = -Math.PI / 5; dr2.parent = root; const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#ffe44a' }); sign.position.set(0, COL_H + 0.5, 0.26); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } // ----------------------------------------- Эпоха II — Горы ----- function archMountainStone(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.4, GAP = 3.0; const colDif = [0.50, 0.50, 0.55]; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.75, shape: 'box', diffuse: colDif, emissive: [0.10, 0.10, 0.11] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.75, shape: 'box', diffuse: colDif, emissive: [0.10, 0.10, 0.11] }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 1.0, height: 0.55, depth: 0.55, diffuse: colDif, emissive: [0.10, 0.10, 0.11] }); beam.position.y = COL_H + 0.275; beam.parent = root; const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#aaccff' }); sign.position.set(0, COL_H - 0.3, 0.31); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archMountainCrystal(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.6, GAP = 3.0; const xtaldif = [0.5, 0.7, 0.95], xtalem = [0.20, 0.35, 0.55]; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.55, diffuse: xtaldif, emissive: xtalem, specPower: 96 }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.55, diffuse: xtaldif, emissive: xtalem, specPower: 96 }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.6, height: 0.35, depth: 0.35, diffuse: xtaldif, emissive: xtalem }); beam.position.y = COL_H + 0.175; beam.parent = root; const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#aaeeff' }); sign.position.set(0, COL_H - 0.4, 0.21); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archMountainIce(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.5, GAP = 3.0; const icedif = [0.80, 0.92, 1.0], iceem = [0.25, 0.35, 0.50]; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.55, diffuse: icedif, emissive: iceem, specPower: 128 }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.55, diffuse: icedif, emissive: iceem, specPower: 128 }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.6, height: 0.35, depth: 0.35, diffuse: icedif, emissive: iceem }); beam.position.y = COL_H + 0.175; beam.parent = root; const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#ddffff' }); sign.position.set(0, COL_H - 0.4, 0.21); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archMountainPeak(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.8, GAP = 3.0; const colDif = [0.40, 0.45, 0.50]; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.6, shape: 'box', diffuse: colDif, emissive: [0.05, 0.06, 0.07] }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.6, shape: 'box', diffuse: colDif, emissive: [0.05, 0.06, 0.07] }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; // вместо балки — пирамидальная крыша из 2-х наклонённых box const sideA = makeBeam(scene, `${id}_a`, { width: GAP * 0.7, height: 0.4, depth: 0.4, diffuse: colDif, emissive: [0.05, 0.06, 0.07] }); sideA.position.set(-GAP * 0.27, COL_H + GAP * 0.27, 0); sideA.rotation.z = -Math.PI / 4; sideA.parent = root; const sideB = sideA.clone(`${id}_b`); sideB.position.set(GAP * 0.27, COL_H + GAP * 0.27, 0); sideB.rotation.z = Math.PI / 4; sideB.parent = root; const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#88aacc' }); sign.position.set(0, COL_H - 0.6, 0.31); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } function archMountainBronze(scene, id) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = 3.6, GAP = 3.0; const brz = [0.55, 0.38, 0.18]; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: 0.5, diffuse: brz, emissive: [0.15, 0.08, 0.03], specPower: 96 }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: 0.5, diffuse: brz, emissive: [0.15, 0.08, 0.03], specPower: 96 }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.8, height: 0.45, depth: 0.45, diffuse: brz, emissive: [0.15, 0.08, 0.03] }); beam.position.y = COL_H + 0.225; beam.parent = root; const sign = makeSignText(scene, `${id}_sign`, 'СТАРТ', { textColor: '#ffd76b' }); sign.position.set(0, COL_H - 0.3, 0.26); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } // ----------------------------------------- Эпохи III-X — упрощённые шаблоны ----- function archGeneric(scene, id, palette) { const root = new TransformNode(`arch_${id}`, scene); const COL_H = palette.colH || 3.5, GAP = palette.gap || 3.0; const colL = makeColumn(scene, `${id}_colL`, { height: COL_H, diameter: palette.colDia || 0.55, shape: palette.shape || 'cylinder', diffuse: palette.colDif, emissive: palette.colEm, specPower: palette.specPower, }); const colR = makeColumn(scene, `${id}_colR`, { height: COL_H, diameter: palette.colDia || 0.55, shape: palette.shape || 'cylinder', diffuse: palette.colDif, emissive: palette.colEm, specPower: palette.specPower, }); colL.position.x = -GAP / 2; colR.position.x = GAP / 2; colL.parent = root; colR.parent = root; const beam = makeBeam(scene, `${id}_beam`, { width: GAP + 0.6, height: palette.beamH || 0.35, depth: 0.35, diffuse: palette.beamDif || palette.colDif, emissive: palette.beamEm || palette.colEm, }); beam.position.y = COL_H + (palette.beamH || 0.35) / 2; beam.parent = root; // бонус — например лампочки или сферки if (palette.bulbs) { for (let i = 0; i < palette.bulbs.count; i++) { const b = makeBulb(scene, `${id}_bulb_${i}`, -GAP / 2 + (i + 0.5) * (GAP / palette.bulbs.count), COL_H + 0.5, 0, palette.bulbs.color ); b.parent = root; } } const sign = makeSignText(scene, `${id}_sign`, palette.signText || 'СТАРТ', { textColor: palette.signColor || '#ffffff', bgColor: palette.signBg || '#0a1428', emissive: palette.signEm || [0.5, 0.5, 0.5], }); sign.position.set(0, COL_H - 0.4, 0.21); sign.parent = root; return { root, dispose: () => { for (const ch of root.getChildMeshes()) ch.dispose(); root.dispose(); } }; } // ========================================================================= // КАТАЛОГ // ========================================================================= const GENERIC_EPOCHS = { 3: [ { name: 'Город хром', colDif:[0.65,0.65,0.7], colEm:[0.15,0.15,0.18], signColor:'#22ccff', specPower:128 }, { name: 'Город неон', colDif:[0.10,0.10,0.20], colEm:[0.10,0.30,0.60], signColor:'#22ddff', signEm:[0.1,0.6,1.0] }, { name: 'Город бетон', colDif:[0.55,0.55,0.55], colEm:[0.10,0.10,0.10], signColor:'#cccccc' }, { name: 'Граффити', colDif:[0.20,0.20,0.25], colEm:[0.05,0.05,0.07], signColor:'#ff44aa', signBg:'#2a0a1a', signEm:[0.8,0.2,0.5] }, { name: 'Город жёлтый', colDif:[0.85,0.65,0.10], colEm:[0.30,0.20,0.05], signColor:'#000', signBg:'#ffe44a', signEm:[1,0.85,0.1] }, ], 4: [ { name: 'Ночной фиолет', colDif:[0.35,0.10,0.50], colEm:[0.35,0.10,0.60], signColor:'#ff88ff', signEm:[0.7,0.3,0.9] }, { name: 'Ночной циан', colDif:[0.10,0.40,0.50], colEm:[0.10,0.50,0.65], signColor:'#88eeff', signEm:[0.3,0.8,1.0] }, { name: 'Ночной розовый', colDif:[0.80,0.20,0.45], colEm:[0.55,0.15,0.30], signColor:'#ff88aa', signEm:[1.0,0.4,0.7] }, { name: 'Ночной жёлтый', colDif:[0.85,0.65,0.10], colEm:[0.55,0.40,0.05], signColor:'#ffee88', signEm:[1,0.85,0.2] }, { name: 'Голограмма', colDif:[0.30,0.50,1.0], colEm:[0.40,0.70,1.0], signColor:'#ffffff', signEm:[0.6,0.8,1.0] }, ], 5: [ { name: 'Пустыня песчаник', colDif:[0.75,0.62,0.38], colEm:[0.18,0.13,0.07], signColor:'#5a3a18' }, { name: 'Пустыня терракота', colDif:[0.65,0.30,0.15], colEm:[0.20,0.07,0.03], signColor:'#ffd76b' }, { name: 'Пустыня кость', colDif:[0.85,0.80,0.65], colEm:[0.25,0.20,0.12], signColor:'#3a2a1a' }, { name: 'Пустыня кактус', colDif:[0.30,0.50,0.25], colEm:[0.07,0.15,0.07], signColor:'#ffffff' }, { name: 'Пустыня закат', colDif:[0.85,0.40,0.20], colEm:[0.45,0.15,0.05], signColor:'#ffe44a', signEm:[1,0.5,0.1] }, ], 6: [ { name: 'Океан коралл', colDif:[0.90,0.40,0.50], colEm:[0.30,0.10,0.15], signColor:'#ffffff' }, { name: 'Океан синий', colDif:[0.10,0.40,0.65], colEm:[0.05,0.20,0.35], signColor:'#aaeeff' }, { name: 'Океан жемчуг', colDif:[0.85,0.85,0.95], colEm:[0.20,0.20,0.30], signColor:'#3a5a7a', specPower:128 }, { name: 'Океан водоросль', colDif:[0.20,0.50,0.30], colEm:[0.07,0.20,0.10], signColor:'#aaffaa' }, { name: 'Океан бирюза', colDif:[0.10,0.65,0.65], colEm:[0.10,0.40,0.40], signColor:'#ffffff' }, ], 7: [ { name: 'Пещеры камень', colDif:[0.35,0.30,0.25], colEm:[0.07,0.05,0.04], signColor:'#aa8855' }, { name: 'Пещеры кварц', colDif:[0.55,0.45,0.75], colEm:[0.20,0.15,0.40], signColor:'#ddccff' }, { name: 'Пещеры гриб', colDif:[0.55,0.20,0.20], colEm:[0.25,0.08,0.08], signColor:'#ffffff' }, { name: 'Пещеры мох', colDif:[0.20,0.50,0.30], colEm:[0.20,0.55,0.30], signColor:'#aaff88', signEm:[0.3,0.8,0.4] }, { name: 'Пещеры алмаз', colDif:[0.75,0.85,0.95], colEm:[0.35,0.40,0.45], signColor:'#ffffff', specPower:128 }, ], 8: [ { name: 'Вулкан лава', colDif:[0.30,0.10,0.05], colEm:[0.50,0.15,0.02], signColor:'#ffaa00', signEm:[1,0.5,0.05] }, { name: 'Вулкан обсидиан', colDif:[0.10,0.05,0.10], colEm:[0.05,0.02,0.05], signColor:'#aa44aa', specPower:128 }, { name: 'Вулкан магма', colDif:[0.55,0.25,0.05], colEm:[0.85,0.40,0.08], signColor:'#ffff55', signEm:[1,1,0.3] }, { name: 'Вулкан пепел', colDif:[0.25,0.22,0.22], colEm:[0.05,0.04,0.04], signColor:'#ff5555' }, { name: 'Вулкан огонь', colDif:[0.45,0.15,0.05], colEm:[0.85,0.30,0.05], signColor:'#ffee00', signEm:[1,0.9,0.1] }, ], 9: [ { name: 'Космос звезда', colDif:[0.45,0.40,0.10], colEm:[0.65,0.55,0.15], signColor:'#ffffaa' }, { name: 'Космос плазма', colDif:[0.30,0.55,0.95], colEm:[0.40,0.80,1.00], signColor:'#aaffff' }, { name: 'Космос лазер', colDif:[0.80,0.10,0.50], colEm:[0.95,0.20,0.80], signColor:'#ffaaff', signEm:[1,0.4,1] }, { name: 'Космос туманность', colDif:[0.55,0.25,0.85], colEm:[0.50,0.20,0.85], signColor:'#ffccff' }, { name: 'Космос луна', colDif:[0.65,0.65,0.65], colEm:[0.35,0.35,0.35], signColor:'#bbbbbb' }, ], 10: [ { name: 'Кибер зелёный', colDif:[0.10,0.80,0.30], colEm:[0.20,1.00,0.40], signColor:'#aaffaa', signEm:[0.2,1.0,0.4] }, { name: 'Кибер фиолет', colDif:[0.55,0.15,0.85], colEm:[0.70,0.25,1.00], signColor:'#ffaaff' }, { name: 'Кибер красный', colDif:[0.85,0.10,0.30], colEm:[0.90,0.20,0.40], signColor:'#ffaaaa' }, { name: 'Кибер голограмма', colDif:[0.30,0.50,1.0], colEm:[0.50,0.85,1.0], signColor:'#ffffff' }, { name: 'Кибер жёлтый', colDif:[0.85,0.85,0.10], colEm:[0.85,0.85,0.15], signColor:'#000', signBg:'#ffff44', signEm:[1,1,0.3] }, ], }; export const ARCH_CATALOG = []; const epoch1 = [ { id: 'a1_v1', title: 'Деревянная', make: archForestWood }, { id: 'a1_v2', title: 'Каменная', make: archForestStone }, { id: 'a1_v3', title: 'С лианами', make: archForestVine }, { id: 'a1_v4', title: 'С фонариками', make: archForestLanterns }, { id: 'a1_v5', title: 'Рустик', make: archForestRustic }, ]; for (const a of epoch1) ARCH_CATALOG.push({ ...a, epoch: 1 }); const epoch2 = [ { id: 'a2_v1', title: 'Каменная', make: archMountainStone }, { id: 'a2_v2', title: 'Кристалл', make: archMountainCrystal }, { id: 'a2_v3', title: 'Ледяная', make: archMountainIce }, { id: 'a2_v4', title: 'Пиковая', make: archMountainPeak }, { id: 'a2_v5', title: 'Бронзовая', make: archMountainBronze }, ]; for (const a of epoch2) ARCH_CATALOG.push({ ...a, epoch: 2 }); for (let epoch = 3; epoch <= 10; epoch++) { const palettes = GENERIC_EPOCHS[epoch] || []; for (let i = 0; i < palettes.length; i++) { const palette = palettes[i]; ARCH_CATALOG.push({ id: `a${epoch}_v${i + 1}`, epoch, title: palette.name, make: (scene, id) => archGeneric(scene, id, palette), }); } } export const EPOCH_INFO = [ { n: 1, name: 'Лес', emoji: '🌲', color: '#3a7a4a' }, { n: 2, name: 'Горы', emoji: '🏔', color: '#aaccff' }, { n: 3, name: 'Город днём', emoji: '🏙', color: '#7a8aaa' }, { n: 4, name: 'Город ночью', emoji: '🌃', color: '#1a1a3a' }, { n: 5, name: 'Пустыня', emoji: '🏜', color: '#c8a575' }, { n: 6, name: 'Океан', emoji: '🌊', color: '#3a8aaa' }, { n: 7, name: 'Пещеры', emoji: '🕳', color: '#3a3a3a' }, { n: 8, name: 'Вулкан', emoji: '🌋', color: '#8a2a2a' }, { n: 9, name: 'Космос', emoji: '🚀', color: '#3a1a5a' }, { n: 10, name: 'Кибер', emoji: '🤖', color: '#ff00ff' }, ]; export function getArchesByEpoch(epoch) { return ARCH_CATALOG.filter(a => a.epoch === epoch); }