betterwithage Claude Opus 4.7 commited on
Commit
0c94fe6
·
verified ·
1 Parent(s): f3f5ac7

deploy(hf): sync szl-holdings/a11oy@main derived COPY set

Browse files

Reusable Dockerfile-COPY-derived deploy from szl-holdings/a11oy main.
Files: 989 Pruned: 0
Derived from Dockerfile COPY sources (NO hand-maintained allowlist).

Signed-off-by: SZL Holdings <noreply@szlholdings.ai>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Files changed (1) hide show
  1. static/3d/holo-lab.html +275 -0
static/3d/holo-lab.html ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Holographic Estate — Holo Lab</title>
7
+ <style>
8
+ :root { --cyan:#39e6d4; --cyan-dim:#1c8f86; --ink:#04070b; }
9
+ * { box-sizing: border-box; }
10
+ html, body { margin:0; height:100%; }
11
+ body {
12
+ background:
13
+ radial-gradient(1200px 700px at 68% 18%, rgba(57,230,212,.10), transparent 60%),
14
+ radial-gradient(900px 900px at 20% 90%, rgba(40,120,200,.08), transparent 60%),
15
+ linear-gradient(160deg, #04070b 0%, #060c14 55%, #030507 100%);
16
+ color:#cfe9e6;
17
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
18
+ overflow:hidden;
19
+ }
20
+ #stage { position:fixed; inset:0; }
21
+ canvas { display:block; width:100%; height:100%; }
22
+ /* Site injects a top-left signed-corpus badge + bottom-right widget; keep clear of them. */
23
+ .hud { position:fixed; left:152px; top:18px; z-index:5; pointer-events:none; max-width:min(560px,60vw); }
24
+ .title { margin:0; font-size:20px; letter-spacing:.28em; font-weight:600; color:#eafffb; }
25
+ .sub { margin:6px 0 12px; font-size:12px; letter-spacing:.14em; color:#7fb7b0; }
26
+ .badges { display:flex; gap:8px; flex-wrap:wrap; }
27
+ .badge {
28
+ font-size:10.5px; letter-spacing:.16em; padding:4px 9px; border-radius:999px;
29
+ border:1px solid rgba(57,230,212,.35); color:#bfeee7; background:rgba(57,230,212,.06);
30
+ }
31
+ .badge.warn { border-color:rgba(240,200,90,.45); color:#f0d98a; background:rgba(240,200,90,.06); }
32
+ .status {
33
+ position:fixed; left:152px; bottom:20px; z-index:5; font-size:11px; letter-spacing:.10em;
34
+ color:#6fa6a0; pointer-events:none;
35
+ }
36
+ .status b { color:#9fe6dd; font-weight:600; }
37
+ .legend {
38
+ position:fixed; right:22px; bottom:56px; z-index:5; font-size:10.5px; letter-spacing:.08em;
39
+ color:#6fa6a0; text-align:right; pointer-events:none; line-height:1.7;
40
+ }
41
+ .dot { display:inline-block; width:8px; height:8px; border-radius:50%; margin-left:8px; vertical-align:middle; }
42
+ </style>
43
+ </head>
44
+ <body>
45
+ <div id="stage">
46
+ <canvas id="gl"></canvas>
47
+ <canvas id="fb" hidden></canvas>
48
+ </div>
49
+
50
+ <div class="hud">
51
+ <h1 class="title">HOLOGRAPHIC ESTATE</h1>
52
+ <p class="sub">Point-field estate model · Holo Lab</p>
53
+ <div class="badges">
54
+ <span class="badge warn">SAMPLE — procedural model, not a real capture</span>
55
+ <span class="badge">PREVIEW</span>
56
+ </div>
57
+ </div>
58
+
59
+ <div class="legend">
60
+ structure<span class="dot" style="background:#eafffb"></span><br/>
61
+ roof line<span class="dot" style="background:#39e6d4"></span><br/>
62
+ grounds<span class="dot" style="background:#2f7fb0"></span>
63
+ </div>
64
+
65
+ <div class="status">renderer: <b id="rstat">initialising…</b> · <span id="rnote">building point field</span></div>
66
+
67
+ <script type="importmap">
68
+ {
69
+ "imports": {
70
+ "three": "/static/3d/vendor/three/three.module.min.js",
71
+ "three/addons/": "/static/3d/vendor/three/addons/"
72
+ }
73
+ }
74
+ </script>
75
+
76
+ <script>
77
+ // ---- Shared procedural estate point field (single source for WebGL + 2D fallback) ----
78
+ // Honest: this is a generated model of a house + grounds, NOT a photogrammetric capture.
79
+ function buildEstatePoints() {
80
+ const pts = []; // {x,y,z, c:[r,g,b]}
81
+ const push = (x,y,z,c) => pts.push({x,y,z,c});
82
+ const CYAN = [0.22,0.90,0.83], WHITE = [0.92,1.0,0.98], BLUE = [0.18,0.50,0.69];
83
+ const jit = (n) => (Math.random()-0.5)*n;
84
+
85
+ // House body: box centred at origin, width 6 (x), height 3 (y), depth 4 (z), base at y=0
86
+ const W=6, H=3, D=4;
87
+ const wallDensity = 2600;
88
+ for (let i=0;i<wallDensity;i++){
89
+ const face = Math.floor(Math.random()*4);
90
+ let x,y,z;
91
+ y = Math.random()*H;
92
+ if (face===0){ x=-W/2; z=(Math.random()-0.5)*D; }
93
+ else if (face===1){ x=W/2; z=(Math.random()-0.5)*D; }
94
+ else if (face===2){ z=-D/2; x=(Math.random()-0.5)*W; }
95
+ else { z=D/2; x=(Math.random()-0.5)*W; }
96
+ push(x+jit(0.03), y+jit(0.03), z+jit(0.03), WHITE);
97
+ }
98
+ // Roof: two sloped planes meeting at a ridge (y from H to H+1.8)
99
+ const roofDensity = 1700, RH=1.8;
100
+ for (let i=0;i<roofDensity;i++){
101
+ const t = Math.random(); // 0..1 across span
102
+ const along = (Math.random()-0.5)*D; // along ridge (z)
103
+ const side = Math.random()<0.5 ? -1 : 1;
104
+ const x = side * (W/2) * (1-t);
105
+ const y = H + RH * t;
106
+ push(x+jit(0.02), y+jit(0.02), along+jit(0.03), CYAN);
107
+ }
108
+ // Ridge line accent
109
+ for (let i=0;i<260;i++){ push(jit(0.05), H+RH+jit(0.02), (Math.random()-0.5)*D, CYAN); }
110
+ // Windows: brighter clusters on front face (z = D/2)
111
+ const winCenters = [[-1.6,1.3],[1.6,1.3],[0,0.9]];
112
+ for (const [wx,wy] of winCenters){
113
+ for (let i=0;i<230;i++){
114
+ push(wx+jit(0.5), wy+jit(0.6), D/2+0.02, WHITE);
115
+ }
116
+ }
117
+ // Grounds: radial point grid on y=0 plane, fading outward
118
+ const groundR = 11;
119
+ for (let i=0;i<3200;i++){
120
+ const r = Math.pow(Math.random(),0.6)*groundR;
121
+ const a = Math.random()*Math.PI*2;
122
+ const x = Math.cos(a)*r, z = Math.sin(a)*r;
123
+ // skip the footprint interior so the house reads clearly
124
+ if (Math.abs(x)<W/2+0.3 && Math.abs(z)<D/2+0.3) continue;
125
+ push(x, jit(0.04), z, BLUE);
126
+ }
127
+ // A few tall accents (trees) at corners of the plot
128
+ const trees = [[-7,-6],[7,-6.5],[-6.5,6],[7.5,6]];
129
+ for (const [tx,tz] of trees){
130
+ for (let i=0;i<420;i++){
131
+ const h = Math.random();
132
+ const spread = (1-h)*1.1;
133
+ push(tx+jit(spread), 0.2 + h*3.4, tz+jit(spread), [0.16,0.6,0.5]);
134
+ }
135
+ }
136
+ return pts;
137
+ }
138
+
139
+ const ESTATE = buildEstatePoints();
140
+ const rstat = document.getElementById('rstat');
141
+ const rnote = document.getElementById('rnote');
142
+
143
+ // ---- 2D never-blank fallback (source-over, small points, shared field) ----
144
+ function run2DFallback(reason){
145
+ const glc = document.getElementById('gl'); glc.hidden = true;
146
+ const c = document.getElementById('fb'); c.hidden = false;
147
+ const ctx = c.getContext('2d');
148
+ rstat.textContent = '2D fallback';
149
+ rstat.style.color = '#f0d98a';
150
+ rnote.textContent = reason || 'WebGL2 unavailable — projecting same model';
151
+ let W,H,DPR;
152
+ function resize(){
153
+ DPR = Math.min(window.devicePixelRatio||1, 2);
154
+ W = c.clientWidth = window.innerWidth; H = c.clientHeight = window.innerHeight;
155
+ c.width = W*DPR; c.height = H*DPR; ctx.setTransform(DPR,0,0,DPR,0,0);
156
+ }
157
+ window.addEventListener('resize', resize); resize();
158
+ let ang = 0;
159
+ const focal = 620, camY = 2.2, camDist = 18;
160
+ function frame(){
161
+ ang += 0.0032;
162
+ ctx.clearRect(0,0,W,H);
163
+ const cx=W/2, cy=H/2 + 40;
164
+ const ca=Math.cos(ang), sa=Math.sin(ang);
165
+ // depth sort (paint far first)
166
+ const proj = [];
167
+ for (const p of ESTATE){
168
+ const x = p.x*ca - p.z*sa;
169
+ const z = p.x*sa + p.z*ca + camDist;
170
+ const y = p.y - camY;
171
+ if (z<=0.1) continue;
172
+ const s = focal/z;
173
+ proj.push({ sx: cx + x*s, sy: cy - y*s, z, s, c:p.c });
174
+ }
175
+ proj.sort((a,b)=>b.z-a.z);
176
+ for (const q of proj){
177
+ const r = Math.max(0.35, q.s*0.05);
178
+ const a = Math.min(0.85, 34/q.z);
179
+ ctx.beginPath();
180
+ ctx.fillStyle = `rgba(${(q.c[0]*255)|0},${(q.c[1]*255)|0},${(q.c[2]*255)|0},${a})`;
181
+ ctx.arc(q.sx, q.sy, r, 0, Math.PI*2);
182
+ ctx.fill();
183
+ }
184
+ requestAnimationFrame(frame);
185
+ }
186
+ frame();
187
+ }
188
+
189
+ // ---- WebGL2 path (soft gaussian points + bloom + orbit), falls back on any failure ----
190
+ async function runWebGL(){
191
+ const canvas = document.getElementById('gl');
192
+ const gl2 = canvas.getContext('webgl2');
193
+ if (!gl2) throw new Error('no-webgl2');
194
+
195
+ const THREE = await import('three');
196
+ const { OrbitControls } = await import('three/addons/controls/OrbitControls.js');
197
+ const { EffectComposer } = await import('three/addons/postprocessing/EffectComposer.js');
198
+ const { RenderPass } = await import('three/addons/postprocessing/RenderPass.js');
199
+ const { UnrealBloomPass } = await import('three/addons/postprocessing/UnrealBloomPass.js');
200
+
201
+ const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:true });
202
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio||1, 2));
203
+ renderer.setSize(window.innerWidth, window.innerHeight);
204
+
205
+ const scene = new THREE.Scene();
206
+ const camera = new THREE.PerspectiveCamera(52, window.innerWidth/window.innerHeight, 0.1, 200);
207
+ camera.position.set(13, 8, 15);
208
+
209
+ const controls = new OrbitControls(camera, renderer.domElement);
210
+ controls.enableDamping = true; controls.autoRotate = true; controls.autoRotateSpeed = 0.55;
211
+ controls.target.set(0, 1.6, 0); controls.minDistance = 8; controls.maxDistance = 40;
212
+
213
+ const n = ESTATE.length;
214
+ const positions = new Float32Array(n*3);
215
+ const colors = new Float32Array(n*3);
216
+ for (let i=0;i<n;i++){
217
+ const p = ESTATE[i];
218
+ positions[i*3]=p.x; positions[i*3+1]=p.y; positions[i*3+2]=p.z;
219
+ colors[i*3]=p.c[0]; colors[i*3+1]=p.c[1]; colors[i*3+2]=p.c[2];
220
+ }
221
+ const geo = new THREE.BufferGeometry();
222
+ geo.setAttribute('position', new THREE.BufferAttribute(positions,3));
223
+ geo.setAttribute('color', new THREE.BufferAttribute(colors,3));
224
+
225
+ const mat = new THREE.ShaderMaterial({
226
+ uniforms: { uSize:{value:16.0}, uPixelRatio:{value:renderer.getPixelRatio()} },
227
+ transparent:true, depthWrite:false, blending:THREE.AdditiveBlending,
228
+ vertexColors:true,
229
+ vertexShader:`
230
+ uniform float uSize; uniform float uPixelRatio;
231
+ varying vec3 vColor;
232
+ void main(){
233
+ vColor = color;
234
+ vec4 mv = modelViewMatrix * vec4(position,1.0);
235
+ gl_PointSize = uSize * uPixelRatio * (1.0 / -mv.z) * 4.0;
236
+ gl_Position = projectionMatrix * mv;
237
+ }`,
238
+ fragmentShader:`
239
+ varying vec3 vColor;
240
+ void main(){
241
+ vec2 d = gl_PointCoord - vec2(0.5);
242
+ float r = dot(d,d);
243
+ float a = exp(-r*7.0) * 0.30; // soft gaussian, low per-point alpha
244
+ if (a < 0.01) discard;
245
+ gl_FragColor = vec4(vColor, a);
246
+ }`
247
+ });
248
+ scene.add(new THREE.Points(geo, mat));
249
+
250
+ const composer = new EffectComposer(renderer);
251
+ composer.addPass(new RenderPass(scene, camera));
252
+ const bloom = new UnrealBloomPass(
253
+ new THREE.Vector2(window.innerWidth, window.innerHeight), 0.7, 0.6, 0.25);
254
+ composer.addPass(bloom);
255
+
256
+ window.addEventListener('resize', ()=>{
257
+ camera.aspect = window.innerWidth/window.innerHeight; camera.updateProjectionMatrix();
258
+ renderer.setSize(window.innerWidth, window.innerHeight);
259
+ composer.setSize(window.innerWidth, window.innerHeight);
260
+ });
261
+
262
+ rstat.textContent = 'WebGL2'; rstat.style.color = '#9fe6dd';
263
+ rnote.textContent = `three r${THREE.REVISION} · ${n.toLocaleString()} points · soft-gaussian + bloom`;
264
+
265
+ (function loop(){ controls.update(); composer.render(); requestAnimationFrame(loop); })();
266
+ }
267
+
268
+ runWebGL().catch(err => {
269
+ run2DFallback(err && err.message === 'no-webgl2'
270
+ ? 'WebGL2 unavailable — projecting same model'
271
+ : 'renderer offline — projecting same model');
272
+ });
273
+ </script>
274
+ </body>
275
+ </html>