diff --git a/AGENTS.md b/AGENTS.md
index 06b99bb..b647e1f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -24,3 +24,6 @@ Read README.md, docs/PROJECT-CONTEXT.md, docs/REQUEST-HISTORY.md and the latest
- Test Unreal collision in a fully initialized play world; editor startup traces can run before physics is ready. Set complex-as-simple collision, refresh the mesh section and save.
- Bedroom bed is to be built into the wall, rigid and quiet, not a free-standing frame. Recorded in decisions/2026-09-11-bed-wall-integrated.md and still to be modelled.
+
+- Latest working revision is v008 in the PRIVATE archive `/home/marcus/projects-private/samford-valley-home-v008`. It contains the licensed 7K Studio Tesla and daylight Unreal scene. Public binaries remain v007. Never publish embedded Tesla geometry; see the v008 decision.
+- Do not export Blender volume-only haze as an opaque Unreal mesh. The v007 enclosing haze cube blocked sunlight and was removed in v008. Match Unreal imported material slots by name, not index. Use explicit look-at rotations or keyword Rotator arguments; confirm the sun forward vector points down.
diff --git a/README.md b/README.md
index 6cf9b88..fddc378 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,11 @@ Read [Project context](docs/PROJECT-CONTEXT.md), [Request history](docs/REQUEST-
Clone using `git clone ssh://git@git.rehbock.xyz:2222/marcus/samford-valley-home.git`. Current files use ordinary Git; no Git LFS client is needed. The existing Git server has LFS disabled.
-## Open the current work
+## Latest working revision — v008
+
+The 7K Studio Tesla Model 3 and daylight Unreal scene are stored privately at `/home/marcus/projects-private/samford-valley-home-v008` because the car licence restricts redistribution. This public repository retains the distributable v007 binaries and new renders/source/context. See [v008 decision](decisions/2026-09-15-v008-tesla-and-daylight.md).
+
+## Open the public v007 work
- **Blender 5.2.1:** `blender/samford-solarpunk-presentation-tour.blend`. Includes the entire homestead, reading chair and 163 books. Its camera tour has 31 chapters and lasts 2 minutes 35 seconds. Hover over the 3D view and press Space to play; Shift + Left Arrow returns to the start. It opens at the whole-site overview. Earlier bedroom and reading-tour files remain as previous versions.
- **Walkable Unreal Engine 5.8.2:** `unreal/SamfordHomestead/SamfordHomestead.uproject`. Whole-site editor-play prototype, 229 mesh groups and 117 materials. Play, click the viewport, then WASD and mouse; Escape stops. Fresh-launch play testing verified floor collision and movement from the verandah into the house. The earlier meditation-only study is preserved separately.
diff --git a/decisions/2026-09-15-v008-tesla-and-daylight.md b/decisions/2026-09-15-v008-tesla-and-daylight.md
new file mode 100644
index 0000000..d0c992d
--- /dev/null
+++ b/decisions/2026-09-15-v008-tesla-and-daylight.md
@@ -0,0 +1,17 @@
+# Version 008 — licensed Tesla and daylight walkthrough
+
+15 September 2026. Marcus selected the existing Tesla Model 3 by 7K Studio, then asked for more sunlight to walk around in daylight.
+
+The licensed model replaces the handmade Model Y-inspired placeholder in a private Blender revision and the whole-site Unreal prototype. The original artist geometry, interior, wheels and shaders are retained in Blender, with a simplified fast display. All 31 tour chapters match v007. Unreal uses the reduced artist geometry and adapted PBR materials, with slot assignment by imported material name. A simple car collision box blocks walking; eight floor traces and normal entry movement passed.
+
+Unreal daylight uses a higher neutral sun, brighter sky, reduced native fog and adaptive exposure. Inspection found the old Blender haze volume had imported as an opaque enclosing cube, blocking sunlight and the sky. That non-colliding export was removed; Unreal's native atmosphere/fog now handle the environment. The sun also pointed upward because of positional Rotator argument ordering. An explicit look-at rotation now points the sunlight downward from the northeast, at approximately 52.5 degrees elevation; its forward vector was verified. Actual daylight captures were reviewed.
+
+## Licensed storage
+
+Asset: Tesla Model 3 by 7K Studio. https://www.blendkit.com/asset-gallery-detail/1fc56739-2fd9-447e-b2c1-fee5d9e276b7/
+
+Royalty Free licence: https://www.blendkit.com/docs/licenses/licensing-faq/
+
+The original model is free to acquire but its raw geometry must not be publicly redistributed. The complete v008 Blender file, FBX and Unreal project are stored at `/home/marcus/projects-private/samford-valley-home-v008`, outside the public repository and web root, with restricted directory access. The public repository retains the last distributable v007 binaries, source scripts, this context and permitted rendered images. Do not copy the licensed car or an embedded .blend/.uasset into public Git.
+
+The v007 client film remains unchanged. The pending wall-integrated bed requirement remains unmodelled.
diff --git a/docs/PROJECT-CONTEXT.md b/docs/PROJECT-CONTEXT.md
index bcb504a..ca9cbd6 100644
--- a/docs/PROJECT-CONTEXT.md
+++ b/docs/PROJECT-CONTEXT.md
@@ -91,3 +91,7 @@ Marcus requested more overall Blender fidelity, a start on a walkable UE5 simula
## Pending wall-integrated bed requirement
A 11 September 2026 note requests that the bed be rigidly built into wall framing with a considered load path, quiet isolation and Eight Sleep access. This was recorded without a geometry edit in decisions/2026-09-11-bed-wall-integrated.md. The v007 presentation retains the current free-standing bed; incorporate the wall-integrated platform in the next bedroom design revision, with its fixings and load path still subject to engineering.
+
+## Version 008 — Tesla and daylight
+
+Selected the existing 7K Studio Tesla Model 3 and added clear daytime lighting to Unreal. Full licensed revision is stored privately at `/home/marcus/projects-private/samford-valley-home-v008`; public v007 binaries remain available. See `decisions/2026-09-15-v008-tesla-and-daylight.md`. The v007 movie is unchanged.
diff --git a/docs/REQUEST-HISTORY.md b/docs/REQUEST-HISTORY.md
index f28f760..b97f2e8 100644
--- a/docs/REQUEST-HISTORY.md
+++ b/docs/REQUEST-HISTORY.md
@@ -59,3 +59,7 @@ Marcus asked for a note on the Blender bedroom: the bed should be built into the
wall rather than stand as free furniture, so it stays rigid and quiet in use.
Recorded as a requirement in `decisions/2026-09-11-bed-wall-integrated.md`. Not
yet modelled — the scene still shows a free-standing bed.
+
+## Version 008 — Tesla and daylight
+
+Selected the existing 7K Studio Tesla Model 3 and added clear daytime lighting to Unreal. Full licensed revision is stored privately at `/home/marcus/projects-private/samford-valley-home-v008`; public v007 binaries remain available. See `decisions/2026-09-15-v008-tesla-and-daylight.md`. The v007 movie is unchanged.
diff --git a/renders/v008-daylight-overview.png b/renders/v008-daylight-overview.png
new file mode 100644
index 0000000..4245d1a
Binary files /dev/null and b/renders/v008-daylight-overview.png differ
diff --git a/renders/v008-daylight-tesla.png b/renders/v008-daylight-tesla.png
new file mode 100644
index 0000000..ebbf1fa
Binary files /dev/null and b/renders/v008-daylight-tesla.png differ
diff --git a/renders/v008-daylight-verandah.png b/renders/v008-daylight-verandah.png
new file mode 100644
index 0000000..72556a1
Binary files /dev/null and b/renders/v008-daylight-verandah.png differ
diff --git a/renders/v008-tesla-garage.png b/renders/v008-tesla-garage.png
new file mode 100644
index 0000000..1efaf63
Binary files /dev/null and b/renders/v008-tesla-garage.png differ
diff --git a/repository-files-sha256.json b/repository-files-sha256.json
index 70f366b..a76ebb4 100644
--- a/repository-files-sha256.json
+++ b/repository-files-sha256.json
@@ -1,10 +1,10 @@
{
- "milestone": "2026-09-12-v007-presentation-walkthrough",
+ "milestone": "2026-09-15-v008-tesla-and-daylight",
"files": {
".gitattributes": "d4f9cc15aed223cff7a906452370117fc93992272828cb1efbdd94c61422ad19",
".gitignore": "d38c3a1d58416906185c4c7695ea24f9401be3b610fcce0e624f41dff9fe1675",
- "AGENTS.md": "f95132bb06e10888f7948f3277f669cad6353fba87b446a6fb731b6cc423e638",
- "README.md": "903a431234608261cb998f6bff42bfc566462253a5f165bf569e3ee12dc71edd",
+ "AGENTS.md": "79150cb6cc0df63c78bc0ba782f02d49734dba400d71bef56fd867bc7ac6c53b",
+ "README.md": "142f6a77a2261180015717017fc4e677db9cfa88f14667ba76a0d2da9454d0a9",
"blender/bedroom-sleep-checks.json": "4f28426b4c23e55c956a4c5bc94947706da63e35de455cfaedd8e90e330f1114",
"blender/blender-enhancement-checks.json": "f66943121057ec2e3c2fd0b2bb5d9245721e063b56cfef060598081fce3554e0",
"blender/blender-verification.json": "772764db02a6cec6225d01bf8e38c7680087e53f35614ed48212ea57cbec51dc",
@@ -46,8 +46,9 @@
"decisions/2026-09-10-v006-buddha-garden.md": "aa14fcca78e225563b19ed4a98e335b2f465ed27e12904665c3c654de77b950c",
"decisions/2026-09-11-bed-wall-integrated.md": "31eb04842a0a5904d477d7d28f07792f8b0b1737ac5bb3cbdcc2acb2d7f02a22",
"decisions/2026-09-12-v007-presentation-and-walkthrough.md": "6b3aa18b3660730313f5e0f6a9218c0c868b9734c800456d65c62996cbf7a0b0",
- "docs/PROJECT-CONTEXT.md": "c8d69a96c26d3ca1cfe8162982a511542a8b78f6c1c3881fe2f603ab1504c1c1",
- "docs/REQUEST-HISTORY.md": "af1168f209ba93270e9adfd93de1d8a548bcee5db6ee795b89bb627c03fb4aae",
+ "decisions/2026-09-15-v008-tesla-and-daylight.md": "aa5ba8211c49dbe30f5bd205843dec0de6144833907b8739cfa4cea4da0e6a1e",
+ "docs/PROJECT-CONTEXT.md": "adc652086e3ff36b9958167b0a6649a6020e99c089f836f464c7ab8154d65644",
+ "docs/REQUEST-HISTORY.md": "0c567e6ce5407e0a3a617d221756457a45645b446a75365d94f66a396d63d465",
"plans/architectural/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"plans/concept/buddha-garden-plan.svg": "62f622647732bf9556e7d351c06c9dc8576f68e8e0044f91232401972e43e466",
"plans/concept/container-water-plan.svg": "5cf52ea84ae8e222f64881b46807ca869728845c9e1a5b5c80ecfdbfbc3d5fe3",
@@ -78,9 +79,14 @@
"renders/training-area.png": "4534ad28d7ccda82bc93f44f5c0b8b358a3f9e549fe4ba141ca94931812678f8",
"renders/unreal-overview.png": "c01aa10e711c55773b0e087191f6b8857f575f51843e3ebffdf9c7eddd857aca",
"renders/unreal-verandah.png": "d04cd18d2a564e7fd0bc7a9539ffaa590a9e836e6322ba03951eaf0c01e70276",
+ "renders/v008-daylight-overview.png": "f19f22b21b1227dce3d19b0385b00af757ebc3ca30196dc8f044188f27d39143",
+ "renders/v008-daylight-tesla.png": "1113d76c2f7edbb98b582f5ee07afad876a40a5810134ec99231233038d46e4c",
+ "renders/v008-daylight-verandah.png": "8909c2603b0f98c62fc0c4f5d4632172eebdf939819b806f095b557ef870244e",
+ "renders/v008-tesla-garage.png": "1e706ab3873ba0369d507f89f690e9185b10622cba95a6022b9a989d6b0b0eba",
"site/lidar/processed/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"site/lidar/raw/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"site/photos/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "site/samford-valley-home/index.html": "30d72377b5803e7687dad9ed11000536ac61c477fe48ed0494ed1aefa6dc26bc",
"site/surveys/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"source/samford-modular/README.md": "e4dd2ed10b0e4f33ddfae86e753cc572d7872bce67ba9aecf66557befc05324d",
"source/samford-modular/build_scene.py": "0bce8490a7f078880c0902b464e9f0202e30f2b44673a7b5378d248850264aa9",
@@ -147,6 +153,19 @@
"source/samford-v007-client-walkthrough/source/refine_film_bedroom.py": "ea6bae1e216a12f0bb7c201fb5bfdc6b39b4eda6045beb2f305c9538d8a18084",
"source/samford-v007-client-walkthrough/source/render_film.py": "77ce49f28c2a47968e00b8c86bae5704d2c683361c2a3689e1cc9da1b8e75f0f",
"source/samford-v007-client-walkthrough/source/verify_blender.py": "7ac14703e84eb6c885d930b9971bd96058de3fe83e4b7c3428cb466bc9231ff6",
+ "source/samford-v008-tesla/asset-source.json": "1582cdeb9c32b57545020a76def5046257f1ab7c6e4b8cc1ecff72353cadb79c",
+ "source/samford-v008-tesla/blender-final-verification.json": "2c6c73634c367d29181085dd81ca355accf680da9a3e4de71a4e41675ee28686",
+ "source/samford-v008-tesla/export_tesla.py": "42f8f7313263cadad2fdb5d2b8f8cf20a3ad969fcb48399f43b99ed09607a049",
+ "source/samford-v008-tesla/finalize_blender.py": "9d5b1e7bfe0dd9a5576be16be5347545a9bdd7d8185e79c8602dfb9917bffbca",
+ "source/samford-v008-tesla/replace_tesla.py": "d9764fddd296175c47d60a47849874e3e60c6d541b5ae2a78dcd0e7bb7227cca",
+ "source/samford-v008-tesla/unreal-daylight-checks.json": "d28e1a42bf4b78d91164e510cab7cba39b5701127a3bf974a281b9f8be3abe32",
+ "source/samford-v008-tesla/unreal-daylight.py": "f599fa542a520a2991d5a1bd2ccc1e53f7602205207ce58efc010a7fa4890dcb",
+ "source/samford-v008-tesla/unreal-fix_sun_direction.py": "2c9def0ab36406dab5eaa49604887e88447d67eebd5dcecabe0e4bc3f856afeb",
+ "source/samford-v008-tesla/unreal-remove_opaque_haze.py": "e9e4edd5c9a0098017e3e86bf3d5e412b329f53d4f7c77f64631b88ca8b091aa",
+ "source/samford-v008-tesla/unreal-replace_tesla.py": "64563ec67680f065b6ee6f22ea2767a619dc536a2454394daa0ed42894e37cc1",
+ "source/samford-v008-tesla/unreal-verify_walkthrough.py": "ed426cee0c14a00064ca4d79b0fbc80383f119ada2694ae916949b8bb16d3c0e",
+ "source/samford-v008-tesla/unreal-walkthrough-verification.json": "4d883f97fd86e2caa9cc5537bde0f74993fbe61cb099ec6f1f9b274413a4f27c",
+ "source/samford-v008-tesla/verify_saved_blender.py": "ff7b26b54c04b82b773b0b60d192d08717bcf2af393b3d2c4f423c2b07b76384",
"unreal/MeditationRoom.fbx": "7540b71e6cf075e51748db7dc829cf7330c1bfa8cfd8c713041f2127f17ceceb",
"unreal/MeditationRoom.glb": "529770faf5d746f74cc33ccaa84bc1315b1dced2a2e6d14209add716983a9fb6",
"unreal/SamfordHomestead/Config/DefaultEngine.ini": "3448b132adc8ac3f9690fec0a0895d7f3f6d0b1463bf65c81b0d4c822f4c9000",
diff --git a/site/samford-valley-home/index.html b/site/samford-valley-home/index.html
new file mode 100644
index 0000000..44ec827
--- /dev/null
+++ b/site/samford-valley-home/index.html
@@ -0,0 +1,113 @@
+
+
+Samford Valley home — Marcus Rehbock
+
+
+
+
+
+
+
+
+
+
+
+
Started September 2026 · Concept design · A project for the coming years
+
A home that can grow.
A simple family homestead in Samford Valley, Queensland. Warm timber, soft clay walls, solar power, food gardens and room to change my mind.
+
I want to spend the next few years getting this house right. Inspired by Derek Sivers’ article Building without predicting, the starting point is a few straightforward spaces, with future additions left visible as outlines. The house should adapt to life as it unfolds.
+
“All buildings are predictions. All predictions are wrong.”— Stewart Brand
+
The current model brings together a central kitchen, dining and living space, an adjacent parents’ bedroom, a quiet meditation room, an outdoor sauna and shower, and a garage with a workbench and bike storage. Container-enclosed rainwater storage, solar panels, a greenhouse and garden beds are part of the homesteading idea.
+Garden-centred revision: aligned pavilions, an oval shared garden, curved covered walkway and flowering beds. Future pavilions remain outlines; the table-tennis deck has been removed.
+A 30-second concept film: open living, natural materials, shared meals and room to grow. Download the MP4.
+Version 007 adds woven pendants, softer construction edges, natural-finish variation, table settings and fuller garden planting.
+The whole homestead is now an editable first-person Unreal prototype. Walking and floor collision have been tested; the project is in the public repository. The video above is rendered in Blender.
+A quiet garden Buddha beside the meditation room, facing the shared garden court. Weathered stone, a low plinth and a new close-up stop in the Blender tour.
+A 20-foot container-style rainwater module replaces the exposed cylinders. Two separate sealed tanks sit inside the steel enclosure; a cutaway end allows inspection in the Blender model.
+The garden gives the separate pavilions a shared centre. A north–south axis, paired planting and gently curving connections bring the composition together.
+Kitchen refinement: a marble-topped timber island, oven, four-zone induction cooktop, detailed drawers, copper cookware and a recessed sink.
+A ten-place outdoor table with timber benches and end chairs, pergola shade and a nearby tea and matcha preparation counter.
+Covered training beside the garage: a dedicated pull-up and wooden-rings frame, adjustable dumbbells and bench, movable mats and timber access steps.
+Reading-corner study: a timber library filled with books, a linen reading chair and a small side table.
+The first actual Unreal Engine 5.8.2 render: clay walls, timber, a meditation cushion and candles.
+The garage study: a Tesla, workshop bench, bicycle storage and rooftop solar.
+Bedroom revision: an Eight Sleep-style cover and cooling hub, lined blackout curtains and split-system air conditioning. The outdoor condenser sits behind the bedroom wing.
+
Space for everyday life
The plan brings together a covered place to train, an outdoor table for ten, a shared oval garden and gently curving walks ending at a quiet bench. The former table-tennis deck has become a flowering garden. A clear breakfast counter, pantry and freezer storage, and a garden harvest bench make everyday food preparation easier.
A separate 10 × 10 metre area is reserved for basketball later. It is shown as a dashed outline on the plan; the court surface and hoop have not been built into the concept. The future dwelling spaces also remain outlines.
The Blender inspection tour has 31 chapters and lasts 2 minutes 35 seconds, with updated views of the garden layout, future pavilions and kitchen.
+
Where the project goes next
+
The Blender house is the working concept, now accompanied by a short presentation film and a walkable whole-site Unreal prototype. The next step is to refine that prototype for a smooth, packaged client experience.
+
Keep refining the house. Test room proportions, circulation, materials, storage and where future buildings belong.
Bring in the real site. Add boundary and contour surveys, site photographs and LiDAR when a property is available.
Develop coordinated plans. Bring architectural, structural and services models together with the landscape and access design.
Develop the Unreal experience. Refine materials and performance, add interactions and camera tours, then package and test the walkthrough for clients.
Record the build. Keep dated decisions, construction photographs and revised models as the house becomes real.
These images are early design studies. The terrain is illustrative; surveyed land, LiDAR and construction drawings have not been added yet.
+
Tesla and a daylight walkthrough
15 September 2026 — The garage now uses an existing Tesla Model 3 by 7K Studio. The Unreal walkthrough has clear daytime lighting. The licensed scene is stored privately; the public repository retains the earlier distributable model. The film above remains version 007.
The imported artist model in Blender, with the existing workshop and bikes.Actual Unreal Engine daylight scene. Walking and Tesla collision have been tested.
Project journal
12 September 2026 — Presentation and walking prototype. Refined the Blender scene, created a short client concept film and imported the full site into Unreal Engine with a walking character, collision and lighting. This is an evolving design study; the Unreal project is not yet a packaged client application.
10 September 2026 — Garden Buddha. Added a seated stone Buddha beside the meditation pavilion and a 31st tour chapter. The updated Blender model, plan, render and design context are saved in the public project repository.
10 September 2026 — Container water storage. Replaced the exposed water tanks with a dark-green container-style enclosure, updated the service path and tour, and added exterior and cutaway renders. The project repository is now public, including Blender models, design context and revision history.
10 September 2026 — A home held together by its garden. Removed the table-tennis deck, aligned the pavilions and added an oval garden court, curved covered breezeway, smooth paths and thirteen flowering beds. Updated the camera tour and saved the design history, Blender models and supporting files in a private Git repository.
10 September 2026 — Movement, meals and a detailed kitchen. Added the training area, ten-place outdoor table and tea counter, table tennis, a future basketball reserve, garden walking loop, quiet bench and convenient food storage. Refined the kitchen with an oven, induction, copper cookware and a marble island. Updated the site plan and saved the 30-chapter Blender tour as milestone v003.
10 September 2026 — Bedroom comfort. Added an Eight Sleep-style bed-cooling system, blackout curtains and air conditioning. The updated Blender tour opens in the bedroom; the curtains have a saved closed position for night-time studies.
10 September 2026 — First saved milestone. Full Blender homestead and two-minute camera tour; a reading corner with 163 books; a solar-powered garage study; and the first actual Unreal Engine meditation-room render. Working files and a dated snapshot are stored on my server.
+
+
+
\ No newline at end of file
diff --git a/source/samford-v008-tesla/asset-source.json b/source/samford-v008-tesla/asset-source.json
new file mode 100644
index 0000000..dcf7b8f
--- /dev/null
+++ b/source/samford-v008-tesla/asset-source.json
@@ -0,0 +1,8 @@
+{
+ "scene_uuid": "b061a256-d972-4ed3-a632-2d4314aa2e99",
+ "assetBaseId": "1fc56739-2fd9-447e-b2c1-fee5d9e276b7",
+ "assetId": "e829e99d-fbf3-4d9a-96cf-c62495f35e78",
+ "author": "7K Studio",
+ "license": "royalty_free",
+ "source": "https://www.blendkit.com/asset-gallery-detail/1fc56739-2fd9-447e-b2c1-fee5d9e276b7/"
+}
\ No newline at end of file
diff --git a/source/samford-v008-tesla/blender-final-verification.json b/source/samford-v008-tesla/blender-final-verification.json
new file mode 100644
index 0000000..b6a881d
--- /dev/null
+++ b/source/samford-v008-tesla/blender-final-verification.json
@@ -0,0 +1,18 @@
+{
+ "artist_objects": 45,
+ "no_old_tesla": true,
+ "bicycles_and_racks": 86,
+ "tour_chapters": 31,
+ "packed_asset_images": true,
+ "features": {
+ "ISLAND - honed marble countertop": true,
+ "FAST | Garden Buddha": true,
+ "CONTAINER WATER - steel base frame": true,
+ "Tesla wall connector": true,
+ "GARAGE WORKSTATION": true
+ },
+ "licensed_asset_id": "1fc56739-2fd9-447e-b2c1-fee5d9e276b7",
+ "status": "PASS",
+ "tour_matches_v007_exactly": true,
+ "saved_file_reopened": true
+}
\ No newline at end of file
diff --git a/source/samford-v008-tesla/export_tesla.py b/source/samford-v008-tesla/export_tesla.py
new file mode 100644
index 0000000..b698113
--- /dev/null
+++ b/source/samford-v008-tesla/export_tesla.py
@@ -0,0 +1,40 @@
+import bpy,json,re
+from pathlib import Path
+from mathutils import Vector
+P=Path(__file__).resolve().parents[1];out=P/'private-assets/transfer';out.mkdir(exist_ok=True)
+scene=bpy.context.scene;fast=bpy.data.collections['00 FAST TOUR - lightweight viewport'];fast.hide_viewport=False;bpy.data.collections['DETAIL - full geometry for renders'].hide_viewport=False;bpy.context.view_layer.update()
+# Keep existing charging lead endpoint and corresponding plug together.
+bpy.data.objects['Tesla plugged charge connector'].location=(-2.67,-21.08,1.56)
+# Source file is saved with the static display and all existing tour chapters.
+bpy.data.collections['DETAIL - full geometry for renders'].hide_viewport=True
+bpy.ops.wm.save_as_mainfile(filepath=str(P/'samford-solarpunk-tesla-v008.blend'))
+objects=[bpy.data.objects['FAST | 38 Licensed Tesla Model 3'],bpy.data.objects['FAST | 29 Bicycles and racks']]
+# Transfer original mesh, source UVs and material slots. Adapt legacy Blender shaders to UE PBR.
+used=list(dict.fromkeys(m for o in objects for m in o.data.materials if m));mats={}
+for i,m in enumerate(used):
+ n=m.name.lower();base=(.055,.055,.055,1);rough=.45;metal=0;opacity=1;coat=0
+ if 'car paint' in n:base=(.009,.012,.016,1);rough=.16;metal=.35;coat=1
+ elif 'glass' in n:base=(.035,.07,.07,1);rough=.065;opacity=.28 if 'dark' not in n else .65
+ elif any(s in n for s in ['steel','metal','mirror','reflection']):base=(.36,.38,.4,1);rough=.23;metal=1
+ elif 'wood' in n:base=(.36,.19,.08,1);rough=.48
+ elif 'red' in n:base=(.45,.008,.01,1);rough=.18
+ elif 'blinker' in n:base=(.8,.22,.012,1);rough=.18
+ elif any(s in n for s in ['led.front','led.bright','normal lamp']):base=(.85,.85,.82,1);rough=.14
+ elif 'tire' in n or 'rubber' in n:base=(.015,.018,.018,1);rough=.75
+ elif 'bright' in n:base=(.58,.59,.6,1);rough=.5
+ # Preserve original house bicycle colours using their Principled inputs.
+ if not any(m in bpy.data.objects['FAST | 38 Licensed Tesla Model 3'].data.materials[:] for _ in [0]):
+ bs=next((x for x in m.node_tree.nodes if x.type=='BSDF_PRINCIPLED'),None) if m.use_nodes else None
+ if bs:base=tuple(bs.inputs['Base Color'].default_value);rough=bs.inputs['Roughness'].default_value;metal=bs.inputs['Metallic'].default_value
+ key='M_Tesla_%02d_'%i+re.sub('[^a-zA-Z0-9_]','_',m.name)
+ mats[key]={'source':m.name,'base_color':base,'roughness':rough,'metallic':metal,'opacity':opacity,'coat':coat}
+ m.name=key;m.diffuse_color=base
+records=[]
+for name,o in zip(['Tesla_7K','Bicycles_preserved'],objects):
+ o.name=name;records.append({'name':name,'materials':[m.name for m in o.data.materials]})
+bpy.ops.object.select_all(action='DESELECT')
+for o in objects:o.select_set(True)
+bpy.context.view_layer.objects.active=objects[0]
+bpy.ops.export_scene.fbx(filepath=str(out/'TeslaGarage.fbx'),use_selection=True,object_types={'MESH'},use_mesh_modifiers=True,bake_anim=False,axis_forward='-Y',axis_up='Z',path_mode='AUTO')
+(out/'manifest.json').write_text(json.dumps({'materials':mats,'objects':records,'original_asset':'7K Studio Tesla Model 3','note':'Artist geometry and UVs; legacy shaders adapted to UE PBR.'},indent=2))
+print('TESLA_EXPORTED',len(mats),flush=True)
diff --git a/source/samford-v008-tesla/finalize_blender.py b/source/samford-v008-tesla/finalize_blender.py
new file mode 100644
index 0000000..605139c
--- /dev/null
+++ b/source/samford-v008-tesla/finalize_blender.py
@@ -0,0 +1,23 @@
+import bpy,json
+from pathlib import Path
+from mathutils import Vector
+P=Path(__file__).resolve().parents[1];s=bpy.context.scene;detail=bpy.data.collections['DETAIL - full geometry for renders'];fast=bpy.data.collections['00 FAST TOUR - lightweight viewport']
+cam=bpy.data.objects['VIEW - 7K Tesla garage'];cam.location=(-2.8,-12,2.45);cam.rotation_euler=(Vector((-1.2,-19.2,1.45))-cam.location).to_track_quat('-Z','Y').to_euler();cam.data.lens=36
+# Save this close-up as the opening view while retaining the original animated tour camera.
+for screen in bpy.data.screens:
+ for area in screen.areas:
+ if area.type=='VIEW_3D':
+ r=area.spaces.active.region_3d;r.view_perspective='PERSP';r.view_location=Vector((-1.5,-19.1,1.4));r.view_distance=8;r.view_rotation=cam.rotation_euler.to_quaternion()
+s.frame_set(1);bpy.ops.wm.save_as_mainfile(filepath=str(P/'samford-solarpunk-tesla-v008.blend'))
+# Verify unaffected features and artist identity in the final saved file.
+names=[o.name for o in bpy.data.objects];car=bpy.data.collections['38 Licensed - Tesla Model 3 by 7K Studio'];old=bpy.data.collections['29 Car and bicycles'];captions=[o.name for o in bpy.data.objects if o.type=='FONT' and ' / ' in o.name]
+r={'artist_objects':len(car.objects),'no_old_tesla':not any(o.name.lower().startswith('tesla') for o in old.objects),'bicycles_and_racks':len(old.objects),'tour_chapters':len(captions),'packed_asset_images':all(i.packed_file for i in bpy.data.images if i.source=='FILE' and i.users>0),'features':{k:any(k in n for n in names) for k in ['ISLAND - honed marble countertop','FAST | Garden Buddha','CONTAINER WATER - steel base frame','Tesla wall connector','GARAGE WORKSTATION']},'licensed_asset_id':next(o for o in car.objects if o.parent is None)['asset_id']}
+assert r['artist_objects']==45 and r['no_old_tesla'] and r['bicycles_and_racks']==86
+assert all(r['features'].values())
+r['status']='PASS';(P/'blender-final-verification.json').write_text(json.dumps(r,indent=2))
+detail.hide_viewport=False;fast.hide_viewport=True;s.camera=cam
+s.render.engine='CYCLES';s.render.resolution_x=1600;s.render.resolution_y=1000;s.render.resolution_percentage=100;s.cycles.samples=40;s.cycles.use_denoising=True
+prefs=bpy.context.preferences.addons['cycles'].preferences;prefs.compute_device_type='METAL';prefs.get_devices()
+for d in prefs.devices:d.use=d.type=='METAL'
+s.cycles.device='GPU';s.render.image_settings.file_format='PNG';s.render.filepath=str(P/'renders/tesla-garage.png');bpy.ops.render.render(write_still=True)
+print('FINAL_TESLA_VERIFIED',flush=True)
diff --git a/source/samford-v008-tesla/replace_tesla.py b/source/samford-v008-tesla/replace_tesla.py
new file mode 100644
index 0000000..f95e557
--- /dev/null
+++ b/source/samford-v008-tesla/replace_tesla.py
@@ -0,0 +1,72 @@
+import bpy,json,math
+from pathlib import Path
+from mathutils import Matrix,Vector
+P=Path(__file__).resolve().parents[1]
+scene=bpy.context.scene;detail=bpy.data.collections['DETAIL - full geometry for renders'];fast=bpy.data.collections['00 FAST TOUR - lightweight viewport'];detail.hide_viewport=False;fast.hide_viewport=True
+scene.frame_set(1);bpy.context.view_layer.update()
+old=bpy.data.collections['29 Car and bicycles'];removed=[o.name for o in old.objects if o.name.lower().startswith('tesla')]
+for n in removed:bpy.data.objects.remove(bpy.data.objects[n],do_unlink=True)
+oldproxy=bpy.data.objects.get('FAST | 29 Car and bicycles')
+if oldproxy:bpy.data.objects.remove(oldproxy,do_unlink=True)
+with bpy.data.libraries.load(str(P/'private-assets/7K-Studio-Tesla-Model-3.blend'),link=False) as (src,dst):dst.objects=src.objects
+car=bpy.data.collections.new('38 Licensed - Tesla Model 3 by 7K Studio');detail.children.link(car)
+for o in dst.objects:
+ if o:car.objects.link(o);o.name='7K Tesla | '+o.name
+root=next(o for o in car.objects if o.type=='EMPTY' and o.parent is None)
+root.location=(-1.7,-19.1,.631);root['creator']='7K Studio';root['license']='BlenderKit Royalty Free - keep out of public source distribution';root['asset_id']='1fc56739-2fd9-447e-b2c1-fee5d9e276b7'
+bpy.context.view_layer.update()
+# Keep original artist geometry/shaders. Limit only the viewport subdivision cost.
+for o in car.objects:
+ for mod in o.modifiers:
+ if mod.type=='SUBSURF':mod.levels=min(mod.levels,1);mod.render_levels=min(mod.render_levels,2)
+# Static evaluated copy preserves source UVs and materials for fast viewport and export.
+def proxy(collection,name,ratio=1):
+ deps=bpy.context.evaluated_depsgraph_get();copies=[]
+ for o in collection.objects:
+ if o.type not in {'MESH','CURVE','FONT'}:continue
+ ev=o.evaluated_get(deps);me=bpy.data.meshes.new_from_object(ev,depsgraph=deps);ob=bpy.data.objects.new('temporary proxy',me);fast.objects.link(ob);ob.matrix_world=o.matrix_world.copy();copies.append(ob)
+ # Resolve original material datablocks, never keep evaluated IDs.
+ mats=[bpy.data.materials.get(m.name) if m else None for m in me.materials];me.materials.clear()
+ for m in mats:
+ if m:me.materials.append(m)
+ bpy.ops.object.select_all(action='DESELECT')
+ for o in copies:o.select_set(True)
+ bpy.context.view_layer.objects.active=copies[0];bpy.ops.object.join();ob=copies[0];ob.name=name
+ bpy.ops.object.transform_apply(location=True,rotation=True,scale=True)
+ if ratio<1:
+ d=ob.modifiers.new('Viewport simplification','DECIMATE');d.ratio=ratio;bpy.ops.object.modifier_apply(modifier=d.name)
+ return ob
+fast.hide_viewport=False
+bikeproxy=proxy(old,'FAST | 29 Bicycles and racks')
+teslaproxy=proxy(car,'FAST | 38 Licensed Tesla Model 3',.35)
+fast.hide_viewport=True
+# Coil cable on the wall hook instead of leaving a plug floating at the old car.
+for o in list(bpy.data.collections['28 Garage and workbench'].objects):
+ if 'charge' in o.name.lower() or 'cable' in o.name.lower():print('CHARGER',o.name,flush=True)
+plug=bpy.data.objects.get('Tesla plugged charge connector')
+if plug:plug.location=(-3.66,-20.8,1.77)
+# Additional camera does not alter the existing animated 31-stop tour.
+camdata=bpy.data.cameras.new('Tesla garage detail');cam=bpy.data.objects.new('VIEW - 7K Tesla garage',camdata);scene.collection.objects.link(cam);cam.location=(-5.1,-12.1,2.55);target=Vector((-1.0,-19.25,1.40));cam.rotation_euler=(target-cam.location).to_track_quat('-Z','Y').to_euler();camdata.lens=39
+scene['vehicle_asset']='Tesla Model 3 by 7K Studio; BlenderKit asset 1fc56739-2fd9-447e-b2c1-fee5d9e276b7';scene['revision']='v008 licensed Tesla replacement';scene['public_distribution']='Do not publish this .blend or extracted car; use public source without licensed asset.'
+# Record exact source objects for the narrow Unreal replacement.
+pts=[o.matrix_world@Vector(v) for o in car.objects if o.type=='MESH' for v in o.bound_box]
+r={'removed_placeholder_objects':removed,'artist_objects':len(car.objects),'car_bounds':[[min(v[k] for v in pts),max(v[k] for v in pts)] for k in range(3)],'car_length':max(v.y for v in pts)-min(v.y for v in pts),'fast_car_polygons':len(teslaproxy.data.polygons),'bicycles_preserved':len(old.objects),'source_asset':'1fc56739-2fd9-447e-b2c1-fee5d9e276b7'}
+(P/'blender-replacement-checks.json').write_text(json.dumps(r,indent=2))
+assert 4.510
+bpy.ops.file.pack_all()
+# Save user-ready file with fast display and the original tour camera active.
+fast.hide_viewport=False;detail.hide_viewport=True
+bpy.ops.wm.save_as_mainfile(filepath=str(P/'samford-solarpunk-tesla-v008.blend'))
+# Render full geometry in the dedicated garage camera.
+detail.hide_viewport=False;fast.hide_viewport=True;scene.camera=cam
+scene.render.engine='CYCLES';scene.render.resolution_x=1600;scene.render.resolution_y=1000;scene.render.resolution_percentage=100;scene.cycles.samples=40;scene.cycles.use_denoising=True
+prefs=bpy.context.preferences.addons['cycles'].preferences
+try:
+ prefs.compute_device_type='METAL';prefs.get_devices()
+ for d in prefs.devices:d.use=d.type=='METAL'
+ scene.cycles.device='GPU'
+except Exception:pass
+scene.render.image_settings.file_format='PNG';scene.render.filepath=str(P/'renders/tesla-garage.png');bpy.ops.render.render(write_still=True)
+print('TESLA_REPLACEMENT_READY',flush=True)
diff --git a/source/samford-v008-tesla/unreal-daylight-checks.json b/source/samford-v008-tesla/unreal-daylight-checks.json
new file mode 100644
index 0000000..4d883b4
--- /dev/null
+++ b/source/samford-v008-tesla/unreal-daylight-checks.json
@@ -0,0 +1,107 @@
+{
+ "sun_lux": 65000,
+ "sun_elevation_degrees": 52.465094,
+ "sky_intensity": 3.5,
+ "exposure_EV_range": [
+ 6.5,
+ 16
+ ],
+ "exposure_bias": 0.5,
+ "material_slots_resolved_by_imported_name": [
+ [
+ "TeslaGarage_Bicycles_preserved",
+ 0,
+ "M_Tesla_26_Garage_rubber_and_dark_tools"
+ ],
+ [
+ "TeslaGarage_Bicycles_preserved",
+ 1,
+ "M_Tesla_27_Garage_brushed_aluminium"
+ ],
+ [
+ "TeslaGarage_Bicycles_preserved",
+ 2,
+ "M_Tesla_28_Bicycle_ochre_frame"
+ ],
+ [
+ "TeslaGarage_Bicycles_preserved",
+ 3,
+ "M_Tesla_29_Reusable_dark_steel_bolts_and_shoes"
+ ],
+ [
+ "TeslaGarage_Bicycles_preserved",
+ 4,
+ "M_Tesla_30_Bicycle_blue_green_frame"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 0,
+ "M_Tesla_00_Glass"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 1,
+ "M_Tesla_01_LightAbsorber"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 2,
+ "M_Tesla_02_Tire"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 3,
+ "M_Tesla_03_Plastic_Inventory"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 4,
+ "M_Tesla_04_Steel"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 5,
+ "M_Tesla_06_Plastic_Shiny"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 6,
+ "M_Tesla_08_Car_Paint"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 7,
+ "M_Tesla_10_Plastic_Inventory_Bright"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 8,
+ "M_Tesla_21_Carpet"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 9,
+ "M_Tesla_23_Fabric_Dark"
+ ],
+ [
+ "TeslaGarage_Tesla_7K",
+ 10,
+ "M_Tesla_24_Metal_brake_discs"
+ ]
+ ],
+ "car_collision": "simple box for walking, detail triangles retained for complex traces",
+ "level_saved": true,
+ "removed_opaque_blender_volume": [
+ "SamfordHomestead_SM_056_11_Camera_and_atmosphere"
+ ],
+ "sunlight_obstruction_fixed": true,
+ "sun_forward": [
+ -0.39649116028239617,
+ 0.4625730204439079,
+ -0.7929823204683187
+ ],
+ "sun_rotation": "",
+ "sun_direction_corrected": true,
+ "actual_daylight_verified": true,
+ "visual_verification": "Reviewed fresh Unreal overview, verandah and garage screenshots after correcting the sun direction: directly sunlit terrain and buildings, shaded interiors remain readable."
+}
\ No newline at end of file
diff --git a/source/samford-v008-tesla/unreal-daylight.py b/source/samford-v008-tesla/unreal-daylight.py
new file mode 100644
index 0000000..066eed7
--- /dev/null
+++ b/source/samford-v008-tesla/unreal-daylight.py
@@ -0,0 +1,44 @@
+import unreal as u,time,json,math
+from pathlib import Path
+P=Path(__file__).resolve().parents[3];A=u.get_editor_subsystem(u.EditorActorSubsystem);E=u.get_editor_subsystem(u.LevelEditorSubsystem);L=u.EditorAssetLibrary;S=u.get_editor_subsystem(u.StaticMeshEditorSubsystem);world=u.get_editor_subsystem(u.UnrealEditorSubsystem).get_editor_world();actors=A.get_all_level_actors();u.EditorPythonScripting.set_keep_python_script_alive(True)
+def prop(o,k,v):o.set_editor_property(k,v)
+# Resolve the actual imported slot names; FBX can reorder slots.
+slots=[]
+for path in L.list_assets('/Game/LicensedTesla/Meshes',recursive=True):
+ mesh=L.load_asset(path)
+ if not isinstance(mesh,u.StaticMesh):continue
+ for i,slot in enumerate(mesh.static_materials):
+ key=str(slot.get_editor_property('imported_material_slot_name'))
+ material=L.load_asset('/Game/LicensedTesla/Materials/'+key)
+ assert material,('Missing imported material slot',mesh.get_name(),key)
+ mesh.set_material(i,material);slots.append([mesh.get_name(),i,key])
+ if mesh.get_name().endswith('Tesla_7K'):
+ S.remove_collisions(mesh);S.add_simple_collisions(mesh,u.ScriptCollisionShapeType.BOX);prop(mesh.get_editor_property('body_setup'),'collision_trace_flag',u.CollisionTraceFlag.CTF_USE_SIMPLE_AND_COMPLEX)
+ L.save_loaded_asset(mesh)
+sun=next(a for a in actors if isinstance(a,u.DirectionalLight));sun.set_actor_label('Clear daytime sun');sun.set_actor_rotation(u.MathLibrary.find_look_at_rotation(u.Vector(1200,-1400,2400),u.Vector(0,0,0)),False);sun.light_component.set_intensity(65000);sun.light_component.set_light_color(u.LinearColor(1,.96,.88,1));prop(sun.light_component,'light_source_angle',1.0);prop(sun.light_component,'indirect_lighting_intensity',2.5)
+for a in actors:
+ if isinstance(a,u.SkyLight):
+ a.light_component.set_intensity(3.5);prop(a.light_component,'real_time_capture',True)
+ if isinstance(a,u.ExponentialHeightFog):prop(a.component,'fog_density',.001)
+ if isinstance(a,u.PostProcessVolume):
+ p=a.settings
+ for k,v in dict(override_auto_exposure_min_brightness=True,override_auto_exposure_max_brightness=True,auto_exposure_min_brightness=5.5,auto_exposure_max_brightness=11.0,override_auto_exposure_bias=True,auto_exposure_bias=1.2,override_auto_exposure_speed_up=True,auto_exposure_speed_up=3.0,override_auto_exposure_speed_down=True,auto_exposure_speed_down=2.0,override_lumen_scene_lighting_quality=True,lumen_scene_lighting_quality=2.0,override_lumen_final_gather_quality=True,lumen_final_gather_quality=2.0).items():prop(p,k,v)
+ prop(a,'settings',p)
+ if isinstance(a,u.RectLight):
+ a.light_component.set_light_color(u.LinearColor(1,.97,.91,1))
+ if a.get_actor_label()=='Garage presentation fill':a.light_component.set_intensity(9000)
+ elif 'verandah bounce' in a.get_actor_label():a.light_component.set_intensity(6000)
+E.save_current_level();L.save_directory('/Game/LicensedTesla',only_if_is_dirty=True,recursive=True)
+r={'sun_lux':65000,'sun_elevation_degrees':52,'sky_intensity':3.5,'exposure_EV_range':[5.5,11.0],'exposure_bias':1.2,'material_slots_resolved_by_imported_name':slots,'car_collision':'simple box for walking, detail triangles retained for complex traces','level_saved':True}
+(P/'unreal-daylight-checks.json').write_text(json.dumps(r,indent=2))
+for c in ['r.HighResScreenshotDelay 64','r.AntiAliasingMethod 2','r.TemporalAASamples 64']:u.SystemLibrary.execute_console_command(world,c)
+cams=[next(a for a in actors if a.get_actor_label()==n) for n in ['CAM - Verandah','CAM - Overview','CAM - Licensed Tesla garage']];state={'start':time.monotonic(),'i':0,'task':None}
+def tick(dt):
+ if time.monotonic()-state['start']<30:return
+ if state['task'] is None:
+ u.AutomationLibrary.finish_loading_before_screenshot();cam=cams[state['i']];u.EditorLevelLibrary.set_level_viewport_camera_info(cam.get_actor_location(),cam.get_actor_rotation());state['task']=u.AutomationLibrary.take_high_res_screenshot(1600,1000,str(P/'renders'/('daylight-'+['verandah','overview','tesla'][state['i']]+'.png')),camera=cam,delay=5)
+ elif state['task'].is_task_done():
+ state['i']+=1;state['task']=None
+ if state['i']==3:
+ u.unregister_slate_post_tick_callback(handle);u.log('DAYLIGHT_CAPTURED');u.SystemLibrary.quit_editor()
+handle=u.register_slate_post_tick_callback(tick)
diff --git a/source/samford-v008-tesla/unreal-fix_sun_direction.py b/source/samford-v008-tesla/unreal-fix_sun_direction.py
new file mode 100644
index 0000000..e04e771
--- /dev/null
+++ b/source/samford-v008-tesla/unreal-fix_sun_direction.py
@@ -0,0 +1,24 @@
+import unreal as u,time,json
+from pathlib import Path
+P=Path(__file__).resolve().parents[3];A=u.get_editor_subsystem(u.EditorActorSubsystem);E=u.get_editor_subsystem(u.LevelEditorSubsystem);world=u.get_editor_subsystem(u.UnrealEditorSubsystem).get_editor_world();u.EditorPythonScripting.set_keep_python_script_alive(True)
+actors=A.get_all_level_actors()
+sun=next(a for a in actors if isinstance(a,u.DirectionalLight))
+sun.set_actor_rotation(u.MathLibrary.find_look_at_rotation(u.Vector(1200,-1400,2400),u.Vector(0,0,0)),False)
+sun.set_actor_scale3d(u.Vector(1,1,1))
+direction=sun.get_actor_forward_vector()
+assert direction.z < -.5,str(direction)
+sun.light_component.set_intensity(65000)
+E.save_current_level()
+f=P/'unreal-daylight-checks.json';r=json.loads(f.read_text());r['sun_forward']=[direction.x,direction.y,direction.z];r['sun_rotation']=str(sun.get_actor_rotation());r['sun_direction_corrected']=True;r['sun_elevation_degrees']=52.46;f.write_text(json.dumps(r,indent=2))
+for c in ['r.HighResScreenshotDelay 64','r.AntiAliasingMethod 2','r.TemporalAASamples 64']:u.SystemLibrary.execute_console_command(world,c)
+actors=A.get_all_level_actors()
+cams=[next(a for a in actors if a.get_actor_label()==n) for n in ['CAM - Overview','CAM - Verandah','CAM - Licensed Tesla garage']];state={'start':time.monotonic(),'i':0,'task':None}
+def tick(dt):
+ if time.monotonic()-state['start']<25:return
+ if state['task'] is None:
+ u.AutomationLibrary.finish_loading_before_screenshot();cam=cams[state['i']];u.EditorLevelLibrary.set_level_viewport_camera_info(cam.get_actor_location(),cam.get_actor_rotation());state['task']=u.AutomationLibrary.take_high_res_screenshot(1600,1000,str(P/'renders'/('daylight-'+['overview','verandah','tesla'][state['i']]+'.png')),camera=cam,delay=6)
+ elif state['task'].is_task_done():
+ state['i']+=1;state['task']=None
+ if state['i']==3:
+ u.unregister_slate_post_tick_callback(handle);u.log('CORRECTED_SUN_CAPTURED');u.SystemLibrary.quit_editor()
+handle=u.register_slate_post_tick_callback(tick)
diff --git a/source/samford-v008-tesla/unreal-remove_opaque_haze.py b/source/samford-v008-tesla/unreal-remove_opaque_haze.py
new file mode 100644
index 0000000..ad1cf9d
--- /dev/null
+++ b/source/samford-v008-tesla/unreal-remove_opaque_haze.py
@@ -0,0 +1,24 @@
+import unreal as u,time,json
+from pathlib import Path
+P=Path(__file__).resolve().parents[3];A=u.get_editor_subsystem(u.EditorActorSubsystem);E=u.get_editor_subsystem(u.LevelEditorSubsystem);world=u.get_editor_subsystem(u.UnrealEditorSubsystem).get_editor_world();u.EditorPythonScripting.set_keep_python_script_alive(True)
+actors=A.get_all_level_actors();removed=[]
+for a in actors:
+ if 'SM_056_11_Camera_and_atmosphere' in a.get_actor_label():removed.append(a.get_actor_label());A.destroy_actor(a)
+assert len(removed)<=1,removed
+for a in A.get_all_level_actors():
+ if isinstance(a,u.PostProcessVolume):
+ p=a.settings;p.auto_exposure_min_brightness=6.5;p.auto_exposure_max_brightness=16;p.auto_exposure_bias=.5;a.set_editor_property('settings',p)
+E.save_current_level()
+f=P/'unreal-daylight-checks.json';r=json.loads(f.read_text());r['removed_opaque_blender_volume']=removed or r.get('removed_opaque_blender_volume',[]);r['exposure_EV_range']=[6.5,16];r['exposure_bias']=.5;r['sunlight_obstruction_fixed']=True;f.write_text(json.dumps(r,indent=2))
+for c in ['r.HighResScreenshotDelay 64','r.AntiAliasingMethod 2','r.TemporalAASamples 64']:u.SystemLibrary.execute_console_command(world,c)
+actors=A.get_all_level_actors()
+cams=[next(a for a in actors if a.get_actor_label()==n) for n in ['CAM - Overview','CAM - Verandah','CAM - Licensed Tesla garage']];state={'start':time.monotonic(),'i':0,'task':None}
+def tick(dt):
+ if time.monotonic()-state['start']<25:return
+ if state['task'] is None:
+ u.AutomationLibrary.finish_loading_before_screenshot();cam=cams[state['i']];u.EditorLevelLibrary.set_level_viewport_camera_info(cam.get_actor_location(),cam.get_actor_rotation());state['task']=u.AutomationLibrary.take_high_res_screenshot(1600,1000,str(P/'renders'/('daylight-'+['overview','verandah','tesla'][state['i']]+'.png')),camera=cam,delay=6)
+ elif state['task'].is_task_done():
+ state['i']+=1;state['task']=None
+ if state['i']==3:
+ u.unregister_slate_post_tick_callback(handle);u.log('TRUE_DAYLIGHT_CAPTURED');u.SystemLibrary.quit_editor()
+handle=u.register_slate_post_tick_callback(tick)
diff --git a/source/samford-v008-tesla/unreal-replace_tesla.py b/source/samford-v008-tesla/unreal-replace_tesla.py
new file mode 100644
index 0000000..bf04376
--- /dev/null
+++ b/source/samford-v008-tesla/unreal-replace_tesla.py
@@ -0,0 +1,44 @@
+import unreal as u,json,math,time,traceback
+from pathlib import Path
+P=Path(__file__).resolve().parents[3];D=json.loads((P/'private-assets/transfer/manifest.json').read_text());L=u.EditorAssetLibrary;M=u.MaterialEditingLibrary;A=u.get_editor_subsystem(u.EditorActorSubsystem);E=u.get_editor_subsystem(u.LevelEditorSubsystem);T=u.AssetToolsHelpers.get_asset_tools();u.EditorPythonScripting.set_keep_python_script_alive(True)
+def prop(o,k,v):o.set_editor_property(k,v)
+def scalar(m,v,p):
+ n=M.create_material_expression(m,u.MaterialExpressionConstant);prop(n,'r',v);M.connect_material_property(n,'',p)
+materials={}
+for key,r in D['materials'].items():
+ m=L.load_asset('/Game/LicensedTesla/Materials/'+key) or T.create_asset(key,'/Game/LicensedTesla/Materials',u.Material,u.MaterialFactoryNew());M.delete_all_material_expressions(m);prop(m,'two_sided',True)
+ n=M.create_material_expression(m,u.MaterialExpressionConstant3Vector);prop(n,'constant',u.LinearColor(*r['base_color']));M.connect_material_property(n,'',u.MaterialProperty.MP_BASE_COLOR)
+ scalar(m,r['roughness'],u.MaterialProperty.MP_ROUGHNESS);scalar(m,r['metallic'],u.MaterialProperty.MP_METALLIC)
+ if r['opacity']<1:
+ prop(m,'blend_mode',u.BlendMode.BLEND_TRANSLUCENT);scalar(m,r['opacity'],u.MaterialProperty.MP_OPACITY)
+ M.recompile_material(m);L.save_loaded_asset(m);materials[key]=m
+opts=u.FbxImportUI()
+for k,v in dict(import_mesh=True,import_materials=False,import_textures=False,import_as_skeletal=False,import_animations=False,mesh_type_to_import=u.FBXImportType.FBXIT_STATIC_MESH).items():prop(opts,k,v)
+for k,v in dict(combine_meshes=False,auto_generate_collision=False,generate_lightmap_u_vs=False,convert_scene=True,force_front_x_axis=False).items():prop(opts.static_mesh_import_data,k,v)
+t=u.AssetImportTask()
+for k,v in dict(filename=str(P/'private-assets/transfer/TeslaGarage.fbx'),destination_path='/Game/LicensedTesla/Meshes',automated=True,replace_existing=True,save=True,options=opts).items():prop(t,k,v)
+T.import_asset_tasks([t]);meshes=[L.load_asset(p) for p in t.imported_object_paths];meshes=[m for m in meshes if isinstance(m,u.StaticMesh)];assert len(meshes)==2
+before=A.get_all_level_actors();old=[a for a in before if '29_Car_and_bicycles' in a.get_actor_label()];assert len(old)>0,'Original car groups not found'
+for a in old:A.destroy_actor(a)
+for mesh in meshes:
+ rec=next(r for r in D['objects'] if mesh.get_name().endswith(r['name']))
+ for i,key in enumerate(rec['materials']):mesh.set_material(i,materials[key])
+ body=mesh.get_editor_property('body_setup');prop(body,'collision_trace_flag',u.CollisionTraceFlag.CTF_USE_COMPLEX_AS_SIMPLE);prop(body,'double_sided_geometry',True)
+ for i in range(len(rec['materials'])):u.get_editor_subsystem(u.StaticMeshEditorSubsystem).enable_section_collision(mesh,True,0,i)
+ a=A.spawn_actor_from_class(u.StaticMeshActor,u.Vector());a.static_mesh_component.set_static_mesh(mesh);a.static_mesh_component.set_collision_profile_name('BlockAll');a.set_actor_label('LICENSED - '+rec['name']);a.set_folder_path('Licensed Tesla - exclude from public source');L.save_loaded_asset(mesh)
+car=next(m for m in meshes if m.get_name().endswith('Tesla_7K'));bounds=car.get_bounds();assert 2003:
+ u.unregister_slate_post_tick_callback(handle);u.log('HOMESTEAD_WALK_VERIFIED '+json.dumps(report['movement']));u.SystemLibrary.quit_editor()
+ return
+ if elapsed>90:raise RuntimeError('Play-in-editor movement test timed out')
+ if state['phase']=='load':
+ if elapsed<12:return
+ u.AutomationLibrary.finish_loading_before_screenshot();LEVEL.editor_request_begin_play();state['phase']='settle';state['t']=time.monotonic();return
+ game=EDITOR.get_game_world()
+ if not game:return
+ pawn=u.GameplayStatics.get_player_pawn(game,0)
+ if not pawn:return
+ if state['phase']=='settle':
+ if time.monotonic()-state['t']<4:return
+ assert 'HomesteadWalker' in pawn.get_class().get_name(),pawn.get_class().get_name()
+ for name,xy in [('verandah',(0,4)),('living',(-1.8,1)),('corridor',(-7.5,-1.8)),('bedroom',(-10.7,-3.5)),('meditation',(-11.8,10.8)),('garage',(2,-18)),('garden',(0,13)),('training',(-10,-19))]:
+ result=u.SystemLibrary.line_trace_single(game,pos((*xy,2.9)),pos((*xy,-2)),u.TraceTypeQuery.TRACE_TYPE_QUERY1,True,[pawn],u.DrawDebugTrace.NONE,True);assert result is not None,name;report['floor_traces'][name]='hit'
+ p=pawn.get_actor_location();state['initial']=[p.x,p.y,p.z];assert 1702.5:
+ q=pawn.get_actor_location();assert 15702.5:
+ a=state['initial'];dist=math.hypot(p.x-a[0],p.y-a[1]);assert dist>100,('No meaningful movement',dist);assert 170",
+ "controller_possessed": true,
+ "sampled_positions": 59
+ },
+ "tesla_collision": {
+ "walk_stopped_before_car": true,
+ "position_cm": [
+ -170.0,
+ 1651.1851263218496,
+ 154.14999469910472
+ ]
+ },
+ "status": "PASS: Tesla blocks walking, eight floor traces and possessed character walking from verandah into living entry",
+ "verification_scope": "Play-in-editor checks preceded final lighting-only corrections and removal of the non-colliding opaque haze box; fresh final daylight screenshots are recorded separately."
+}
\ No newline at end of file
diff --git a/source/samford-v008-tesla/verify_saved_blender.py b/source/samford-v008-tesla/verify_saved_blender.py
new file mode 100644
index 0000000..ee1fb74
--- /dev/null
+++ b/source/samford-v008-tesla/verify_saved_blender.py
@@ -0,0 +1,9 @@
+import bpy,json
+from pathlib import Path
+P=Path(__file__).resolve().parents[1]
+def snap():
+ c=bpy.data.collections['22 PLAY - guided camera tour'];s=bpy.context.scene
+ return {'captions':{o.name:o.data.body for o in c.objects if o.type=='FONT'},'frame_range':[s.frame_start,s.frame_end],'camera':s.camera.name,'markers':[(m.name,m.frame) for m in s.timeline_markers]}
+bpy.ops.wm.open_mainfile(filepath=str(P/'base/samford-solarpunk-presentation-tour.blend'),use_scripts=False);a=snap()
+bpy.ops.wm.open_mainfile(filepath=str(P/'samford-solarpunk-tesla-v008.blend'),use_scripts=False);b=snap();assert a==b,('Tour changed',a,b)
+p=P/'blender-final-verification.json';r=json.loads(p.read_text());r['tour_chapters']=len(b['captions']);r['tour_matches_v007_exactly']=True;r['saved_file_reopened']=True;p.write_text(json.dumps(r,indent=2));print('SAVED_BLEND_VERIFIED',len(b['captions']))