FerrellSyntheticIntelligence
Add GitHub Sponsors + Buy Me A Coffee
d26d55f
Raw
History Blame Contribute Delete
12.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vitalis DevCore — 3D Blueprint</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0a0a1a;overflow:hidden;color:#fff;}
#canvas-container{width:100vw;height:100vh;display:block;}
#info-overlay{position:fixed;top:16px;left:16px;background:rgba(10,10,30,0.85);border:1px solid rgba(100,60,255,0.3);border-radius:12px;padding:16px 20px;max-width:340px;font-size:13px;line-height:1.5;backdrop-filter:blur(8px);z-index:10;}
#info-overlay h2{font-size:16px;margin-bottom:6px;color:#a78bfa;}
#info-overlay p{color:#c4b5fd;margin:2px 0;font-size:12px;}
.badge{display:inline-block;padding:2px 8px;border-radius:6px;font-size:11px;margin:2px;background:rgba(100,60,255,0.15);color:#a78bfa;border:1px solid rgba(100,60,255,0.2);}
.badge-dim{background:rgba(50,180,100,0.15);color:#6ee7a7;border-color:rgba(50,180,100,0.2);}
#controls-hint{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:rgba(10,10,30,0.7);border:1px solid rgba(255,255,255,0.1);border-radius:8px;padding:8px 16px;font-size:12px;color:#888;backdrop-filter:blur(4px);z-index:10;display:flex;gap:16px;}
#controls-hint span{cursor:pointer;padding:2px 8px;border-radius:4px;transition:background 0.2s;}
#controls-hint span:hover{background:rgba(100,60,255,0.2);color:#a78bfa;}
#controls-hint .active{background:rgba(100,60,255,0.3);color:#a78bfa;}
.tool-btn{position:fixed;bottom:20px;right:20px;background:rgba(100,60,255,0.2);border:1px solid rgba(100,60,255,0.3);border-radius:8px;padding:8px 14px;font-size:12px;color:#a78bfa;cursor:pointer;backdrop-filter:blur(4px);z-index:10;transition:all 0.2s;}
.tool-btn:hover{background:rgba(100,60,255,0.4);}
</style>
</head>
<body>
<div id="info-overlay">
<h2>🏗️ <span id="style-name">Blueprint</span></h2>
<p id="summary-text">Loading...</p>
<div id="features" style="margin-top:6px;"></div>
<div id="dimensions" style="margin-top:4px;font-size:11px;color:#6ee7a7;"></div>
</div>
<div id="controls-hint">
<span data-mode="orbit" class="active">🔄 Orbit</span>
<span data-mode="pan">✋ Pan</span>
<span data-mode="tour">🎬 Tour</span>
</div>
<button class="tool-btn" id="export-btn">📥 Export JSON</button>
<div id="canvas-container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
<script>
/* BLUEPRINT_DATA */
var BP = BLUEPRINT;
var scene, camera, renderer, controls;
var tourActive = false, tourPoints = [], tourIdx = 0;
function initScene() {
var container = document.getElementById('canvas-container');
var w = container.clientWidth, h = container.clientHeight;
scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0a1a);
scene.fog = new THREE.Fog(0x0a0a1a, 120, 200);
camera = new THREE.PerspectiveCamera(40, w/h, 0.1, 500);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(w, h);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;
container.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.08;
controls.maxPolarAngle = Math.PI / 2.05;
controls.minDistance = 3;
controls.maxDistance = 120;
// Lights
scene.add(new THREE.AmbientLight(0x404060, 0.5));
var sun = new THREE.DirectionalLight(0xffeedd, 1.4);
sun.position.set(40, 60, 30);
sun.castShadow = true;
sun.shadow.mapSize.width = 2048;
sun.shadow.mapSize.height = 2048;
scene.add(sun);
scene.add(new THREE.DirectionalLight(0x8888ff, 0.3).position.set(-30, 20, -20));
scene.add(new THREE.HemisphereLight(0x8888ff, 0x444422, 0.5));
// Ground
var gnd = new THREE.Mesh(
new THREE.PlaneGeometry(200, 200),
new THREE.MeshStandardMaterial({color:0x181830,roughness:0.9,metalness:0,transparent:true,opacity:0.8})
);
gnd.rotation.x = -Math.PI/2;
gnd.position.y = -0.25;
gnd.receiveShadow = true;
scene.add(gnd);
var grid = new THREE.GridHelper(100, 40, 0x444488, 0x333366);
grid.position.y = 0.01;
scene.add(grid);
var sp = BP.scene;
var sw = sp.width, sd = sp.depth;
// Foundation outline
var ol = new THREE.Line(
new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array([0,0,0,sw,0,0,sw,0,sd,0,0,sd,0,0,0]),3)),
new THREE.LineBasicMaterial({color:0x6666cc,transparent:true,opacity:0.4})
);
ol.position.y = 0.02;
scene.add(ol);
// Floors
BP.floors.forEach(function(f) {
var g = new THREE.BoxGeometry(f.w, f.h, f.d);
var m = new THREE.MeshStandardMaterial({roughness:0.7,metalness:0.05,color:f.color||0x444466,transparent:true,opacity:f.exterior?0.4:0.8});
var mesh = new THREE.Mesh(g, m);
mesh.position.set(f.x+f.w/2, f.y, f.z+f.d/2);
mesh.castShadow = true; mesh.receiveShadow = true;
scene.add(mesh);
if (!f.exterior) {
var e = new THREE.LineSegments(new THREE.EdgesGeometry(g), new THREE.LineBasicMaterial({color:0x8888cc,transparent:true,opacity:0.15}));
e.position.copy(mesh.position);
scene.add(e);
}
});
// Walls
BP.walls.forEach(function(w) {
var wx, wz, ww, wd;
if (w.side === 'north') { wx = w.x; wz = w.z; ww = w.w; wd = 0.15; }
else if (w.side === 'south') { wx = w.x; wz = w.z+w.d; ww = w.w; wd = 0.15; }
else if (w.side === 'east') { wx = w.x+w.w; wz = w.z; ww = 0.15; wd = w.d; }
else { wx = w.x; wz = w.z; ww = 0.15; wd = w.d; }
var g = new THREE.BoxGeometry(ww, w.h, wd);
var m = new THREE.MeshStandardMaterial({color:0x555599,roughness:0.6,metalness:0.1,transparent:true,opacity:0.1});
var mesh = new THREE.Mesh(g, m);
mesh.position.set(wx+ww/2, w.h/2, wz+wd/2);
scene.add(mesh);
});
// Roof
var rf = BP.roof;
var roofMesh;
if (rf.style === 'flat') {
var rg = new THREE.BoxGeometry(rf.w, rf.h*0.3, rf.d);
var rm = new THREE.MeshStandardMaterial({color:rf.color||0x5a4a3a,roughness:0.8,metalness:0});
roofMesh = new THREE.Mesh(rg, rm);
roofMesh.position.set(sw/2, rf.y, sd/2);
} else if (rf.style === 'gable' || rf.style === 'steep-gable' || rf.style === 'low-gable') {
var shape = new THREE.Shape();
var pitch = rf.pitch || 0.4;
var ridgeH = rf.w * pitch * 0.5;
shape.moveTo(-rf.w/2, 0);
shape.lineTo(0, ridgeH);
shape.lineTo(rf.w/2, 0);
shape.lineTo(-rf.w/2, 0);
var extrudeSettings = {steps:1,depth:rf.d,bevelEnabled:true,bevelThickness:0.5,bevelSize:0.3,bevelSegments:2};
var rg = new THREE.ExtrudeGeometry(shape, extrudeSettings);
var rm = new THREE.MeshStandardMaterial({color:rf.color||0x5a4a3a,roughness:0.8,metalness:0,side:THREE.DoubleSide});
roofMesh = new THREE.Mesh(rg, rm);
roofMesh.position.set(sw/2, rf.y, sd/2 - rf.d/2);
roofMesh.rotation.x = 0;
} else {
var rg = new THREE.ConeGeometry(Math.max(rf.w,rf.d)*0.6, rf.h, 4);
var rm = new THREE.MeshStandardMaterial({color:rf.color||0x5a4a3a,roughness:0.8,metalness:0});
roofMesh = new THREE.Mesh(rg, rm);
roofMesh.position.set(sw/2, rf.y + rf.h/2, sd/2);
roofMesh.rotation.y = Math.PI/4;
}
if (roofMesh) { roofMesh.castShadow = true; scene.add(roofMesh); }
// Measurements
BP.measurements.forEach(function(m) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 256; canvas.height = 64;
ctx.fillStyle = 'rgba(50,180,100,0.15)';
ctx.beginPath(); ctx.roundRect(20,8,216,48,6); ctx.fill();
ctx.strokeStyle = 'rgba(50,180,100,0.4)'; ctx.lineWidth=1; ctx.stroke();
ctx.fillStyle = '#6ee7a7'; ctx.font = 'bold 24px monospace'; ctx.textAlign='center'; ctx.textBaseline='middle';
ctx.fillText(m.text, 128, 32);
var tex = new THREE.CanvasTexture(canvas);
tex.needsUpdate = true;
var sp = new THREE.Sprite(new THREE.SpriteMaterial({map:tex,transparent:true,depthTest:false,sizeAttenuation:true}));
sp.position.set(m.x, m.y + 0.5, m.z);
sp.scale.set(m.dim === 'width' ? 4 : 2.5, 1, 1);
scene.add(sp);
});
// Labels
BP.labels.forEach(function(l) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 512; canvas.height = 100;
ctx.shadowColor = 'rgba(0,0,0,0.8)'; ctx.shadowBlur = 10;
ctx.fillStyle = 'rgba(20,20,50,0.5)';
ctx.beginPath(); ctx.roundRect(50,12,412,76,10); ctx.fill();
ctx.strokeStyle = 'rgba(100,60,255,0.2)'; ctx.lineWidth=1; ctx.stroke();
ctx.shadowColor = 'rgba(0,0,0,0.5)'; ctx.shadowBlur = 4;
ctx.fillStyle = l.text.includes('Upper') ? 'rgba(180,180,220,0.6)' : '#ffffff';
ctx.font = 'bold 28px -apple-system, BlinkMacSystemFont, sans-serif';
ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
ctx.fillText(l.text, 256, 50);
var tex = new THREE.CanvasTexture(canvas);
tex.needsUpdate = true;
var sp = new THREE.Sprite(new THREE.SpriteMaterial({map:tex,transparent:true,depthTest:false,sizeAttenuation:true}));
sp.position.set(l.x, l.y + 2.5, l.z);
sp.scale.set(6, 1.2, 1);
scene.add(sp);
});
// Position camera
var dist = Math.max(sw, sd) * 1.2 + 8;
camera.position.set(dist*0.6, dist*0.6, dist*0.7);
controls.target.set(sw/2, 1, sd/2);
controls.update();
// Tour points
tourPoints = BP.labels.map(function(l) { return {x:l.x, y:3, z:l.z}; });
// Resize
window.addEventListener('resize', function() {
var w2 = container.clientWidth, h2 = container.clientHeight;
camera.aspect = w2/h2; camera.updateProjectionMatrix();
renderer.setSize(w2, h2);
});
animate();
}
function animate() {
requestAnimationFrame(animate);
if (tourActive && tourPoints.length > 0) {
var p = tourPoints[tourIdx];
controls.target.lerp(new THREE.Vector3(p.x, p.y, p.z), 0.03);
var dist = controls.target.distanceTo(camera.position);
if (dist < 2) { tourIdx = (tourIdx + 1) % tourPoints.length; }
}
controls.update();
renderer.render(scene, camera);
}
// UI
document.getElementById('summary-text').textContent = BP.summary || 'No description.';
document.getElementById('style-name').textContent = (BP.scene.style || 'Modern').charAt(0).toUpperCase() + (BP.scene.style||'Modern').slice(1);
var feat = BP.features || {};
var featHtml = '';
var dimHtml = '';
if (feat.bedrooms !== undefined) featHtml += '<span class="badge">🛏️ ' + feat.bedrooms + ' bed</span>';
if (feat.bathrooms !== undefined) featHtml += '<span class="badge">🚿 ' + feat.bathrooms + ' bath</span>';
if (feat.stories !== undefined) featHtml += '<span class="badge">🏠 ' + feat.stories + ' story</span>';
if (feat.garage !== undefined) featHtml += '<span class="badge">🚗 ' + (feat.garage ? 'Garage' : 'No garage') + '</span>';
featHtml += '<span class="badge badge-dim">📐 ' + BP.scene.width + 'ft x ' + BP.scene.depth + 'ft</span>';
document.getElementById('features').innerHTML = featHtml;
var sqft = BP.scene.width * BP.scene.depth * (BP.scene.stories || 1);
document.getElementById('dimensions').textContent = '≈ ' + sqft + ' sq ft total';
// Control mode switching
document.querySelectorAll('#controls-hint span').forEach(function(el) {
el.addEventListener('click', function() {
document.querySelectorAll('#controls-hint span').forEach(function(e) { e.classList.remove('active'); });
el.classList.add('active');
var mode = el.dataset.mode;
if (mode === 'orbit') { tourActive = false; controls.enableRotate = true; controls.enablePan = true; }
else if (mode === 'pan') { tourActive = false; controls.enableRotate = false; controls.enablePan = true; }
else if (mode === 'tour') { tourActive = true; tourIdx = 0; controls.enableRotate = true; controls.enablePan = true; }
});
});
// Export
document.getElementById('export-btn').addEventListener('click', function() {
var json = JSON.stringify(BP, null, 2);
var blob = new Blob([json], {type:'application/json'});
var a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'blueprint.json';
a.click();
});
initScene();
</script>
</body>
</html>