Created
February 7, 2026 16:07
-
-
Save noone0/8a8fb9ac12ec92a34e6eda2141c9aae0 to your computer and use it in GitHub Desktop.
Çenger Farm 3D Viewer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
| <title>Çenger Farm 3D</title> | |
| <style> | |
| *{margin:0;padding:0;box-sizing:border-box} | |
| body{overflow:hidden;touch-action:none;font-family:system-ui,sans-serif} | |
| canvas{display:block} | |
| .ui{position:fixed;z-index:10} | |
| .info{top:10px;left:10px;background:rgba(0,0,0,.8);color:#fff;padding:15px;border-radius:10px;font-size:13px;max-width:220px} | |
| .info h3{color:#4fc3f7;margin-bottom:8px} | |
| .info p{margin:4px 0;color:#ccc} | |
| .btns{bottom:15px;left:50%;transform:translateX(-50%);display:flex;gap:8px} | |
| .btns button{background:rgba(0,0,0,.8);color:#fff;border:1px solid #4fc3f7;padding:10px 15px;border-radius:6px;font-size:13px} | |
| .tip{bottom:60px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,.6);color:#aaa;padding:6px 12px;border-radius:15px;font-size:11px} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="ui info"> | |
| <h3>🏡 Çenger Farm</h3> | |
| <p>📍 Fethiye, Muğla</p> | |
| <p>📐 5,361 m²</p> | |
| <p style="margin-top:8px;font-size:11px;color:#888">🟢 Residential • 🟤 Barn<br>🟠 Field • 🌿 Garden</p> | |
| </div> | |
| <div class="ui tip">👆 Drag rotate • Pinch zoom</div> | |
| <div class="ui btns"> | |
| <button onclick="goTo(0)">🎯 All</button> | |
| <button onclick="goTo(1)">🏠 House</button> | |
| <button onclick="goTo(2)">🏚️ Barn</button> | |
| <button onclick="spin=!spin">🔄</button> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script> | |
| <script> | |
| // Globals | |
| let W=innerWidth, H=innerHeight, spin=false; | |
| const scene=new THREE.Scene(); | |
| const cam=new THREE.PerspectiveCamera(60,W/H,1,1000); | |
| const renderer=new THREE.WebGLRenderer({antialias:true}); | |
| renderer.setSize(W,H); | |
| renderer.setPixelRatio(Math.min(devicePixelRatio,2)); | |
| document.body.appendChild(renderer.domElement); | |
| scene.background=new THREE.Color(0x7ec8e3); | |
| cam.position.set(70,50,70); | |
| cam.lookAt(0,0,0); | |
| // Lights | |
| scene.add(new THREE.AmbientLight(0xffffff,0.6)); | |
| const sun=new THREE.DirectionalLight(0xffffff,0.8); | |
| sun.position.set(30,50,30); | |
| scene.add(sun); | |
| // Materials | |
| const mat={ | |
| ground:new THREE.MeshLambertMaterial({color:0x8B7355}), | |
| parcel:new THREE.MeshLambertMaterial({color:0x9B8B6B}), | |
| field:new THREE.MeshLambertMaterial({color:0xCD853F}), | |
| garden:new THREE.MeshLambertMaterial({color:0x66BB6A}), | |
| house:new THREE.MeshLambertMaterial({color:0xFFF8DC}), | |
| roof:new THREE.MeshLambertMaterial({color:0xB84C29}), | |
| barn:new THREE.MeshLambertMaterial({color:0xA0522D}), | |
| door:new THREE.MeshLambertMaterial({color:0x5D4037}), | |
| tree:new THREE.MeshLambertMaterial({color:0x2E7D32}), | |
| trunk:new THREE.MeshLambertMaterial({color:0x5D4037}) | |
| }; | |
| // Ground | |
| const ground=new THREE.Mesh(new THREE.PlaneGeometry(200,200),mat.ground); | |
| ground.rotation.x=-Math.PI/2; | |
| ground.position.y=-0.5; | |
| scene.add(ground); | |
| // Parcel | |
| const parcel=new THREE.Mesh(new THREE.PlaneGeometry(35,90),mat.parcel); | |
| parcel.rotation.x=-Math.PI/2; | |
| parcel.position.set(0,0,5); | |
| scene.add(parcel); | |
| // Cultivated Field | |
| const field=new THREE.Mesh(new THREE.PlaneGeometry(28,22),mat.field); | |
| field.rotation.x=-Math.PI/2; | |
| field.position.set(0,0.1,38); | |
| scene.add(field); | |
| // Field rows | |
| for(let i=-10;i<=10;i+=2.5){ | |
| const row=new THREE.Mesh(new THREE.BoxGeometry(0.4,0.2,20),new THREE.MeshLambertMaterial({color:0x8B4513})); | |
| row.position.set(i,0.2,38); | |
| scene.add(row); | |
| } | |
| // Garden | |
| const garden=new THREE.Mesh(new THREE.PlaneGeometry(18,12),mat.garden); | |
| garden.rotation.x=-Math.PI/2; | |
| garden.position.set(0,0.1,15); | |
| scene.add(garden); | |
| // Garden beds | |
| for(let x=-5;x<=5;x+=5){ | |
| for(let z=-3;z<=3;z+=3){ | |
| const bed=new THREE.Mesh(new THREE.BoxGeometry(3,0.3,2),new THREE.MeshLambertMaterial({color:0x4CAF50})); | |
| bed.position.set(x,0.25,15+z); | |
| scene.add(bed); | |
| } | |
| } | |
| // Main House | |
| const houseG=new THREE.Group(); | |
| const walls=new THREE.Mesh(new THREE.BoxGeometry(12,4,9),mat.house); | |
| walls.position.y=2; | |
| houseG.add(walls); | |
| const roof=new THREE.Mesh(new THREE.ConeGeometry(8.5,3,4),mat.roof); | |
| roof.position.y=5.5; | |
| roof.rotation.y=Math.PI/4; | |
| houseG.add(roof); | |
| const door=new THREE.Mesh(new THREE.BoxGeometry(1.8,2.5,0.3),mat.door); | |
| door.position.set(0,1.25,4.6); | |
| houseG.add(door); | |
| houseG.position.set(0,0,-8); | |
| scene.add(houseG); | |
| // Barn | |
| const barnG=new THREE.Group(); | |
| const barnBase=new THREE.Mesh(new THREE.BoxGeometry(12,4.5,9),mat.barn); | |
| barnBase.position.y=2.25; | |
| barnG.add(barnBase); | |
| const barnRoof=new THREE.Mesh(new THREE.ConeGeometry(8,2.5,4),mat.roof); | |
| barnRoof.position.y=5.75; | |
| barnRoof.rotation.y=Math.PI/4; | |
| barnG.add(barnRoof); | |
| const barnDoor=new THREE.Mesh(new THREE.BoxGeometry(3.5,3.5,0.3),mat.door); | |
| barnDoor.position.set(0,1.75,4.6); | |
| barnG.add(barnDoor); | |
| barnG.position.set(-2,0,-30); | |
| scene.add(barnG); | |
| // Small shed | |
| const shed=new THREE.Mesh(new THREE.BoxGeometry(6,2.5,5),mat.barn); | |
| shed.position.set(4,1.25,26); | |
| scene.add(shed); | |
| const shedRoof=new THREE.Mesh(new THREE.BoxGeometry(7,0.3,6),mat.roof); | |
| shedRoof.position.set(4,2.65,26); | |
| scene.add(shedRoof); | |
| // Trees | |
| [[−22,−20],[−25,5],[−23,30],[−20,48],[22,−18],[25,8],[23,32],[20,50],[−18,−42],[18,−40]].forEach(p=>{ | |
| const t=new THREE.Group(); | |
| t.add(new THREE.Mesh(new THREE.CylinderGeometry(0.4,0.6,3,6),mat.trunk)); | |
| t.children[0].position.y=1.5; | |
| const fol=new THREE.Mesh(new THREE.SphereGeometry(2.5,6,5),mat.tree); | |
| fol.position.y=4.5; | |
| t.add(fol); | |
| t.position.set(p[0],0,p[1]); | |
| scene.add(t); | |
| }); | |
| // Parcel outline | |
| const outline=new THREE.Line( | |
| new THREE.BufferGeometry().setFromPoints([ | |
| new THREE.Vector3(-16,0.3,-42), | |
| new THREE.Vector3(-14,0.3,50), | |
| new THREE.Vector3(16,0.3,52), | |
| new THREE.Vector3(18,0.3,-40), | |
| new THREE.Vector3(-16,0.3,-42) | |
| ]), | |
| new THREE.LineBasicMaterial({color:0xff0000}) | |
| ); | |
| scene.add(outline); | |
| // Camera targets | |
| const views=[ | |
| {p:[70,50,70],t:[0,0,5]}, // overview | |
| {p:[22,12,8],t:[0,2,-8]}, // house | |
| {p:[18,10,-18],t:[-2,2,-30]} // barn | |
| ]; | |
| function goTo(i){ | |
| const v=views[i]; | |
| const startP={x:cam.position.x,y:cam.position.y,z:cam.position.z}; | |
| const startT={x:target.x,y:target.y,z:target.z}; | |
| const st=Date.now(); | |
| (function anim(){ | |
| const t=Math.min((Date.now()-st)/1000,1); | |
| const e=1-Math.pow(1-t,3); | |
| cam.position.set(startP.x+(v.p[0]-startP.x)*e,startP.y+(v.p[1]-startP.y)*e,startP.z+(v.p[2]-startP.z)*e); | |
| target.x=startT.x+(v.t[0]-startT.x)*e; | |
| target.y=startT.y+(v.t[1]-startT.y)*e; | |
| target.z=startT.z+(v.t[2]-startT.z)*e; | |
| if(t<1)requestAnimationFrame(anim); | |
| })(); | |
| } | |
| window.goTo=goTo; | |
| window.spin=false; | |
| // Simple orbit controls | |
| let drag=false,prevX=0,prevY=0,theta=Math.PI/4,phi=Math.PI/4,radius=100; | |
| const target={x:0,y:0,z:5}; | |
| function updateCam(){ | |
| cam.position.x=target.x+radius*Math.sin(phi)*Math.cos(theta); | |
| cam.position.y=target.y+radius*Math.cos(phi); | |
| cam.position.z=target.z+radius*Math.sin(phi)*Math.sin(theta); | |
| cam.lookAt(target.x,target.y,target.z); | |
| } | |
| renderer.domElement.addEventListener('pointerdown',e=>{drag=true;prevX=e.clientX;prevY=e.clientY}); | |
| renderer.domElement.addEventListener('pointerup',()=>drag=false); | |
| renderer.domElement.addEventListener('pointerleave',()=>drag=false); | |
| renderer.domElement.addEventListener('pointermove',e=>{ | |
| if(!drag)return; | |
| theta+=(e.clientX-prevX)*0.01; | |
| phi+=( e.clientY-prevY)*0.01; | |
| phi=Math.max(0.2,Math.min(1.5,phi)); | |
| prevX=e.clientX;prevY=e.clientY; | |
| updateCam(); | |
| }); | |
| renderer.domElement.addEventListener('wheel',e=>{ | |
| radius+=e.deltaY*0.1; | |
| radius=Math.max(25,Math.min(150,radius)); | |
| updateCam(); | |
| },{passive:true}); | |
| // Touch zoom | |
| let lastDist=0; | |
| renderer.domElement.addEventListener('touchstart',e=>{ | |
| if(e.touches.length===2){ | |
| lastDist=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY); | |
| } | |
| },{passive:true}); | |
| renderer.domElement.addEventListener('touchmove',e=>{ | |
| if(e.touches.length===2){ | |
| const d=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY); | |
| radius+=( lastDist-d)*0.3; | |
| radius=Math.max(25,Math.min(150,radius)); | |
| lastDist=d; | |
| updateCam(); | |
| } | |
| },{passive:true}); | |
| // Initial camera | |
| theta=Math.PI/4;phi=Math.PI/4;radius=100; | |
| updateCam(); | |
| // Render loop | |
| (function render(){ | |
| requestAnimationFrame(render); | |
| if(spin)theta+=0.005; | |
| if(spin)updateCam(); | |
| renderer.render(scene,cam); | |
| })(); | |
| // Resize | |
| onresize=()=>{W=innerWidth;H=innerHeight;cam.aspect=W/H;cam.updateProjectionMatrix();renderer.setSize(W,H)}; | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment