diff --git a/assets/blender/expressway/README.md b/assets/blender/expressway/README.md new file mode 100644 index 0000000..386093c --- /dev/null +++ b/assets/blender/expressway/README.md @@ -0,0 +1,12 @@ +# Expressway grand tourer + +Original portfolio coachwork developed from the approved `../evolution/nightdrive-evolution.blend` at `c9ac36e`. No third-party model, texture, or generated project evidence is used. + +- `nightdrive-expressway.blend`: isolated editable source. Open the **Midnight Expressway** scene. Body components, optical cells, intake vanes, wheel machining, panel seams, wing details, and look-development setup remain editable. +- `author-expressway.py`: appends the approved source into a separate scene and authors this edition. Run once in a fresh Blender session with `__file__` set to the script path. It saves only the isolated expressway library; it does not overwrite the approved evolution source. +- `export-expressway.py`: run with the expressway source open. It evaluates modifiers into a separate export scene, batches by material and wheel, exports the runtime GLB, and writes its provenance JSON. Four wheel parents remain independently rotatable. Cameras and look-development lights are excluded. +- `nightdrive-expressway.asset.json`: export path, SHA-256, triangle count, and source lineage. + +Runtime: 31,288 triangles, 19 material batches, four independently rotating wheel groups. Geometry follows the existing Blender-to-glTF coordinate convention and runtime scale. Body suspension is applied separately from grounded wheels. + +The runtime asset is `src/assets/nightdrive-grand-tourer-expressway.glb`. The review contains a Blender look-development render and actual in-browser views. The Static-mode JPEGs are captures of this portfolio's live Three.js world; they contain no fabricated project media. diff --git a/assets/blender/expressway/author-expressway.py b/assets/blender/expressway/author-expressway.py new file mode 100644 index 0000000..14c99eb --- /dev/null +++ b/assets/blender/expressway/author-expressway.py @@ -0,0 +1,124 @@ +"""Append the approved coachwork into its own scene; author only the new edition. +Run inside Blender with __file__ pointing here. No open project is overwritten. +""" +import bpy, math +from pathlib import Path +from mathutils import Vector +root_path = Path(__file__).resolve().parents[3] +source = root_path / 'assets/blender/evolution/nightdrive-evolution.blend' +with bpy.data.libraries.load(str(source), link=False) as (available, loaded): + loaded.scenes = ['Portfolio Evolution'] +scene = loaded.scenes[0] +scene.name = 'Midnight Expressway' +bpy.context.window.scene = scene +car = next(o for o in scene.objects if o.type=='EMPTY' and o.name.startswith('chase-car')) +materials = {m.name.split('.')[0]: m for o in scene.objects if o.type=='MESH' for m in o.data.materials} + +def finish(obj, name, material, bevel=0.007): + obj.name = 'expressway-' + name + obj.parent = car + obj.data.materials.append(materials[material]) + if bevel: + mod = obj.modifiers.new('Machined radii', 'BEVEL'); mod.width=bevel; mod.segments=2 + obj.modifiers.new('Surface normals', 'WEIGHTED_NORMAL') + return obj + +def box(name, loc, dims, mat, bevel=0.007): + bpy.ops.mesh.primitive_cube_add(size=1, location=loc) + o=bpy.context.object; o.dimensions=dims + bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) + return finish(o,name,mat,bevel) + +def shell(name, vertices, faces, mat, bevel=0.005): + mesh=bpy.data.meshes.new(name); mesh.from_pydata(vertices,[],faces); mesh.update() + o=bpy.data.objects.new(name,mesh); scene.collection.objects.link(o) + return finish(o,name,mat,bevel) + +def line(name, coords, mat, radius=0.004): + curve=bpy.data.curves.new(name,'CURVE'); curve.dimensions='3D' + curve.resolution_u=1; curve.bevel_depth=radius; curve.bevel_resolution=2 + spline=curve.splines.new('POLY'); spline.points.add(len(coords)-1) + for p,co in zip(spline.points,coords): p.co=(*co,1) + obj=bpy.data.objects.new(name,curve); scene.collection.objects.link(obj) + obj.parent=car; obj.data.materials.append(materials[mat]); obj.name='expressway-'+name + return obj + +# Material story: cold painted metal, brushed alloy, smoke and deep graphite. +for name,color,metal,rough in [ + ('M_Body_Gunmetal',(0.18,0.28,0.36,1),0.72,0.27), + ('M_Body_Haunch',(0.30,0.41,0.48,1),0.78,0.22), + ('M_Lower_Graphite',(0.018,0.028,0.039,1),0.6,0.38), + ('M_Wheel',(0.45,0.53,0.57,1),0.92,0.21), + ('M_Tire',(0.009,0.012,0.016,1),0.0,0.9), + ('M_Glass_Smoke',(0.014,0.045,0.065,1),0.36,0.14)]: + bsdf=materials[name].node_tree.nodes.get('Principled BSDF') + bsdf.inputs['Base Color'].default_value=color + bsdf.inputs['Metallic'].default_value=metal; bsdf.inputs['Roughness'].default_value=rough + if 'Body' in name: + bsdf.inputs['Coat Weight'].default_value=0.42; bsdf.inputs['Coat Roughness'].default_value=0.19 + +# Replace the plain lamp with fourteen paired optical cells and lit outer returns. +for obj in list(scene.objects): + if obj.name.startswith(('rear-light-bar','evolution-lamp-divider','signature-turbine-vane')): + bpy.data.objects.remove(obj,do_unlink=True) +box('rear-optical-cassette',(0,2.684,0.700),(1.79,0.06,0.21),'M_Lower_Graphite',0.025) +for side in [-1,1]: + for i in range(7): + x=side*(0.11+i*0.109) + for z in [0.664,0.746]: + box('rear-optic-cell',(x,2.720,z),(0.091,0.022,0.034),'M_Rear_Light',0.006) + box('lamp-return',(side*0.852,2.704,0.705),(0.025,0.04,0.139),'M_Rear_Light',0.009) + # Side intake recess, bevelled upper lip and three angled internal vanes. + x=side*1.073 + box('side-intake',(x,0.16,0.53),(0.027,1.03,0.255),'M_Lower_Graphite',0.033) + box('intake-upper-lip',(side*1.093,0.13,0.670),(0.035,1.09,0.025),'M_Body_Haunch') + for i in range(4): + o=box('intake-vane',(side*1.095,-0.18+i*0.22,0.54),(0.025,0.022,0.21),'M_Wheel',0.003) + o.rotation_euler.x=-0.32 + # Deep lower blade has a distinct kicked-up rear end. + poly=[(side*1.05,-1.03,0.24),(side*1.13,-1.03,0.20),(side*1.13,1.1,0.20),(side*1.11,1.30,0.36),(side*1.05,1.30,0.36)] + shell('sculpted-skirt',poly,[tuple(range(5))],'M_Body_Haunch') + line('skirt-channel',[(side*1.137,-0.8,0.224),(side*1.137,0.92,0.224),(side*1.117,1.17,0.31)],'M_Cyan_Accent',0.006) + # Rear deck channel and restrained panel separation follow the wedge surfaces. + line('rear-deck-seam',[(side*.72,1.12,.928),(side*.76,1.78,.876),(side*.85,2.25,.825)],'M_Lower_Graphite',0.006) + line('haunch-pinstripe',[(side*.91,1.2,.905),(side*1.005,1.67,.857),(side*.997,2.20,.759)],'M_Wheel',0.0035) + for i in range(4): + box('deck-extraction-slot',(side*.49,1.36+i*.116,.906-i*.012),(.31,.039,.018),'M_Lower_Graphite',0.009) + # Larger aerofoil endplates, kinked with a recessed coral slit. + box('wing-endplate-shell',(side*1.195,2.35,1.268),(.032,.43,.24),'M_Body_Haunch',.016) + box('wing-endplate-inlay',(side*1.213,2.39,1.28),(.009,.22,.025),'M_Rear_Light',.004) + # Exhausts inside the graphite recess, with dark cores instead of solid cylinders. + for x0 in [0.29,0.43]: + x=side*x0 + box('rear-exhaust-surround',(x,2.7,.37),(.105,.115,.085),'M_Wheel',.018) + box('rear-exhaust-core',(x,2.762,.37),(.079,.01,.059),'M_Lower_Graphite',.014) + for i in range(5): + box('rear-cooling-slot',(side*(.53+i*.06),2.704,.497),(.028,.018,.064),'M_Lower_Graphite',.005) + +# Diffuser undertray: channels and an alloy trailing edge remain readable at speed. +line('diffuser-frame',[(-.82,2.68,.29),(-.63,2.78,.24),(.63,2.78,.24),(.82,2.68,.29)],'M_Wheel',.009) +for x in [-.66,-.33,0,.33,.66]: + shell('diffuser-strake',[(x,2.25,.22),(x,2.74,.26),(x,2.78,.105),(x,2.36,.105)],[(0,1,2,3)],'M_Lower_Graphite',0) + +# Turbine machining has a dished barrel, swept spokes and a shoulder ring. +for side in [-1,1]: + for axle,y,z,radius in [('front',-1.62,.42,.42),('rear',1.62,.46,.46)]: + label=f'wheel-{axle}-{"left" if side<0 else "right"}' + for rad,xoff,thick,mat in [(radius-.016,1.153,.009,'M_Tire'),(.282 if axle=='rear' else .26,1.181,.008,'M_Wheel')]: + coords=[(side*xoff,y+math.sin(i*math.tau/64)*rad,z+math.cos(i*math.tau/64)*rad) for i in range(65)] + line(label+'-shoulder',coords,mat,thick) + for i in range(10): + angle=i*math.tau/10 + verts=[] + for rad,a,xoff in [(.075,angle,1.17),(.255,angle+.30,1.193),(.263,angle+.48,1.193),(.088,angle+.35,1.17)]: + verts.append((side*xoff,y+math.sin(a)*rad,z+math.cos(a)*rad)) + shell(label+'-turbine',verts,[(0,1,2,3)],'M_Wheel',.004) + bpy.ops.mesh.primitive_uv_sphere_add(segments=16,ring_count=8,radius=1,location=(side*1.20,y,z)) + hub=bpy.context.object; hub.scale=(.025,.064,.064) + bpy.ops.object.transform_apply(location=False,rotation=False,scale=True) + finish(hub,label+'-hub','M_Lower_Graphite',0) + +# Write only this scene and its own dependencies, retaining individually editable objects. +output=root_path/'assets/blender/expressway/nightdrive-expressway.blend' +bpy.data.libraries.write(str(output),{scene},fake_user=True,compress=True) +print('AUTHORED',scene.name,len(scene.objects),'objects',output) diff --git a/assets/blender/expressway/export-expressway.py b/assets/blender/expressway/export-expressway.py new file mode 100644 index 0000000..dac2de5 --- /dev/null +++ b/assets/blender/expressway/export-expressway.py @@ -0,0 +1,51 @@ +"""Export isolated authored source into material batches; leave lookdev editable.""" +import bpy, json, hashlib +from mathutils import Matrix, Vector +from pathlib import Path +root_path=Path(__file__).resolve().parents[3] +scene=bpy.data.scenes['Midnight Expressway'] +bpy.context.window.scene=scene +export_scene=bpy.data.scenes.new('Expressway Export') +root=bpy.data.objects.new('evolution-chase-car',None); export_scene.collection.objects.link(root) +names={'M_Body_Gunmetal':'car-body','M_Body_Haunch':'body-haunches','M_Glass_Smoke':'rear-glass','M_Rear_Light':'rear-light-bar','M_Cyan_Accent':'car-underglow-source','M_Lower_Graphite':'body-trim','M_Wheel':'wheel-machining','M_Tire':'tires'} +depsgraph=bpy.context.evaluated_depsgraph_get(); groups={} +for obj in scene.objects: + if obj.type not in ['MESH','CURVE'] or obj.name.startswith('LOOKDEV'): continue + evaluated=obj.evaluated_get(depsgraph) + mesh=bpy.data.meshes.new_from_object(evaluated,depsgraph=depsgraph); mesh.transform(obj.matrix_world) + clone=bpy.data.objects.new('export-'+obj.name,mesh); export_scene.collection.objects.link(clone) + key=obj.data.materials[0].name.split('.')[0] + wheel=None + for axle in ['front','rear']: + for side in ['left','right']: + if any(token in obj.name for token in [f'{axle}-wheel-{side}', f'{axle}-rim-{side}', f'{axle}-rim-ring-{side}', f'wheel-{axle}-{side}']): + wheel=f'wheel-{axle}-{side}' + groups.setdefault((key,wheel),[]).append(clone) +bpy.context.window.scene=export_scene +wheel_roots={} +for (key,wheel),objects in groups.items(): + bpy.ops.object.select_all(action='DESELECT') + for obj in objects: obj.select_set(True) + bpy.context.view_layer.objects.active=objects[0] + if len(objects)>1: bpy.ops.object.join() + joined=bpy.context.object; joined.name='evolution-'+names[key] + if wheel: + if wheel not in wheel_roots: + axle='front' if 'front' in wheel else 'rear'; side=-1 if 'left' in wheel else 1 + wheel_root=bpy.data.objects.new(wheel,None); export_scene.collection.objects.link(wheel_root) + wheel_root.parent=root; wheel_root.location=(side*1.01,-1.62 if axle=='front' else 1.62,.42 if axle=='front' else .46) + wheel_roots[wheel]=wheel_root + wheel_root=wheel_roots[wheel] + joined.data.transform(Matrix.Translation(-wheel_root.location)) + joined.parent=wheel_root + else: joined.parent=root +bpy.ops.object.select_all(action='SELECT') +output=root_path/'src/assets/nightdrive-grand-tourer-expressway.glb' +bpy.ops.export_scene.gltf(filepath=str(output),export_format='GLB',use_selection=True,use_active_scene=True,export_apply=True,export_animations=False,export_cameras=False,export_lights=False) +triangles=0 +for obj in export_scene.objects: + if obj.type=='MESH': obj.data.calc_loop_triangles(); triangles+=len(obj.data.loop_triangles) +provenance={'asset':'Nightdrive expressway grand tourer','source':'nightdrive-expressway.blend','base':'../evolution/nightdrive-evolution.blend at c9ac36e','authorship':'Original procedural modelling in Blender for this portfolio; no external assets or generated project evidence.','editable_scene':'Midnight Expressway','material_groups':len(groups),'independent_wheels':4,'triangles':triangles,'export':'../../../src/assets/nightdrive-grand-tourer-expressway.glb','sha256':hashlib.sha256(output.read_bytes()).hexdigest()} +(root_path/'assets/blender/expressway/nightdrive-expressway.asset.json').write_text(json.dumps(provenance,indent=2)+'\n') +bpy.context.window.scene=scene +print(json.dumps(provenance)) diff --git a/assets/blender/expressway/nightdrive-expressway.asset.json b/assets/blender/expressway/nightdrive-expressway.asset.json new file mode 100644 index 0000000..e74ca93 --- /dev/null +++ b/assets/blender/expressway/nightdrive-expressway.asset.json @@ -0,0 +1,12 @@ +{ + "asset": "Nightdrive expressway grand tourer", + "source": "nightdrive-expressway.blend", + "base": "../evolution/nightdrive-evolution.blend at c9ac36e", + "authorship": "Original procedural modelling in Blender for this portfolio; no external assets or generated project evidence.", + "editable_scene": "Midnight Expressway", + "material_groups": 19, + "independent_wheels": 4, + "triangles": 31288, + "export": "../../../src/assets/nightdrive-grand-tourer-expressway.glb", + "sha256": "8418ff060b75c6fef200eaa526adae7fe51286b7fc30628671b9eb242641d1c3" +} diff --git a/assets/blender/expressway/nightdrive-expressway.blend b/assets/blender/expressway/nightdrive-expressway.blend new file mode 100644 index 0000000..1799705 Binary files /dev/null and b/assets/blender/expressway/nightdrive-expressway.blend differ diff --git a/docs/reviews/evidence/midnight-expressway/after-builds.png b/docs/reviews/evidence/midnight-expressway/after-builds.png new file mode 100644 index 0000000..35dcd2e Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/after-builds.png differ diff --git a/docs/reviews/evidence/midnight-expressway/after-contact.png b/docs/reviews/evidence/midnight-expressway/after-contact.png new file mode 100644 index 0000000..aad1331 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/after-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/after-desktop.png b/docs/reviews/evidence/midnight-expressway/after-desktop.png new file mode 100644 index 0000000..0b6e136 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/after-desktop.png differ diff --git a/docs/reviews/evidence/midnight-expressway/after-infrastructure.png b/docs/reviews/evidence/midnight-expressway/after-infrastructure.png new file mode 100644 index 0000000..fd0961d Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/after-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/after-phone-sign.png b/docs/reviews/evidence/midnight-expressway/after-phone-sign.png new file mode 100644 index 0000000..1e456ec Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/after-phone-sign.png differ diff --git a/docs/reviews/evidence/midnight-expressway/after-phone.png b/docs/reviews/evidence/midnight-expressway/after-phone.png new file mode 100644 index 0000000..2db4e54 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/after-phone.png differ diff --git a/docs/reviews/evidence/midnight-expressway/baseline-checks.log b/docs/reviews/evidence/midnight-expressway/baseline-checks.log new file mode 100644 index 0000000..c206701 --- /dev/null +++ b/docs/reviews/evidence/midnight-expressway/baseline-checks.log @@ -0,0 +1,150 @@ + +> portfolio-phase-1@1.0.0 build:preview +> npm run verify:approved-assets && npm run typecheck && npm run test:unit && npm run build:client && npm run build:ssr && npm run prerender -- --config config/site.preview.json && npm run verify:artifacts -- --config config/site.preview.json && npm run check:budgets:transfer + + +> portfolio-phase-1@1.0.0 verify:approved-assets +> node scripts/materialize-empty-asset-set.mjs + + +> portfolio-phase-1@1.0.0 typecheck +> vue-tsc --noEmit + + +> portfolio-phase-1@1.0.0 test:unit +> vitest run + + + RUN v4.1.11 /home/luca/Documents/Portfolio/.worktrees/midnight-expressway + + ❯ tests/unit/world-models.test.ts (29 tests | 7 failed) 272ms + × disposes a composer and its passes exactly once 32ms + × keeps the grand tourer anatomy readable in desktop and portrait chase views 29ms + × reflows a visible portrait sign into its navigator-safe pose without a teleport 4ms + × keeps a short-landscape left sign inside the narrow desktop roadside gutter 3ms + × places a portrait navigator arrival below its full-width destination panel 3ms + × grows a medium portrait navigator sign without enlarging the phone pose 7ms + × places route signs in their authored transition-safe corridors 10ms + ❯ tests/unit/SceneCanvas.test.ts (16 tests | 2 failed) 134ms + × does not request or render the scene for reduced motion 36ms + × does not request or render the scene for saved Static mode 6ms + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 9 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL tests/unit/SceneCanvas.test.ts > SceneCanvas > does not request or render the scene for reduced motion + FAIL tests/unit/SceneCanvas.test.ts > SceneCanvas > does not request or render the scene for saved Static mode +AssertionError: expected [] to have a length of 7 but got +0 + +- Expected ++ Received + +- 7 ++ 0 + + ❯ tests/unit/SceneCanvas.test.ts:95:9 + 93| expect( + 94| wrapper.findAll(".journey-poster-composition > span"), + 95| ).toHaveLength(7); + | ^ + 96| expect(wrapper.find(".journey-poster__sun").exists()).toBe(true); + 97| expect(wrapper.find(".journey-poster__road").exists()).toBe(true… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > disposes a composer and its passes exactly once +AssertionError: expected 0.39 to be greater than 0.54 + ❯ tests/unit/world-models.test.ts:439:32 + 437| expect(outputPass.dispose).toHaveBeenCalledOnce(); + 438| expect(composer.dispose).toHaveBeenCalledOnce(); + 439| expect(bloomPass.strength).toBeGreaterThan(0.54); + | ^ + 440| }); + 441| + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > keeps the grand tourer anatomy readable in desktop and portrait chase views +AssertionError: expected 56 to be 66 // Object.is equality + +- Expected ++ Received + +- 66 ++ 56 + + ❯ tests/unit/world-models.test.ts:461:52 + 459| + 460| const desktopCamera = createChaseCamera(16 / 9); + 461| expect((desktopCamera as { fov: number }).fov).toBe(66); + | ^ + 462| const desktop = projectedBounds(car.group, desktopCamera); + 463| expect(desktop.maxX - desktop.minX).toBeGreaterThan(0.28); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > reflows a visible portrait sign into its navigator-safe pose without a teleport +AssertionError: expected 595.8091348948393 to be greater than or equal to 626 + ❯ tests/unit/world-models.test.ts:818:37 + 816| if (presentation === null) throw new Error("Missing navigator-safe… + 817| expect(sign.group.position.distanceTo(midpoint)).toBeGreaterThan(0… + 818| expect(presentation.bounds.top).toBeGreaterThanOrEqual(626); + | ^ + 819| expect(presentation.bounds.bottom).toBeLessThanOrEqual(690); + 820| resources.dispose(); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > keeps a short-landscape left sign inside the narrow desktop roadside gutter +AssertionError: expected -10.199278524338355 to be greater than or equal to 8 + ❯ tests/unit/world-models.test.ts:884:38 + 882| const presentation = sign.inspect(camera, 780, 493); + 883| if (presentation === null) throw new Error("Missing short-landscap… + 884| expect(presentation.bounds.left).toBeGreaterThanOrEqual(8); + | ^ + 885| expect(presentation.bounds.right).toBeLessThanOrEqual(265); + 886| resources.dispose(); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > places a portrait navigator arrival below its full-width destination panel +AssertionError: expected 595.8091348948393 to be greater than or equal to 626 + ❯ tests/unit/world-models.test.ts:921:37 + 919| if (presentation === null) throw new Error("Missing portrait navig… + 920| expect(presentation.bounds.left).toBeGreaterThanOrEqual(8); + 921| expect(presentation.bounds.top).toBeGreaterThanOrEqual(626); + | ^ + 922| expect(presentation.bounds.right).toBeLessThanOrEqual(382); + 923| expect(presentation.bounds.bottom).toBeLessThanOrEqual(690); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > grows a medium portrait navigator sign without enlarging the phone pose +AssertionError: expected 122.59356940139988 to be less than or equal to 110 + ❯ tests/unit/world-models.test.ts:958:32 + 956| + 957| expect(phone.bounds.width).toBeGreaterThanOrEqual(85); + 958| expect(phone.bounds.width).toBeLessThanOrEqual(110); + | ^ + 959| expect(medium.viewportProfile).toBe("tall"); + 960| expect(medium.bounds.width).toBeGreaterThanOrEqual(145); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/9]⎯ + + FAIL tests/unit/world-models.test.ts > procedural world models > places route signs in their authored transition-safe corridors +AssertionError: expected 656.9555824147709 to be less than or equal to 630 + ❯ tests/unit/world-models.test.ts:1013:51 + 1011| expect(experiencePresentation?.corridor).toBe("right"); + 1012| expect(experiencePresentation?.bounds.top).toBeGreaterThanOrEqual(… + 1013| expect(experiencePresentation?.bounds.bottom).toBeLessThanOrEqual(… + | ^ + 1014| + 1015| sign.update(null); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/9]⎯ + + + Test Files 2 failed | 47 passed (49) + Tests 9 failed | 653 passed (662) + Start at 04:04:19 + Duration 23.81s (transform 17.57s, setup 0ms, import 30.29s, tests 45.44s, environment 19.53s) + diff --git a/docs/reviews/evidence/midnight-expressway/before-desktop.png b/docs/reviews/evidence/midnight-expressway/before-desktop.png new file mode 100644 index 0000000..0dfffca Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/before-desktop.png differ diff --git a/docs/reviews/evidence/midnight-expressway/before-infrastructure.png b/docs/reviews/evidence/midnight-expressway/before-infrastructure.png new file mode 100644 index 0000000..92a7f17 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/before-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/before-phone.png b/docs/reviews/evidence/midnight-expressway/before-phone.png new file mode 100644 index 0000000..eecca0d Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/before-phone.png differ diff --git a/docs/reviews/evidence/midnight-expressway/blender-coachwork.png b/docs/reviews/evidence/midnight-expressway/blender-coachwork.png new file mode 100644 index 0000000..d1d62e6 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/blender-coachwork.png differ diff --git a/docs/reviews/evidence/midnight-expressway/chrome-hardware-performance.json b/docs/reviews/evidence/midnight-expressway/chrome-hardware-performance.json new file mode 100644 index 0000000..85fe0ad --- /dev/null +++ b/docs/reviews/evidence/midnight-expressway/chrome-hardware-performance.json @@ -0,0 +1,48 @@ +{ + "browser": "152.0.7977.64", + "renderer": { + "renderer": "ANGLE (Intel, Mesa Intel(R) Graphics (ARL), OpenGL ES 3.2)", + "vendor": "Google Inc. (Intel)", + "canvas": { + "width": 1425, + "height": 900 + }, + "dpr": 1.0000000298023224 + }, + "samples": [ + { + "label": "1440x900 opening high preference", + "frames": 379, + "seconds": 6.004099999999999, + "averageFps": 63.12353225296048, + "p50Ms": 16.600000000000364, + "p95Ms": 20.900000000001455 + }, + { + "label": "1440x900 infrastructure reading", + "frames": 377, + "seconds": 6.012599999999998, + "averageFps": 62.70165984765328, + "p50Ms": 16.600000000002183, + "p95Ms": 20.900000000001455 + }, + { + "label": "1440x900 native scrolling and coasting", + "frames": 393, + "seconds": 6.0125, + "averageFps": 65.36382536382537, + "p50Ms": 16.599999999998545, + "p95Ms": 20.899999999997817 + }, + { + "label": "390x844 opening high preference", + "frames": 1132, + "seconds": 6.000000000000001, + "averageFps": 188.66666666666663, + "p50Ms": 4.199999999999818, + "p95Ms": 8.400000000000546 + } + ], + "errors": [], + "notes": "Headed host Google Chrome in an isolated temporary profile. Native devicePixelRatio 1. High maximum-quality preference; normal adaptive quality behavior preserved. requestAnimationFrame measurements; no profiler injection." +} diff --git a/docs/reviews/evidence/midnight-expressway/content-preservation.json b/docs/reviews/evidence/midnight-expressway/content-preservation.json new file mode 100644 index 0000000..18fd1b6 --- /dev/null +++ b/docs/reviews/evidence/midnight-expressway/content-preservation.json @@ -0,0 +1,46 @@ +{ + "baseline": { + "text": "8621cc0f9fab07e86edb0308cc7b7f9d7ce519b2a55b8a39bd1a01f6820b1520", + "rendered": "59a5678b6efe114292c5113ba7922c427d6911823a980ccbe43c284adabf80f5", + "head": "b5571c4ca03daff042ebc496a5c4e01ea70fee7ed2fab08d4b0b126440ab790d", + "links": "11e4e3627e0d5f1bf1140e7c73ab86a6d305ceaf8286c0649e4a4a3266e48977", + "sections": [ + "start", + "profile", + "experience", + "infrastructure", + "selected-builds", + "additional-work", + "toolkit", + "contact" + ], + "scene": "static", + "canvas": 0 + }, + "implementation": { + "text": "8621cc0f9fab07e86edb0308cc7b7f9d7ce519b2a55b8a39bd1a01f6820b1520", + "rendered": "59a5678b6efe114292c5113ba7922c427d6911823a980ccbe43c284adabf80f5", + "head": "b5571c4ca03daff042ebc496a5c4e01ea70fee7ed2fab08d4b0b126440ab790d", + "links": "11e4e3627e0d5f1bf1140e7c73ab86a6d305ceaf8286c0649e4a4a3266e48977", + "sections": [ + "start", + "profile", + "experience", + "infrastructure", + "selected-builds", + "additional-work", + "toolkit", + "contact" + ], + "scene": "static", + "canvas": 0 + }, + "sameText": true, + "sameRenderedText": true, + "sameMetadata": true, + "sameLinks": true, + "noJavaScript": { + "sections": 8, + "characters": 12333 + } +} diff --git a/docs/reviews/evidence/midnight-expressway/desktop-additional-work.png b/docs/reviews/evidence/midnight-expressway/desktop-additional-work.png new file mode 100644 index 0000000..7327b8d Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-additional-work.png differ diff --git a/docs/reviews/evidence/midnight-expressway/desktop-contact.png b/docs/reviews/evidence/midnight-expressway/desktop-contact.png new file mode 100644 index 0000000..29e11bd Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/desktop-experience.png b/docs/reviews/evidence/midnight-expressway/desktop-experience.png new file mode 100644 index 0000000..4178d54 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-experience.png differ diff --git a/docs/reviews/evidence/midnight-expressway/desktop-infrastructure.png b/docs/reviews/evidence/midnight-expressway/desktop-infrastructure.png new file mode 100644 index 0000000..1417f89 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/desktop-profile.png b/docs/reviews/evidence/midnight-expressway/desktop-profile.png new file mode 100644 index 0000000..fd97a16 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-profile.png differ diff --git a/docs/reviews/evidence/midnight-expressway/desktop-selected-builds.png b/docs/reviews/evidence/midnight-expressway/desktop-selected-builds.png new file mode 100644 index 0000000..7ff80e3 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-selected-builds.png differ diff --git a/docs/reviews/evidence/midnight-expressway/desktop-toolkit.png b/docs/reviews/evidence/midnight-expressway/desktop-toolkit.png new file mode 100644 index 0000000..789e137 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/desktop-toolkit.png differ diff --git a/docs/reviews/evidence/midnight-expressway/hardware-desktop.png b/docs/reviews/evidence/midnight-expressway/hardware-desktop.png new file mode 100644 index 0000000..0e04619 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/hardware-desktop.png differ diff --git a/docs/reviews/evidence/midnight-expressway/hardware-infrastructure.png b/docs/reviews/evidence/midnight-expressway/hardware-infrastructure.png new file mode 100644 index 0000000..484f375 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/hardware-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/hardware-phone.png b/docs/reviews/evidence/midnight-expressway/hardware-phone.png new file mode 100644 index 0000000..aec080c Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/hardware-phone.png differ diff --git a/docs/reviews/evidence/midnight-expressway/index.html b/docs/reviews/evidence/midnight-expressway/index.html new file mode 100644 index 0000000..586efe8 --- /dev/null +++ b/docs/reviews/evidence/midnight-expressway/index.html @@ -0,0 +1,21 @@ + + + + +Midnight expressway — visual review + + + +
Portfolio / September 2026 / Local visual review

Midnight
expressway.

A more physical road, coachbuilt silver bodywork, illuminated route signs, and a layered coral horizon. The approved portfolio content and adaptive soundtrack remain intact.

Open the live portfolio ↗Watch the journey ↓
+
+
01 / The opening

The same identity, a deeper world.

Drag the divider to compare the merged baseline with this implementation. These are actual browser captures; moving objects naturally occupy different positions.

New expressway opening with detailed road, silver car, opaque cyan terrain and separated coral sun bandsApproved previous openingBEFOREAFTER
+
02 / Motion study

Travel, settle, arrive.

Actual hardware-backed Chrome capture: forward acceleration, coasting, reverse document scrolling, and navigation to Infrastructure, Selected builds, and Contact. Silent recording with the High maximum-quality preference and normal adaptive behavior.

+
03 / Route objects

Signs with their own space.

Infrastructure in the approved baseline
Before — merged version.
New beveled Infrastructure sign clearly above its reading surface
After — beveled housing, luminous edges, inset label, and a reserved approach corridor.
Infrastructure sign and reading surface on phone
Phone sign arrival. The canvas retains its original stacking order.
Infrastructure reading layout at 320 pixels wide
320 px reading layout after the sign has departed.
+
04 / Coachwork

A more memorable grand tourer.

Blender render showing articulated rear lamps, machined wheels, side channels and refined wing

Editable Blender source retains the individual parts and look-development setup. The runtime export batches materials and preserves four independently rotating wheels.

+
05 / Small screens

The night drive travels with you.

Previous phone introduction
Before.
New phone introduction
After.
+
06 / Evidence and arrival

The work stays central.

Selected builds with approved real medication tracker media
Unchanged project evidence, staged within the continuous world.
Warm Contact arrival
Contact resolves into a warmer horizon and slower camera recovery.
+

Verified, with clear limits.

Approved wording, links, metadata, section order, and all 15 approved media/audio files match the baseline. Asset validation, typecheck, client/SSR build, prerender, artifact verification, and transfer checks pass. Static and reduced-motion views retain the full content.

Host Chrome uses the Intel hardware GPU: desktop samples averaged 63–65 fps across opening, reading, and native scrolling at 1440×900, with p95 frame time 20.9 ms. Physical phones and high-DPI displays remain unverified. The untouched baseline already had nine failing unit assertions; tests were preserved. Ready for visual review.

+
+ diff --git a/docs/reviews/evidence/midnight-expressway/journey-motion.mp4 b/docs/reviews/evidence/midnight-expressway/journey-motion.mp4 new file mode 100644 index 0000000..5407a5c Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/journey-motion.mp4 differ diff --git a/docs/reviews/evidence/midnight-expressway/landscape-contact.png b/docs/reviews/evidence/midnight-expressway/landscape-contact.png new file mode 100644 index 0000000..1d01018 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/landscape-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/landscape-infrastructure.png b/docs/reviews/evidence/midnight-expressway/landscape-infrastructure.png new file mode 100644 index 0000000..0a30594 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/landscape-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/landscape-start.png b/docs/reviews/evidence/midnight-expressway/landscape-start.png new file mode 100644 index 0000000..cf3a0cc Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/landscape-start.png differ diff --git a/docs/reviews/evidence/midnight-expressway/media-audio-preservation.json b/docs/reviews/evidence/midnight-expressway/media-audio-preservation.json new file mode 100644 index 0000000..0f843a5 --- /dev/null +++ b/docs/reviews/evidence/midnight-expressway/media-audio-preservation.json @@ -0,0 +1,96 @@ +{ + "assetCount": 15, + "allIdentical": true, + "assets": [ + { + "asset": "nightdrive-afterglow.mp3", + "sha256": "685687ad131d61c34e42bcee29af16a4c8180d788c67d75f2331fa9082a3a44e", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-afterglow.opus", + "sha256": "693215397e8ae4c2c13a4a6e4cc74b0059fb26b396c7f35d99e0e2c3e738d4b1", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-drive-lift.mp3", + "sha256": "edcb802938d3d1e53392f9ccd2e153f72a24b494c205ce6f556d73de5fe709ec", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-drive-lift.opus", + "sha256": "d580e58039c9d700599cf100c96b50d4b5816d93a0af738a93a1e8646fbb7566", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-intro.mp3", + "sha256": "008794ebd7f545c32f19aab4ada6aba40d9fc3341830a66e77f21d87a41c009b", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-intro.opus", + "sha256": "561c05cea71d0920ec323375644039007b91b0a4c346dc663e233ad42d6ab490", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-main.mp3", + "sha256": "796de8247c4cb8012d7c6883b534112ac09a40255a2c33cd68acf0f87c066659", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "nightdrive-main.opus", + "sha256": "81933fc8e589428ef07fb265572a79975f183848b6a23616cb289e33fe3fb88c", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-currency-converter.webp", + "sha256": "57159ae72a075ba5317217233c3c0eb210a485c51b5f2c37b5ed156d5ea37efb", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-medication-data-settings.webp", + "sha256": "d951dd723047b737ab6a7da46b82f3f3f3aca7ec8853314f74ac57e1950ce1ba", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-medication-logs.webp", + "sha256": "d34b2d41855e6dca4762fb9fc7728b64a94fef60de36149e465ce50821bc1dc7", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-medication-notification-settings.webp", + "sha256": "d2fe0076d6581e76c361cb656350c58f6685f6fe91c5b6c5871e60977e8d5be7", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-opinion-final-distribution.webp", + "sha256": "2f2f6d64b8bb4f79ecbce1a8bc486cf7bbdf4087eb4f10062a6fe889246dbdf1", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-opinion-polarization.webp", + "sha256": "77f0d5076769e6e45b566c5f322d8f535686f9e9f928e18fe4c16b3dac989c43", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + }, + { + "asset": "project-social-preview.webp", + "sha256": "ed470760643ef3d413b6ca4a0e1434771fcc9b61b6ac34011feae77a13f2daca", + "matchesApprovedManifest": true, + "samePreparedBaselineAndPreview": true + } + ] +} diff --git a/docs/reviews/evidence/midnight-expressway/narrow-contact.png b/docs/reviews/evidence/midnight-expressway/narrow-contact.png new file mode 100644 index 0000000..5ee0d46 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/narrow-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/narrow-infrastructure.png b/docs/reviews/evidence/midnight-expressway/narrow-infrastructure.png new file mode 100644 index 0000000..11b5d73 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/narrow-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/narrow-start.png b/docs/reviews/evidence/midnight-expressway/narrow-start.png new file mode 100644 index 0000000..968ce89 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/narrow-start.png differ diff --git a/docs/reviews/evidence/midnight-expressway/performance.json b/docs/reviews/evidence/midnight-expressway/performance.json new file mode 100644 index 0000000..e87f9fa --- /dev/null +++ b/docs/reviews/evidence/midnight-expressway/performance.json @@ -0,0 +1,39 @@ +{ + "renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)", + "hardwareVerified": false, + "quality": "low", + "samples": [ + { + "viewport": "390x844", + "seconds": 3.05, + "frames": 95, + "averageFps": 31.1, + "p50Ms": 33.3, + "p95Ms": 49.9 + }, + { + "viewport": "1440x900", + "seconds": 4.02, + "frames": 48, + "averageFps": 12, + "p50Ms": 83.3, + "p95Ms": 99.9 + } + ], + "inactiveSignScene": { + "drawCalls": 45, + "triangles": 44572, + "points": 160, + "lines": 4586, + "rendererGeometries": 34, + "rendererTextures": 3, + "programs": 21 + }, + "afterStaticHighLow": { + "orphanedGeometries": 0, + "orphanedTextures": 0 + }, + "limitations": "Software rendering with instrumentation. Physical devices and hardware frame rates unverified. Static quality removes all live canvases and clipping.", + "scope": "Initial software renderer inspection only", + "hardwareReport": "chrome-hardware-performance.json" +} diff --git a/docs/reviews/evidence/midnight-expressway/phone-additional-work.png b/docs/reviews/evidence/midnight-expressway/phone-additional-work.png new file mode 100644 index 0000000..833fd07 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-additional-work.png differ diff --git a/docs/reviews/evidence/midnight-expressway/phone-contact.png b/docs/reviews/evidence/midnight-expressway/phone-contact.png new file mode 100644 index 0000000..2a7aa16 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/phone-experience.png b/docs/reviews/evidence/midnight-expressway/phone-experience.png new file mode 100644 index 0000000..df65109 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-experience.png differ diff --git a/docs/reviews/evidence/midnight-expressway/phone-infrastructure.png b/docs/reviews/evidence/midnight-expressway/phone-infrastructure.png new file mode 100644 index 0000000..82aa65b Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/phone-profile.png b/docs/reviews/evidence/midnight-expressway/phone-profile.png new file mode 100644 index 0000000..b34453a Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-profile.png differ diff --git a/docs/reviews/evidence/midnight-expressway/phone-selected-builds.png b/docs/reviews/evidence/midnight-expressway/phone-selected-builds.png new file mode 100644 index 0000000..6e35143 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-selected-builds.png differ diff --git a/docs/reviews/evidence/midnight-expressway/phone-toolkit.png b/docs/reviews/evidence/midnight-expressway/phone-toolkit.png new file mode 100644 index 0000000..90413c4 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/phone-toolkit.png differ diff --git a/docs/reviews/evidence/midnight-expressway/reduced-motion-phone.png b/docs/reviews/evidence/midnight-expressway/reduced-motion-phone.png new file mode 100644 index 0000000..380975f Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/reduced-motion-phone.png differ diff --git a/docs/reviews/evidence/midnight-expressway/short-contact.png b/docs/reviews/evidence/midnight-expressway/short-contact.png new file mode 100644 index 0000000..0d70375 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/short-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/short-infrastructure.png b/docs/reviews/evidence/midnight-expressway/short-infrastructure.png new file mode 100644 index 0000000..6948854 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/short-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/short-start.png b/docs/reviews/evidence/midnight-expressway/short-start.png new file mode 100644 index 0000000..186cb35 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/short-start.png differ diff --git a/docs/reviews/evidence/midnight-expressway/static-phone.png b/docs/reviews/evidence/midnight-expressway/static-phone.png new file mode 100644 index 0000000..03b1555 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/static-phone.png differ diff --git a/docs/reviews/evidence/midnight-expressway/tablet-contact.png b/docs/reviews/evidence/midnight-expressway/tablet-contact.png new file mode 100644 index 0000000..a20c346 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/tablet-contact.png differ diff --git a/docs/reviews/evidence/midnight-expressway/tablet-infrastructure.png b/docs/reviews/evidence/midnight-expressway/tablet-infrastructure.png new file mode 100644 index 0000000..4b61d1e Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/tablet-infrastructure.png differ diff --git a/docs/reviews/evidence/midnight-expressway/tablet-selected-builds.png b/docs/reviews/evidence/midnight-expressway/tablet-selected-builds.png new file mode 100644 index 0000000..63f0175 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/tablet-selected-builds.png differ diff --git a/docs/reviews/evidence/midnight-expressway/tablet-start.png b/docs/reviews/evidence/midnight-expressway/tablet-start.png new file mode 100644 index 0000000..015f0f6 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/tablet-start.png differ diff --git a/docs/reviews/evidence/midnight-expressway/world-desktop.png b/docs/reviews/evidence/midnight-expressway/world-desktop.png new file mode 100644 index 0000000..ad98627 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/world-desktop.png differ diff --git a/docs/reviews/evidence/midnight-expressway/world-phone.png b/docs/reviews/evidence/midnight-expressway/world-phone.png new file mode 100644 index 0000000..0779685 Binary files /dev/null and b/docs/reviews/evidence/midnight-expressway/world-phone.png differ diff --git a/docs/reviews/midnight-expressway-direction.md b/docs/reviews/midnight-expressway-direction.md new file mode 100644 index 0000000..47e88ef --- /dev/null +++ b/docs/reviews/midnight-expressway-direction.md @@ -0,0 +1,25 @@ +# Midnight expressway + +Base: local main c9ac36e. Branch: codex/midnight-expressway. All public wording, metadata, media, privacy decisions, section order, canonical journey state and audio are immutable. + +## Creative direction + +A silver coachbuilt wedge travelling a graphite causeway through cyan topographic waves toward a burning coral horizon. Architecture uses swept graphite uprights, machined silver edges, recessed cyan glass, and narrow coral indicators. The road has satin moisture, not a perfect mirror: directional broken reflections sit on its surface. Only finite objects are authored in Blender; the road and landscape remain continuous runtime geometry. + +Design read: a personal professional portfolio for technical hiring and collaboration, with expressive synthwave cinematography and stable, spacious reading surfaces. Native Vue/CSS/Three.js; no new dependencies. Variance 9, motion 8 during travel / 3 during reading, content density 4. + +## Scene ledger + +Start: low rear three-quarter coachwork, sun and expressway to the right of the open name. Profile: left world corridor and right reading plate. Experience: right world corridor; roadside fins frame the timeline. Infrastructure: taller architectural pylons and precise road sequencing. Selected builds: broad evidence stages with panoramic gaps. Additional work: quieter mid-distance rhythm. Toolkit: ordered vertical structures. Contact: low, warm, slower-feeling arrival and silver bodywork. + +Signs retain the approved route labels, semantic destinations and lifecycle. Replace brittle world-coordinate offsets with camera-aware projection into measured empty document corridors; retain physical depth, mounting and a real approach/departure. Housing catches light before the text face; label remains still in its dwell. At compact sizes reserve a scene strip below navigation by clipping the reading document there, using matching section scroll margins. Signs remain behind content, never on a higher stacking layer. + +## Materials and motion + +Road: charcoal aggregate, subtle wheel polishing, paired center markings, recessed cyan edge channels, shoulder ribs, reflectors, expansion joints, broken coral tail-light and sun response. No planar reflection pass. Landscape: dark opaque underlay beneath the cyan wave grid, layered silhouettes and sparse paired landmarks. Sun: variable-width separated bands, peach crown, coral body, vermilion lower limb, subtle refraction and fine chromosphere arc. Car: deeper aero channels, articulated rear lamps, side intakes, diffuser, machined wheels, edited materials. All new resources owned by the existing disposal bag; repeated details instanced and bounded. + +Render-only motion uses current journey energy; camera, road, car, sign and lighting updates never write back to audio or journey. Native scrolling, quality controls, Static and reduced-motion remain. + +## Practical verification + +Capture baseline before editing; run the established complete content validation and prerender flow. The untouched baseline unit suite currently has 9 failures (653 passed), in scene fallback expectations and old camera/sign/bloom assertions. Preserve tests per request and record this pre-existing result. Continue required client/SSR/prerender/artifact/transfer validation separately. Inspect all eight chapters at desktop, tablet, phone, narrow and short sizes; scroll, reversal, jumps, keyboard, resize, fallback and console. Identify the GPU, capture actual motion, make a second visual pass, preserve editable isolated Blender source, compare content and media hashes, then commit without merge/push/deploy. diff --git a/docs/reviews/midnight-expressway-review.md b/docs/reviews/midnight-expressway-review.md new file mode 100644 index 0000000..6f9bd72 --- /dev/null +++ b/docs/reviews/midnight-expressway-review.md @@ -0,0 +1,56 @@ +# Midnight expressway — ready for visual review + +Implementation branch: `codex/midnight-expressway`, based on local main `c9ac36e`. Worktree: `/home/luca/Documents/Portfolio/.worktrees/midnight-expressway`. No merge, push, or deployment. + +## Open the work + +- [Live validated preview](http://localhost:41821) +- [Before/after gallery and motion](http://localhost:41822) +- [Motion recording](evidence/midnight-expressway/journey-motion.mp4) +- [Editable Blender source](../../assets/blender/expressway/nightdrive-expressway.blend) +- [Blender provenance and export instructions](../../assets/blender/expressway/README.md) + +The gallery is also available locally as `evidence/midnight-expressway/index.html`. Preview serves this worktree's validated, prerendered `dist`; the baseline was separately built from the merged version and serves on port 41820. The previous port 41812 was not running. + +## What changed + +A satin graphite expressway now has directional grain, broken coral reflections, cyan recessed channels, shoulder ribs, reflectors, expansion joints, low rails, and swept signal pylons. Sparse ridge observatories create a slower outer rhythm. All repeated scenery uses bounded instancing and continuous wrap; no additional reflection pass is required. + +The cyan terrain waves now sit on opaque displaced ground. Dark surfaces occlude distant contours and give the landscape actual depth. Thin, separated atmospheric layers replace full-screen haze. The striped sun has a peach crown, a coral lower limb, luminous band edges, convection filaments, and restrained distortion. Stars sit behind its solid surface. + +The car has twin articulated rear lamp rails, deep side intakes, machined dished wheels, shoulder rings, lower blades, deck seams, larger wing endplates, exhaust surrounds, and a more defined diffuser. Four wheels rotate independently while suspension acts on the body. The isolated Blender source remains editable. + +Signs are beveled illuminated objects with fins, inset faces, twin supports, footings, hardware, and an approach sweep. Camera projection places readable dwell in measured empty screen space. A reserved scene strip protects that space without placing the signs above the content. Very short landscape layouts put reading on the left and the sign on the right. Reflow is damped, keyboard focus stays in the reading corridor, and Static mode releases the clipping entirely. + +Camera lag, forward anticipation, coasting, and warm Contact recovery are visual consumers of existing journey state. Typography, project staging, diagram sizing, and compact reading surfaces were refined around the unchanged copy. + +## Refinement after the first implementation + +Browser observation led to a second pass: removal of flat full-screen haze and distracting old anchors; opaque ground beneath the grid; a crisper sun limb with correct star occlusion; closer sign dwell to prevent foreground pylons crossing labels; corrected short-height composition; stable heading activation after navigation; and independent wheel rotation with grounded contact. Static posters were captured from the live world. + +## Preservation + +The baseline and new preview have identical normalized main text, rendered wording, links, title, metadata, canonical information, structured metadata, and ordered section IDs. The 15 approved media/audio files match the approved manifest and both built previews byte for byte. Content, audio, canonical journey state, motion preferences, route definitions, tests, and preview configuration have no source changes. + +Evidence: [content comparison](evidence/midnight-expressway/content-preservation.json), [all approved media/audio hashes](evidence/midnight-expressway/media-audio-preservation.json). + +The soundtrack reached its running state through the existing controls. Mute/unmute, volume, motion pause/resume, and quality controls were exercised. The capture is silent; it does not replace the soundtrack assets or certify acoustic playback through physical speakers. + +## Practical verification + +- Approved-asset validation, typecheck, client build, SSR build, validated prerender, artifact verification, and transfer checks pass. Validation was not disabled. +- All eight chapters were traversed at 1440×900, 768×1024, 390×844, 320×568, 1024×600, and 844×390. Intermediate resizing also included 900×760. No horizontal page overflow was observed; narrow and short navigation settled on every requested section. +- Ordinary scrolling, acceleration, coasting, reverse scrolling, long navigation jumps, Contact arrival, keyboard skip link, successive media/link focus, and resizing were exercised. The motion recording shows the road, sign transitions, reversal, Builds, and Contact. +- Static mode: zero canvas, no live clipping. Reduced motion: static artwork and all eight sections. JavaScript disabled: all eight sections and the approved content remain available. +- Direct-preview console inspection found no application exceptions or WebGL shader errors. An inherited `/favicon.ico` 404 remains. The instrumentation proxy emitted its own WebGL warning. +- Static → High → Low transitions were exercised. Scene disposal inspection found zero orphaned geometries or textures. Repeated roadside objects are bounded; the final Low scene has 45 draw calls and approximately 44,572 triangles while the sign is inactive. No new full-resolution post-processing pass was added. + +## Performance and limits + +The initial inspection renderer was **ANGLE / Vulkan / SwiftShader Device (Subzero)**. At Low quality the instrumented 1440×900 sample averaged 12 fps (4 seconds, p95 99.9 ms); 390×844 averaged 31.1 fps (3 seconds, p95 49.9 ms). The Chrome app connector returned `Transport closed`, including its reset call. A direct isolated host Chrome window provided the working hardware-backed alternative. + +**Host Chrome 152.0.7977.64 uses ANGLE / Mesa Intel Graphics (ARL), OpenGL ES 3.2.** With the High maximum-quality preference and normal adaptive behavior intact, six-second requestAnimationFrame samples averaged 63.1 fps at the opening, 62.7 fps while reading Infrastructure, and 65.4 fps during native scrolling/coasting at 1440×900. Desktop p95 was 20.9 ms. The 390×844 host-browser viewport averaged 188.7 fps (p95 8.4 ms). These samples use the host GPU at devicePixelRatio 1; they do not certify a physical phone, high-DPI screen, or every browser. No application exceptions occurred. [Raw hardware results](evidence/midnight-expressway/chrome-hardware-performance.json) include the renderer and measurement method. A second motion capture uses this hardware-backed Chrome window. + +Transfer report: initial application JS 90,264 bytes; first live scene code plus car 299,457 bytes; both responsive posters 136,680 bytes, measured by the existing Brotli/raw accounting. No transfer violations. The raw car export is 1,185,588 bytes. Vite retains its large scene-chunk warning. + +The untouched baseline's established `build:preview` stopped at **9 failing / 653 passing unit tests**: fallback counts and old bloom/camera/sign assertions. [The original log](evidence/midnight-expressway/baseline-checks.log) was captured before editing. Tests were not written, changed, or repeatedly run, as requested. The complete validated rendering and artifact stages were run separately and pass; the unit suite is not claimed green. diff --git a/src/assets/hero-expressway-mobile.jpg b/src/assets/hero-expressway-mobile.jpg new file mode 100644 index 0000000..de9569b Binary files /dev/null and b/src/assets/hero-expressway-mobile.jpg differ diff --git a/src/assets/hero-expressway.jpg b/src/assets/hero-expressway.jpg new file mode 100644 index 0000000..1b3686d Binary files /dev/null and b/src/assets/hero-expressway.jpg differ diff --git a/src/assets/nightdrive-grand-tourer-expressway.glb b/src/assets/nightdrive-grand-tourer-expressway.glb new file mode 100644 index 0000000..61088b9 Binary files /dev/null and b/src/assets/nightdrive-grand-tourer-expressway.glb differ diff --git a/src/components/SceneCanvas.vue b/src/components/SceneCanvas.vue index 080ec44..02b3149 100644 --- a/src/components/SceneCanvas.vue +++ b/src/components/SceneCanvas.vue @@ -4,8 +4,8 @@ import { useSceneController, type SceneHostState } from '@/composables/useSceneC import type { JourneySnapshot } from '@/journey/types'; import type { MotionPolicy, QualityTier } from '@/journey/motion-policy'; import { isTestFault, recordTestFaultEvent } from '@/testing/fault-hooks'; -import posterUrl from '@/assets/hero-evolution.jpg'; -import mobilePosterUrl from '@/assets/hero-evolution-mobile.jpg'; +import posterUrl from '@/assets/hero-expressway.jpg'; +import mobilePosterUrl from '@/assets/hero-expressway-mobile.jpg'; declare const __PORTFOLIO_TEST_BUILD__: boolean; const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__; @@ -57,7 +57,7 @@ if (posterFailed.value) recordTestFaultEvent('poster-failure'); > - +