← back to Atmos Game
Design-review pass (graphic-designer agent): IBL+ACES tonemap+rim light, nose-in chase orientation, right-sized framing, HUD gated to play state, clean title hero
89093ba962e3121c2699140a73545bb47cd3125a · 2026-07-23 15:46:30 -0700 · Steve
Files touched
A assets/gen/capture.mjsA assets/review/01-start.pngA assets/review/02-play.pngA assets/review/03-play2.pngA assets/review/BEFORE-play.pngA assets/review2/01-start.pngA assets/review2/02-play.pngA assets/review2/03-play2.pngA assets/review3/01-start.pngA assets/review3/02-play.pngA assets/review3/03-play2.pngA assets/review4/01-start.pngA assets/review4/02-play.pngA assets/review4/03-play2.pngM index.html
Diff
commit 89093ba962e3121c2699140a73545bb47cd3125a
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Jul 23 15:46:30 2026 -0700
Design-review pass (graphic-designer agent): IBL+ACES tonemap+rim light, nose-in chase orientation, right-sized framing, HUD gated to play state, clean title hero
---
assets/gen/capture.mjs | 38 ++++++++++++++++++++++++++++++++++++++
assets/review/01-start.png | Bin 0 -> 1402353 bytes
assets/review/02-play.png | Bin 0 -> 1431879 bytes
assets/review/03-play2.png | Bin 0 -> 1372651 bytes
assets/review/BEFORE-play.png | Bin 0 -> 1431879 bytes
assets/review2/01-start.png | Bin 0 -> 1231596 bytes
assets/review2/02-play.png | Bin 0 -> 1232348 bytes
assets/review2/03-play2.png | Bin 0 -> 1031924 bytes
assets/review3/01-start.png | Bin 0 -> 1463585 bytes
assets/review3/02-play.png | Bin 0 -> 993826 bytes
assets/review3/03-play2.png | Bin 0 -> 1203279 bytes
assets/review4/01-start.png | Bin 0 -> 1329244 bytes
assets/review4/02-play.png | Bin 0 -> 839042 bytes
assets/review4/03-play2.png | Bin 0 -> 1268886 bytes
index.html | 37 ++++++++++++++++++++++++++++---------
15 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/assets/gen/capture.mjs b/assets/gen/capture.mjs
new file mode 100644
index 0000000..b6bd08e
--- /dev/null
+++ b/assets/gen/capture.mjs
@@ -0,0 +1,38 @@
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+const { chromium } = require('/Users/macstudio3/.npm-global/lib/node_modules/playwright');
+const OUT = process.env.OUT || '/Users/macstudio3/Projects/atmos-game/assets/review';
+import { mkdirSync } from 'fs';
+mkdirSync(OUT, { recursive: true });
+
+const browser = await chromium.launch({
+ channel: 'chrome', headless: true,
+ args: ['--use-gl=angle','--use-angle=swiftshader','--enable-unsafe-swiftshader','--ignore-gpu-blocklist','--enable-webgl']
+});
+const page = await browser.newPage({ viewport:{width:1280,height:800}, deviceScaleFactor:2 });
+const errs=[];
+page.on('console', m=>{ if(m.type()==='error') errs.push(m.text()); });
+page.on('pageerror', e=>errs.push('PAGEERR '+e.message));
+
+await page.goto('http://localhost:8087/?v=2', { waitUntil:'networkidle', timeout:60000 });
+await page.waitForTimeout(3000); // three init + model load + clouds drift
+await page.screenshot({ path:`${OUT}/01-start.png` });
+console.log('shot 01-start');
+
+// begin play
+await page.mouse.click(640,400);
+await page.waitForTimeout(400);
+// steer up-ish and fire for a while so obstacles spawn + missiles show
+await page.mouse.move(760,330);
+await page.keyboard.down('Space');
+await page.waitForTimeout(2600);
+await page.screenshot({ path:`${OUT}/02-play.png` });
+console.log('shot 02-play');
+await page.mouse.move(520,300);
+await page.waitForTimeout(2200);
+await page.screenshot({ path:`${OUT}/03-play2.png` });
+console.log('shot 03-play2');
+await page.keyboard.up('Space');
+
+console.log('CONSOLE_ERRORS', JSON.stringify(errs.slice(0,12)));
+await browser.close();
diff --git a/assets/review/01-start.png b/assets/review/01-start.png
new file mode 100644
index 0000000..9da94ec
Binary files /dev/null and b/assets/review/01-start.png differ
diff --git a/assets/review/02-play.png b/assets/review/02-play.png
new file mode 100644
index 0000000..f33f279
Binary files /dev/null and b/assets/review/02-play.png differ
diff --git a/assets/review/03-play2.png b/assets/review/03-play2.png
new file mode 100644
index 0000000..64fff83
Binary files /dev/null and b/assets/review/03-play2.png differ
diff --git a/assets/review/BEFORE-play.png b/assets/review/BEFORE-play.png
new file mode 100644
index 0000000..f33f279
Binary files /dev/null and b/assets/review/BEFORE-play.png differ
diff --git a/assets/review2/01-start.png b/assets/review2/01-start.png
new file mode 100644
index 0000000..2381505
Binary files /dev/null and b/assets/review2/01-start.png differ
diff --git a/assets/review2/02-play.png b/assets/review2/02-play.png
new file mode 100644
index 0000000..d0f4172
Binary files /dev/null and b/assets/review2/02-play.png differ
diff --git a/assets/review2/03-play2.png b/assets/review2/03-play2.png
new file mode 100644
index 0000000..9c3cccc
Binary files /dev/null and b/assets/review2/03-play2.png differ
diff --git a/assets/review3/01-start.png b/assets/review3/01-start.png
new file mode 100644
index 0000000..affff49
Binary files /dev/null and b/assets/review3/01-start.png differ
diff --git a/assets/review3/02-play.png b/assets/review3/02-play.png
new file mode 100644
index 0000000..7364713
Binary files /dev/null and b/assets/review3/02-play.png differ
diff --git a/assets/review3/03-play2.png b/assets/review3/03-play2.png
new file mode 100644
index 0000000..f0c76e0
Binary files /dev/null and b/assets/review3/03-play2.png differ
diff --git a/assets/review4/01-start.png b/assets/review4/01-start.png
new file mode 100644
index 0000000..e0b1948
Binary files /dev/null and b/assets/review4/01-start.png differ
diff --git a/assets/review4/02-play.png b/assets/review4/02-play.png
new file mode 100644
index 0000000..66c2fdd
Binary files /dev/null and b/assets/review4/02-play.png differ
diff --git a/assets/review4/03-play2.png b/assets/review4/03-play2.png
new file mode 100644
index 0000000..a387029
Binary files /dev/null and b/assets/review4/03-play2.png differ
diff --git a/index.html b/index.html
index 19cd987..98497f5 100644
--- a/index.html
+++ b/index.html
@@ -9,7 +9,8 @@
* { margin:0; padding:0; box-sizing:border-box; }
html,body { height:100%; overflow:hidden; background:var(--sky); font-family:"Helvetica Neue",Arial,sans-serif; color:#fff; }
#canvas { position:fixed; inset:0; display:block; }
- #hud { position:fixed; inset:0; pointer-events:none; z-index:10; }
+ #hud { position:fixed; inset:0; pointer-events:none; z-index:10; opacity:0; transition:opacity .6s ease; }
+ body.playing #hud { opacity:1; }
.corner { position:absolute; padding:16px 20px; text-shadow:0 1px 3px rgba(8,20,32,.45); }
#score { top:0; left:0; font-size:14px; letter-spacing:.18em; }
#score b { display:block; font-size:34px; font-weight:600; margin-top:2px; }
@@ -71,6 +72,7 @@
<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
+import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
/* ===========================================================================
ATMOS · Skyfire — Three.js homage to atmos.leeroy.ca, now with AI-generated
@@ -90,8 +92,13 @@ const renderer = new THREE.WebGLRenderer({ canvas, antialias:true });
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
renderer.setSize(innerWidth, innerHeight);
renderer.outputColorSpace = THREE.SRGBColorSpace;
+renderer.toneMapping = THREE.ACESFilmicToneMapping; // cinematic response — lifts AI meshes
+renderer.toneMappingExposure = 1.08;
const scene = new THREE.Scene();
+// image-based lighting so PBR meshes read like product shots (fixes the flat/dark AI model)
+{ const pmrem = new THREE.PMREMGenerator(renderer);
+ scene.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture; }
const SKY_TOP = new THREE.Color(0x2f7fb5), SKY_BOT = new THREE.Color(0xbfe6f5);
scene.background = SKY_BOT.clone();
scene.fog = new THREE.Fog(0xbfe6f5, 60, 250);
@@ -99,8 +106,9 @@ scene.fog = new THREE.Fog(0xbfe6f5, 60, 250);
const camera = new THREE.PerspectiveCamera(62, innerWidth/innerHeight, 0.1, 600);
camera.position.set(0,2.5,14); camera.lookAt(0,1,-30);
-scene.add(new THREE.HemisphereLight(0xffffff, 0x6f97b0, 1.1));
-const sun = new THREE.DirectionalLight(0xfff4e0, 1.25); sun.position.set(-8,14,6); scene.add(sun);
+scene.add(new THREE.HemisphereLight(0xffffff, 0x6f97b0, 0.9));
+const sun = new THREE.DirectionalLight(0xfff4e0, 1.6); sun.position.set(-8,14,6); scene.add(sun);
+const rim = new THREE.DirectionalLight(0xbfe6ff, 1.1); rim.position.set(6,4,-10); scene.add(rim); // sky rim from behind
// ---- gradient sky dome ----
{
@@ -144,7 +152,7 @@ const MODELS = {}; // id -> normalized THREE.Object3D (template to clone), or
// per-item: target max-dimension size, rotation offset (radians), and a fallback builder
const ITEM = {
- plane: { size:5.2, rot:[0, Math.PI, 0] },
+ plane: { size:4.2, rot:[0, Math.PI/2, 0] }, // nose into the screen (-z); tail to camera (chase cam)
bird: { size:2.6, rot:[0, 0, 0] },
balloon: { size:7.0, rot:[0, 0, 0] },
blimp: { size:13, rot:[0, Math.PI/2, 0] },
@@ -152,7 +160,18 @@ const ITEM = {
function normalize(obj, size, rot){
const wrap = new THREE.Group();
- obj.traverse(o=>{ if(o.isMesh){ o.castShadow=false; if(o.geometry && !o.geometry.attributes.normal) o.geometry.computeVertexNormals(); if(o.material){ o.material.side=THREE.DoubleSide; } } });
+ obj.traverse(o=>{ if(o.isMesh){
+ o.castShadow=false;
+ if(o.geometry && !o.geometry.attributes.normal) o.geometry.computeVertexNormals();
+ let m=o.material;
+ if(m && m.isMeshBasicMaterial){ // unlit AI export -> make it respond to lights + IBL
+ m = new THREE.MeshStandardMaterial({ color:m.color, map:m.map||null,
+ vertexColors:m.vertexColors, roughness:.65, metalness:.15 });
+ o.material=m;
+ }
+ if(m){ m.side=THREE.DoubleSide; if('envMapIntensity' in m) m.envMapIntensity=1.1;
+ if('roughness' in m && m.roughness>0.9) m.roughness=0.7; }
+ }});
const box = new THREE.Box3().setFromObject(obj);
const c = box.getCenter(new THREE.Vector3()), s = box.getSize(new THREE.Vector3());
const k = size / Math.max(s.x, s.y, s.z || 1e-3);
@@ -176,7 +195,7 @@ function loadModel(id){
const plane = new THREE.Group();
const planePrim = buildPlanePrimitive();
plane.add(planePrim);
-plane.position.set(0,0,2); scene.add(plane);
+plane.position.set(0,-1.8,0); scene.add(plane); // title hero: low, clear of the CTA line
function buildPlanePrimitive(){
const g = new THREE.Group();
@@ -297,10 +316,10 @@ canvas.addEventListener('click',()=>{ if(state!=='play') begin(); });
const startEl=document.getElementById('start'), overEl=document.getElementById('gameover');
const hpFill=document.getElementById('hpfill'), scoreEl=document.querySelector('#score b'), distEl=document.getElementById('dist'), altEl=document.getElementById('alt');
-function begin(){ if(state==='play')return; score=kills=dist=0; hp=100; firing=false; cooldown=0; target.x=0; target.y=1; plane.position.set(0,0,2);
+function begin(){ if(state==='play')return; score=kills=dist=0; hp=100; firing=false; cooldown=0; target.x=0; target.y=1; plane.position.set(0,0,0);
obstacles.forEach(o=>{o.alive=false;o.group.visible=false;}); missiles.forEach(m=>{m.userData.alive=false;m.visible=false;});
- state='play'; startEl.classList.add('hidden'); overEl.classList.remove('show'); }
-function endGame(){ state='over'; document.getElementById('finalScore').textContent=score; document.getElementById('finalDist').textContent=Math.floor(dist/100); document.getElementById('finalKills').textContent=kills; overEl.classList.add('show'); }
+ state='play'; document.body.classList.add('playing'); startEl.classList.add('hidden'); overEl.classList.remove('show'); }
+function endGame(){ state='over'; document.body.classList.remove('playing'); document.getElementById('finalScore').textContent=score; document.getElementById('finalDist').textContent=Math.floor(dist/100); document.getElementById('finalKills').textContent=kills; overEl.classList.add('show'); }
addEventListener('resize',()=>{ camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth,innerHeight); });
← 8de8aab Add AI 3D-item pipeline (FLUX->HF image-to-3D) + GLTFLoader
·
back to Atmos Game
·
Upgrade procedural obstacle art (striped balloon, flapping s d8e013a →