Органайзер для кошачьего корма: 3D-модель, STL для печати, просмотрщик

This commit is contained in:
apuc committed 2026-09-29 12:43:43 +03:00
commit bd44338cbd
19 files changed
+61107

No files matched your search

+111
View File
@@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Органайзер для кошачьего корма — сравнение</title>
<style>
body { margin:0; overflow:hidden; font-family:'Segoe UI',Arial,sans-serif; background:#1a1d24; color:#e8e8e8; }
#info { position:absolute; top:12px; left:12px; z-index:10; background:rgba(20,24,32,.85);
padding:10px 14px; border-radius:8px; font-size:13px; line-height:1.5; max-width:300px;
border:1px solid rgba(255,255,255,.12); backdrop-filter:blur(4px); }
#info b { color:#ffb703; }
#toggle { position:absolute; top:12px; left:50%; transform:translateX(-50%); z-index:10;
display:flex; background:rgba(20,24,32,.85); border:1px solid rgba(255,255,255,.15);
border-radius:10px; padding:4px; backdrop-filter:blur(4px); }
#toggle button { background:transparent; color:#9aa3b2; border:none; padding:8px 18px;
border-radius:7px; font-size:13px; cursor:pointer; transition:all .15s; }
#toggle button.active { background:#ffb703; color:#1a1d24; font-weight:600; }
#hint { position:absolute; bottom:12px; left:50%; transform:translateX(-50%); z-index:10;
font-size:12px; color:#9aa3b2; background:rgba(20,24,32,.7); padding:6px 12px; border-radius:20px; }
canvas { display:block; }
</style>
</head>
<body>
<div id="info"><b>Органайзер для кошачьего корма</b><br>
Коробка: 131.5 × 156.2 × 200 мм<br>
Крышка: верх с ушками + низ с защёлками<br>
<span id="modeLabel" style="color:#ffb703"></span></div>
<div id="toggle">
<button id="btnOrig" class="active">Оригинал</button>
<button id="btnEdit">Без боковой конструкции</button>
</div>
<div id="hint">ЛКМ — вращение · колесо — масштаб · ПКМ — сдвиг</div>
<script type="importmap">
{ "imports": {
"three": "./vendor/three.module.js",
"three/addons/": "./vendor/examples/jsm/"
}}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1d24);
const camera = new THREE.PerspectiveCamera(45, innerWidth/innerHeight, 1, 3000);
camera.position.set(320, 260, 380);
const renderer = new THREE.WebGLRenderer({ antialias:true });
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 110, 0);
controls.enableDamping = true;
scene.add(new THREE.HemisphereLight(0xffffff, 0x444455, 0.9));
const sun = new THREE.DirectionalLight(0xffffff, 1.6);
sun.position.set(200, 400, 150); sun.castShadow = true; scene.add(sun);
const fill = new THREE.DirectionalLight(0x88aaff, 0.5);
fill.position.set(-250, 150, -200); scene.add(fill);
const grid = new THREE.GridHelper(400, 20, 0x3a4150, 0x2a2f3a);
grid.position.y = -1; scene.add(grid);
function loadGLB(b64str) {
return new Promise((resolve, reject) => {
const bin = atob(b64str);
const arr = new Uint8Array(bin.length);
for (let i=0;i<bin.length;i++) arr[i] = bin.charCodeAt(i);
new GLTFLoader().parse(arr.buffer, '', (gltf) => {
const model = gltf.scene;
model.traverse(o => { if (o.isMesh) { o.castShadow = true; o.receiveShadow = true; } });
scene.add(model);
resolve(model);
}, reject);
});
}
const models = {};
Promise.all([
loadGLB("Z2xURgIAAACw+QMAXAkAAEpTT057InNjZW5lIjowLCJzY2VuZXMiOlt7Im5vZGVzIjpbMCwxLDJdfV0sImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJodHRwczovL2dpdGh1Yi5jb20vbWlrZWRoL3RyaW1lc2gifSwiYWNjZXNzb3JzIjpbeyJjb21wb25lbnRUeXBlIjo1MTI1LCJ0eXBlIjoiU0NBTEFSIiwiYnVmZmVyVmlldyI6MCwiY291bnQiOjI1NTY2LCJtYXgiOls0MjYwXSwibWluIjpbMF19LHsiY29tcG9uZW50VHlwZSI6NTEyNiwidHlwZSI6IlZFQzMiLCJieXRlT2Zmc2V0IjowLCJidWZmZXJWaWV3IjoxLCJjb3VudCI6NDI2MSwibWF4IjpbNjUuNzY2MDA2NDY5NzI2NTYsNzguMDgwNTUxMTQ3NDYwOTQsMjAwLjBdLCJtaW4iOlstNjUuNzY2MDA2NDY5NzI2NTYsLTc4LjA4MDU1MTE0NzQ2MDk0LDAuMF19LHsiY29tcG9uZW50VHlwZSI6NTEyMSwibm9ybWFsaXplZCI6dHJ1ZSwidHlwZSI6IlZFQzQiLCJieXRlT2Zmc2V0IjowLCJidWZmZXJWaWV3IjoyLCJjb3VudCI6NDI2MSwibWF4IjpbMTQyLDIwMiwyMzAsMjU1XSwibWluIjpbMTQyLDIwMiwyMzAsMjU1XX0seyJjb21wb25lbnRUeXBlIjo1MTI1LCJ0eXBlIjoiU0NBTEFSIiwiYnVmZmVyVmlldyI6MywiY291bnQiOjE3MTYsIm1heCI6WzI4N10sIm1pbiI6WzBdfSx7ImNvbXBvbmVudFR5cGUiOjUxMjYsInR5cGUiOiJWRUMzIiwiYnl0ZU9mZnNldCI6MCwiYnVmZmVyVmlldyI6NCwiY291bnQiOjI4OCwibWF4IjpbNTAuMTAwMDA2MTAzNTE1NjI1LDc1LjA5OTk5ODQ3NDEyMTEsMjA5LjBdLCJtaW4iOlstNTAuMTAwMDA2MTAzNTE1NjI1LC03NS4wOTk5OTg0NzQxMjExLDIwMC4wXX0seyJjb21wb25lbnRUeXBlIjo1MTIxLCJub3JtYWxpemVkIjp0cnVlLCJ0eXBlIjoiVkVDNCIsImJ5dGVPZmZzZXQiOjAsImJ1ZmZlclZpZXciOjUsImNvdW50IjoyODgsIm1heCI6WzE2OCwyMTgsMjIwLDI1NV0sIm1pbiI6WzE2OCwyMTgsMjIwLDI1NV19LHsiY29tcG9uZW50VHlwZSI6NTEyNSwidHlwZSI6IlNDQUxBUiIsImJ1ZmZlclZpZXciOjYsImNvdW50IjoxMTQyNCwibWF4IjpbMTkwNV0sIm1pbiI6WzBdfSx7ImNvbXBvbmVudFR5cGUiOjUxMjYsInR5cGUiOiJWRUMzIiwiYnl0ZU9mZnNldCI6MCwiYnVmZmVyVmlldyI6NywiY291bnQiOjE5MDYsIm1heCI6WzUyLjUsNzcuNSwyMzMuMF0sIm1pbiI6Wy01Mi41LC03Ny41LDIwOS4wXX0seyJjb21wb25lbnRUeXBlIjo1MTIxLCJub3JtYWxpemVkIjp0cnVlLCJ0eXBlIjoiVkVDNCIsImJ5dGVPZmZzZXQiOjAsImJ1ZmZlclZpZXciOjgsImNvdW50IjoxOTA2LCJtYXgiOlsyNTUsMTgzLDMsMjU1XSwibWluIjpbMjU1LDE4MywzLDI1NV19XSwibWVzaGVzIjpbeyJuYW1lIjoiZ2VvbWV0cnlfMCIsImV4dHJhcyI6eyJ1bml0cyI6Im1pbGxpbWV0ZXIiLCJwcm9jZXNzZWQiOnRydWV9LCJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjoxLCJDT0xPUl8wIjoyfSwiaW5kaWNlcyI6MCwibW9kZSI6NH1dfSx7Im5hbWUiOiJnZW9tZXRyeV8xIiwiZXh0cmFzIjp7InVuaXRzIjoibWlsbGltZXRlciIsInByb2Nlc3NlZCI6dHJ1ZX0sInByaW1pdGl2ZXMiOlt7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjQsIkNPTE9SXzAiOjV9LCJpbmRpY2VzIjozLCJtb2RlIjo0fV19LHsibmFtZSI6Imdlb21ldHJ5XzIiLCJleHRyYXMiOnsidW5pdHMiOiJtaWxsaW1ldGVyIiwicHJvY2Vzc2VkIjp0cnVlfSwicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6NywiQ09MT1JfMCI6OH0sImluZGljZXMiOjYsIm1vZGUiOjR9XX1d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 truncated
loadGLB("Z2xURgIAAABM9QMAOAkAAEpTT057InNjZW5lIjowLCJzY2VuZXMiOlt7Im5vZGVzIjpbMCwxLDJdfV0sImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJodHRwczovL2dpdGh1Yi5jb20vbWlrZWRoL3RyaW1lc2gifSwiYWNjZXNzb3JzIjpbeyJjb21wb25lbnRUeXBlIjo1MTI1LCJ0eXBlIjoiU0NBTEFSIiwiYnVmZmVyVmlldyI6MCwiY291bnQiOjI1Mzk4LCJtYXgiOls0MjM0XSwibWluIjpbMF19LHsiY29tcG9uZW50VHlwZSI6NTEyNiwidHlwZSI6IlZFQzMiLCJieXRlT2Zmc2V0IjowLCJidWZmZXJWaWV3IjoxLCJjb3VudCI6NDIzNSwibWF4IjpbNjUuNzY2MDA2NDY5NzI2NTYsNzguMDgwNTUxMTQ3NDYwOTQsMjAwLjBdLCJtaW4iOlstNjUuNzY2MDA2NDY5NzI2NTYsLTc4LjA4MDU1MTE0NzQ2MDk0LDAuMF19LHsiY29tcG9uZW50VHlwZSI6NTEyMSwibm9ybWFsaXplZCI6dHJ1ZSwidHlwZSI6IlZFQzQiLCJieXRlT2Zmc2V0IjowLCJidWZmZXJWaWV3IjoyLCJjb3VudCI6NDIzNSwibWF4IjpbMTQyLDIwMiwyMzAsMjU1XSwibWluIjpbMTQyLDIwMiwyMzAsMjU1XX0seyJjb21wb25lbnRUeXBlIjo1MTI1LCJ0eXBlIjoiU0NBTEFSIiwiYnVmZmVyVmlldyI6MywiY291bnQiOjE3MTYsIm1heCI6WzI4N10sIm1pbiI6WzBdfSx7ImNvbXBvbmVudFR5cGUiOjUxMjYsInR5cGUiOiJWRUMzIiwiYnl0ZU9mZnNldCI6MCwiYnVmZmVyVmlldyI6NCwiY291bnQiOjI4OCwibWF4IjpbNTAuMTAwMDA2MTAzNTE1NjI1LDc1LjA5OTk5ODQ3NDEyMTEsMjA5LjBdLCJtaW4iOlstNTAuMTAwMDA2MTAzNTE1NjI1LC03NS4wOTk5OTg0NzQxMjExLDIwMC4wXX0seyJjb21wb25lbnRUeXBlIjo1MTIxLCJub3JtYWxpemVkIjp0cnVlLCJ0eXBlIjoiVkVDNCIsImJ5dGVPZmZzZXQiOjAsImJ1ZmZlclZpZXciOjUsImNvdW50IjoyODgsIm1heCI6WzE2OCwyMTgsMjIwLDI1NV0sIm1pbiI6WzE2OCwyMTgsMjIwLDI1NV19LHsiY29tcG9uZW50VHlwZSI6NTEyNSwidHlwZSI6IlNDQUxBUiIsImJ1ZmZlclZpZXciOjYsImNvdW50IjoxMTQyNCwibWF4IjpbMTkwNV0sIm1pbiI6WzBdfSx7ImNvbXBvbmVudFR5cGUiOjUxMjYsInR5cGUiOiJWRUMzIiwiYnl0ZU9mZnNldCI6MCwiYnVmZmVyVmlldyI6NywiY291bnQiOjE5MDYsIm1heCI6WzUyLjUsNzcuNSwyMzMuMF0sIm1pbiI6Wy01Mi41LC03Ny41LDIwOS4wXX0seyJjb21wb25lbnRUeXBlIjo1MTIxLCJub3JtYWxpemVkIjp0cnVlLCJ0eXBlIjoiVkVDNCIsImJ5dGVPZmZzZXQiOjAsImJ1ZmZlclZpZXciOjgsImNvdW50IjoxOTA2LCJtYXgiOlsyNTUsMTgzLDMsMjU1XSwibWluIjpbMjU1LDE4MywzLDI1NV19XSwibWVzaGVzIjpbeyJuYW1lIjoiZ2VvbWV0cnlfMCIsImV4dHJhcyI6e30sInByaW1pdGl2ZXMiOlt7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjEsIkNPTE9SXzAiOjJ9LCJpbmRpY2VzIjowLCJtb2RlIjo0fV19LHsibmFtZSI6Imdlb21ldHJ5XzEiLCJleHRyYXMiOnsidW5pdHMiOiJtaWxsaW1ldGVyIiwicHJvY2Vzc2VkIjp0cnVlfSwicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6NCwiQ09MT1JfMCI6NX0sImluZGljZXMiOjMsIm1vZGUiOjR9XX0seyJuYW1lIjoiZ2VvbWV0cnlfMiIsImV4dHJhcyI6eyJ1bml0cyI6Im1pbGxpbWV0ZXIiLCJwcm9jZXNzZWQiOnRydWV9LCJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjo3LCJDT0xPUl8wIjo4fSwiaW5kaWNlcyI6NiwibW9kZSI6NH1dfV0sIm5vZGVzIjpbeyJuYW1lIjoiZ2VvbWV0cnlfMCIsIm1lc2gi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 truncated
]).then(() => {
const box = new THREE.Box3().setFromObject(models.orig);
const c = box.getCenter(new THREE.Vector3());
controls.target.copy(c);
camera.position.copy(c).add(new THREE.Vector3(320, 260, 380));
});
function setMode(mode) {
models.orig.visible = (mode === 'orig');
models.edit.visible = (mode === 'edit');
document.getElementById('btnOrig').classList.toggle('active', mode === 'orig');
document.getElementById('btnEdit').classList.toggle('active', mode === 'edit');
document.getElementById('modeLabel').textContent =
mode === 'orig' ? 'Показан: оригинал' : 'Показан: без боковой конструкции';
}
document.getElementById('btnOrig').onclick = () => setMode('orig');
document.getElementById('btnEdit').onclick = () => setMode('edit');
setMode('orig');
window.addEventListener('resize', () => {
camera.aspect = innerWidth/innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
function animate(){ requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); }
animate();
</script>
</body>
</html>