2 Commits

37 changed files with 6816 additions and 11 deletions

View File

@@ -2,7 +2,7 @@
Read README.md, docs/PROJECT-CONTEXT.md, docs/REQUEST-HISTORY.md and the latest decision record before editing.
- Current model: blender/samford-solarpunk-presentation-tour.blend, version 007.
- Current public model: blender/samford-solarpunk-wind-tour-v009.blend. It derives from distributable v007; earlier binaries remain historical.
- The table-tennis deck was explicitly removed. Do not restore it from older scenes.
- Future child/dwelling pavilions remain ghost outlines. The one built small pavilion is a meditation room.
- Preserve the detailed kitchen, reading library, bedroom sleep setup, sauna, shower, solar, tanks, Starlink, homelab, Tesla garage, training and food-growing features.
@@ -17,10 +17,17 @@ Read README.md, docs/PROJECT-CONTEXT.md, docs/REQUEST-HISTORY.md and the latest
- Current water storage is a container-style enclosure with two sealed internal tanks. Do not restore the old exposed cylinders from earlier scene files.
- Preserve the garden Buddha north of the meditation room and its chapter 31 tour stop. Latest scene is version 007.
- Preserve the garden Buddha north of the meditation room and its chapter 31 tour stop. The Buddha remains in v009.
- v007 has a separate client cinematic and an actual whole-site Unreal walking project at unreal/SamfordHomestead. Do not describe Unreal as meditation-only anymore. Read walkthroughs/CLIENT-PRESENTATION-V007.md.
- Never attach evaluated temporary Blender material IDs to persistent meshes: resolve materials through bpy.data.materials by name. Invalid evaluated references caused a save-time crash during this revision and were fixed.
- 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.
- Historical licensed revision v008 is 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.
- Latest revision is v009. Public Blender is based on v007; private Blender with the licensed Tesla is at `/home/marcus/projects-private/samford-valley-home-v009/`. Never publish that private binary.
- Preserve the wind turbine detailed and FAST copies, provisional (-36,40) concept location, and chapter 32 (32 chapters, 160 seconds). The 18 m hub and 6 m rotor are visual placeholders, not engineered dimensions or a product selection.
- Current plan: plans/concept/wind-turbine-plan-v009.svg. Unreal and the v007 film do not yet contain the turbine. Read the v009 decision before editing.

View File

@@ -10,7 +10,19 @@ 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 revision — v009 wind turbine, 24 September 2026
Added a three-blade wind turbine on a freestanding mast beyond the northwestern edge of the homestead. The concept location (-36, 40) m, 18 m hub height and 6 m rotor diameter are illustrative placeholders pending an actual site, wind measurements, equipment selection, engineering and approvals. Solar and storage remain part of the brief.
Current public Blender file: `blender/samford-solarpunk-wind-tour-v009.blend`, derived from distributable v007. The private v009 Blender file preserves the licensed v008 Tesla at `/home/marcus/projects-private/samford-valley-home-v009/`. Keep private binaries out of public Git. Both models add matching detailed/fast turbine geometry and chapter 32; the tour now lasts 2 min 40 sec and opens at the turbine chapter. Shift + Left Arrow restarts the complete tour.
Current plan: `plans/concept/wind-turbine-plan-v009.svg`. Current overview: `renders/v009-wind-overview.png`. See [v009 decision](decisions/2026-09-24-v009-wind-turbine.md) for assumptions and feasibility work. The Unreal walkthroughs and v007 film are unchanged and do not yet include the turbine. All previous house and landscape features remain, including the future pavilion outlines and garden Buddha.
## Previous 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).
## Preserved 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.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
{
"status": "PASS",
"model": "samford-solarpunk-wind-tour-v009.blend",
"turbine_objects": 20,
"rotor_blades": 3,
"hub_height_m": 18,
"rotor_diameter_m": 6,
"concept_xy": [
-36,
40
],
"tour_chapters": 32,
"tour_seconds": 160,
"captions": [
"01 / ONE CONNECTED GARDEN HOMESTEAD",
"02 / LIVING PAVILION & VERANDA",
"03 / KITCHEN & EXPOSED STRUCTURE",
"04 / DINING & OPEN LIVING",
"05 / ONE SERVER - LOCAL AI",
"06 / SHORT CORRIDOR TO PRIVATE ROOMS",
"07 / ADJACENT BEDROOM WING",
"08 / ENCLOSED BEDROOM",
"09 / BATHROOM - SEPARATE LOBBY DOOR",
"10 / FINNISH SAUNA & OUTDOOR SHOWER",
"11 / SAUNA BENCHES & STONE HEATER",
"12 / OUTDOOR SHOWER",
"13 / CONTAINER RAINWATER STORAGE",
"14 / ROOFTOP SOLAR & STARLINK",
"15 / SOLAR ARRAY & ENERGY STORAGE",
"16 / FOOD GARDEN & GREENHOUSE",
"17 / INSIDE THE GREENHOUSE",
"18 / QUIET MEDITATION ROOM",
"19 / CUSHION, CANDLES & STILLNESS",
"20 / GRAVEL ROAD & GARAGE",
"21 / TESLA, SOLAR CHARGING & WORKSHOP",
"22 / BALANCED FUTURE PAVILIONS",
"23 / RECTANGLES AND GARDEN CURVES",
"24 / BOOKS & A QUIET READING CORNER",
"25 / TRAINING & STRENGTH",
"26 / OUTDOOR TABLE & MATCHA",
"27 / FLOWERING GARDEN - ROOM TO BREATHE",
"28 / FLOWING WALKS AND GARDEN COURT",
"29 / EASY EVERYDAY FOOD",
"30 / COPPER & MARBLE KITCHEN",
"31 / QUIET GARDEN BUDDHA",
"32 / WIND POWER - PROPERTY CONCEPT"
],
"preserved_features": [
"ISLAND - honed marble countertop",
"FAST | Garden Buddha statue",
"CONTAINER WATER - steel base frame",
"Living woven jute rug",
"Fuller garden borders - curved lanceolate leaves"
],
"future_outline_objects": 26,
"material_references_valid": true,
"dimensions_status": "Illustrative placeholders, not engineered"
}

View File

@@ -0,0 +1,194 @@
[
{
"title": "01 / ONE CONNECTED GARDEN HOMESTEAD",
"start": 1,
"end": 120,
"seconds": 5
},
{
"title": "02 / LIVING PAVILION & VERANDA",
"start": 121,
"end": 240,
"seconds": 5
},
{
"title": "03 / KITCHEN & EXPOSED STRUCTURE",
"start": 241,
"end": 360,
"seconds": 5
},
{
"title": "04 / DINING & OPEN LIVING",
"start": 361,
"end": 480,
"seconds": 5
},
{
"title": "05 / ONE SERVER - LOCAL AI",
"start": 481,
"end": 600,
"seconds": 5
},
{
"title": "06 / SHORT CORRIDOR TO PRIVATE ROOMS",
"start": 601,
"end": 720,
"seconds": 5
},
{
"title": "07 / ADJACENT BEDROOM WING",
"start": 721,
"end": 840,
"seconds": 5
},
{
"title": "08 / ENCLOSED BEDROOM",
"start": 841,
"end": 960,
"seconds": 5
},
{
"title": "09 / BATHROOM - SEPARATE LOBBY DOOR",
"start": 961,
"end": 1080,
"seconds": 5
},
{
"title": "10 / FINNISH SAUNA & OUTDOOR SHOWER",
"start": 1081,
"end": 1200,
"seconds": 5
},
{
"title": "11 / SAUNA BENCHES & STONE HEATER",
"start": 1201,
"end": 1320,
"seconds": 5
},
{
"title": "12 / OUTDOOR SHOWER",
"start": 1321,
"end": 1440,
"seconds": 5
},
{
"title": "13 / CONTAINER RAINWATER STORAGE",
"start": 1441,
"end": 1560,
"seconds": 5
},
{
"title": "14 / ROOFTOP SOLAR & STARLINK",
"start": 1561,
"end": 1680,
"seconds": 5
},
{
"title": "15 / SOLAR ARRAY & ENERGY STORAGE",
"start": 1681,
"end": 1800,
"seconds": 5
},
{
"title": "16 / FOOD GARDEN & GREENHOUSE",
"start": 1801,
"end": 1920,
"seconds": 5
},
{
"title": "17 / INSIDE THE GREENHOUSE",
"start": 1921,
"end": 2040,
"seconds": 5
},
{
"title": "18 / QUIET MEDITATION ROOM",
"start": 2041,
"end": 2160,
"seconds": 5
},
{
"title": "19 / CUSHION, CANDLES & STILLNESS",
"start": 2161,
"end": 2280,
"seconds": 5
},
{
"title": "20 / GRAVEL ROAD & GARAGE",
"start": 2281,
"end": 2400,
"seconds": 5
},
{
"title": "21 / TESLA, SOLAR CHARGING & WORKSHOP",
"start": 2401,
"end": 2520,
"seconds": 5
},
{
"title": "22 / BALANCED FUTURE PAVILIONS",
"start": 2521,
"end": 2640,
"seconds": 5
},
{
"title": "23 / RECTANGLES AND GARDEN CURVES",
"start": 2641,
"end": 2760,
"seconds": 5
},
{
"title": "24 / BOOKS & A QUIET READING CORNER",
"start": 2761,
"end": 2880,
"seconds": 5
},
{
"title": "25 / TRAINING & STRENGTH",
"start": 2881,
"end": 3000,
"seconds": 5
},
{
"title": "26 / OUTDOOR TABLE & MATCHA",
"start": 3001,
"end": 3120,
"seconds": 5
},
{
"title": "27 / FLOWERING GARDEN - ROOM TO BREATHE",
"start": 3121,
"end": 3240,
"seconds": 5
},
{
"title": "28 / FLOWING WALKS AND GARDEN COURT",
"start": 3241,
"end": 3360,
"seconds": 5
},
{
"title": "29 / EASY EVERYDAY FOOD",
"start": 3361,
"end": 3480,
"seconds": 5
},
{
"title": "30 / COPPER & MARBLE KITCHEN",
"start": 3481,
"end": 3600,
"seconds": 5
},
{
"title": "31 / QUIET GARDEN BUDDHA",
"start": 3601,
"end": 3720,
"seconds": 5
},
{
"title": "32 / WIND POWER - PROPERTY CONCEPT",
"start": 3721,
"end": 3840,
"seconds": 5
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -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.

View File

@@ -0,0 +1,53 @@
# Version 009 — a wind turbine for the property
24 September 2026. Marcus asked to add his own wind turbine to the property,
the associated Git project and the public project page.
## Design
Added a conventional three-blade horizontal-axis turbine on a freestanding,
tapered galvanised mast, with an ivory rotor/nacelle, tail vane, foundation cap
and indicative lockable isolation cabinet. The illustrative location is
(-36, 40) m, beyond the northwestern edge of the homestead. The hub is 18 m above local
concept terrain and the rotor is 6 m in diameter. These are visual study
dimensions, not a selected product, rated output or engineered design.
Retain solar and energy storage. Keep the turbine out of the garden court,
future pavilion footprints, food beds and basketball reserve. Its final
position, tower height, foundations, access and electrical route must be
reconsidered against the actual site. No setback or wind clearance is verified.
## Deliverables and version boundaries
- Public model: `blender/samford-solarpunk-wind-tour-v009.blend`, derived only
from the distributable v007 model. Prior binaries remain unchanged.
- Private model: `/home/marcus/projects-private/samford-valley-home-v009/`
contains the turbine added to the licensed v008 Blender scene. Never copy
that binary into public Git or the web root.
- Matching detailed and lightweight viewport geometry; the original 31 tour
chapters remain, with turbine chapter 32 added (2 min 40 sec total).
- Updated concept plan, actual Blender overview render, website and context.
- The Unreal projects and v007 film retain their previous contents. The turbine
has not yet been imported into Unreal or added to the film.
## Before equipment selection
Measure the wind resource at a representative proposed hub height and assess
terrain, tree/building turbulence and seasonal variation. Then compare a
supplier's independently supported power curve and expected annual energy
against the household load and solar/storage plan. No output or payback is
assumed in this revision.
Obtain site-specific advice on council planning/building requirements, tower
engineering and geotechnical conditions, noise and neighbours, vegetation and
wildlife, maintenance access and electrical protection. The electrical designer
must establish compatible turbine control, braking/dump-load arrangements where
required, battery/inverter integration, isolation and earthing. If grid-connected,
confirm the combined generation connection requirements with Energex.
References checked 24 September 2026:
- [Australian Government Your Home — renewable energy](https://www.yourhome.gov.au/energy/renewable-energy)
- [Energex — solar connections and other technologies](https://www.energex.com.au/our-services/connections/residential-and-commercial-connections/solar-connections-and-other-technologies)
The existing lack of survey, property boundary, site wind measurements and
engineering remains explicit. The pending wall-integrated bed is unchanged.

View File

@@ -2,9 +2,17 @@
This is Marcus Rehbock's long-term personal homestead design project. The aim is to refine the design over several years, choose a real site, add survey and LiDAR information, coordinate construction plans, and eventually create a full Unreal Engine 5 walkthrough. The design is a working concept, not an approved or engineered building proposal.
## Current state: version 007, 12 September 2026
## Latest revision — v009 wind turbine, 24 September 2026
Open `blender/samford-solarpunk-presentation-tour.blend` in Blender 5.2.1. This is the current model. It includes the detailed kitchen and bedroom upgrades, a garden-centred arrangement, 13 flowering beds, and a 31-chapter camera tour lasting 2 minutes 35 seconds at 24 fps. The former table-tennis platform and its equipment have been removed. Earlier dated scene files are historical versions.
Added a three-blade wind turbine on a freestanding mast beyond the northwestern edge of the homestead. The concept location (-36, 40) m, 18 m hub height and 6 m rotor diameter are illustrative placeholders pending an actual site, wind measurements, equipment selection, engineering and approvals. Solar and storage remain part of the brief.
Current public Blender file: `blender/samford-solarpunk-wind-tour-v009.blend`, derived from distributable v007. The private v009 Blender file preserves the licensed v008 Tesla at `/home/marcus/projects-private/samford-valley-home-v009/`. Keep private binaries out of public Git. Both models add matching detailed/fast turbine geometry and chapter 32; the tour now lasts 2 min 40 sec and opens at the turbine chapter. Shift + Left Arrow restarts the complete tour.
Current plan: `plans/concept/wind-turbine-plan-v009.svg`. Current overview: `renders/v009-wind-overview.png`. See [v009 decision](../decisions/2026-09-24-v009-wind-turbine.md) for assumptions and feasibility work. The Unreal walkthroughs and v007 film are unchanged and do not yet include the turbine. All previous house and landscape features remain, including the future pavilion outlines and garden Buddha.
## Historical state: version 007, 12 September 2026
Open `blender/samford-solarpunk-presentation-tour.blend` in Blender 5.2.1. This is the preserved v007 model. It includes the detailed kitchen and bedroom upgrades, a garden-centred arrangement, 13 flowering beds, and a 31-chapter camera tour lasting 2 minutes 35 seconds at 24 fps. The former table-tennis platform and its equipment have been removed. Earlier dated scene files are historical versions.
The latest plan is `plans/concept/buddha-garden-plan.svg`. It is generated from the same `buddha-garden-layout.json` coordinates used by the Blender revision. The Buddha close-up is `renders/buddha-garden.png`. Other current images are `renders/container-water-overview.png`, `container-water.png` and `container-water-cutaway.png`. The preceding garden revision also has courtyard, planting, dining and training detail renders.
@@ -91,3 +99,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.

View File

@@ -59,3 +59,11 @@ 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.
## Version 009 — wind turbine, 24 September 2026
Marcus asked: “I want to have my own wind turbine on the property, can you add it to the associated git.rehbock.xyz project and update accordingly”. Added a conventional three-blade turbine concept to public and private Blender revisions, a 32nd tour chapter, updated concept plan, actual overview render and the website. The style and dimensions are working assumptions; no product, energy output or site compliance is established. Unreal and the concept film remain unchanged. See the v009 decision.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@@ -1,10 +1,10 @@
{
"milestone": "2026-09-12-v007-presentation-walkthrough",
"milestone": "2026-09-24-v009-wind-turbine",
"files": {
".gitattributes": "d4f9cc15aed223cff7a906452370117fc93992272828cb1efbdd94c61422ad19",
".gitignore": "d38c3a1d58416906185c4c7695ea24f9401be3b610fcce0e624f41dff9fe1675",
"AGENTS.md": "f95132bb06e10888f7948f3277f669cad6353fba87b446a6fb731b6cc423e638",
"README.md": "903a431234608261cb998f6bff42bfc566462253a5f165bf569e3ee12dc71edd",
"AGENTS.md": "f20c3f60e3d8d27b5d4d89a99ebff9e8a23499530f836263ece51d9f806a009f",
"README.md": "2d6e86ac8a38799f984bc95e055df7bd1fcc0d58c7078dbf276b2eb9b08c8801",
"blender/bedroom-sleep-checks.json": "4f28426b4c23e55c956a4c5bc94947706da63e35de455cfaedd8e90e330f1114",
"blender/blender-enhancement-checks.json": "f66943121057ec2e3c2fd0b2bb5d9245721e063b56cfef060598081fce3554e0",
"blender/blender-verification.json": "772764db02a6cec6225d01bf8e38c7680087e53f35614ed48212ea57cbec51dc",
@@ -28,6 +28,8 @@
"blender/samford-solarpunk-garden-flow-tour.blend": "b2bf1e7556f75b3ad3d96dbf340feac0fecfaf0865fcbeb838b1c417bb62ae2b",
"blender/samford-solarpunk-presentation-tour.blend": "9feab166af90eea6492de2999e38b3f1536008fa1b4f62eb9f7b1918cce8367a",
"blender/samford-solarpunk-reading-tour.blend": "f47296df39f3eaa381ec1b60615dec77f1ff5e2b5f3c645deea2e5b3af4e6d83",
"blender/samford-solarpunk-wind-tour-v009.blend": "a02c3898da7f2e385a0a57b5610c0b1035997116f747919a46cebfed8cd12c8a",
"blender/samford-solarpunk-wind-tour-v009.verification.json": "48f5a3909abecb42fcde45efc5800b94f749d00902af2e973d87c10db298f3af",
"blender/scripts/add_daily_life.py": "701f246fe963124b04ef86512ff1465dd51bec335ca0059d6b966b653563be47",
"blender/scripts/create_site_plan.py": "7e7c566e960e37b5a8225157750ba11c06afe72d86fdceea7d73b2e6e0b03a24",
"blender/scripts/enhance_kitchen.py": "2ac50b24427210f00f6bd4ba492ddaffef22ee3835c20f3ec72d41b97081f1f3",
@@ -37,6 +39,8 @@
"blender/tour-chapters-daily-life.json": "d6eb5ff0406a5e3b54fd088ef3e050f876a0b922c2b94350770900bca3d6a587",
"blender/tour-chapters-garden-flow.json": "7a6807925630812188acad57afab5c46671b0d0c4fe6c8b90763f5f80353cea6",
"blender/tour-chapters-reading.json": "53d17d81ab55528240e6453c19fc7e45721c1ecfcf610e90e21644da509d42ab",
"blender/tour-chapters-wind-v009.json": "378b08b048d8c480772c76bc7a141cbede17c531b919658130b033edacd2d735",
"blender/wind-turbine-layout-v009.json": "3e9d06c55ff24bdce810b33d1942fde9f082cf8bd24b46f24126abc3000e4dab",
"decisions/2026-09-10-repository-public.md": "3ded28ebf5fde19aeed74caac9308260602551651fdaebf58494fe625d0d27ad",
"decisions/2026-09-10-v001.md": "8c30365df61ef50a9bc06391e01eccc6e72c7bddd3d368defc34b720fcd90431",
"decisions/2026-09-10-v002-bedroom.md": "36d0a4a398b3fa8ca354e0f560c4cec4c96e788fa8789de41c11dad32d65c90e",
@@ -46,13 +50,16 @@
"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",
"decisions/2026-09-24-v009-wind-turbine.md": "26118e95b1fe9f716bb3a7ed6e7df8c31eff2fcb038500f2b4e6c81e1ec5e228",
"docs/PROJECT-CONTEXT.md": "f44ba333fcf5a6955cd35f281c21677e7c732ea67956e52ea643d2e2349bca95",
"docs/REQUEST-HISTORY.md": "555ec31c40f80a04ee0d24db0fcc766768d66e91a7f692a6b70f9eab2c1d28a7",
"plans/architectural/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"plans/concept/buddha-garden-plan.svg": "62f622647732bf9556e7d351c06c9dc8576f68e8e0044f91232401972e43e466",
"plans/concept/container-water-plan.svg": "5cf52ea84ae8e222f64881b46807ca869728845c9e1a5b5c80ecfdbfbc3d5fe3",
"plans/concept/garden-flow-plan.svg": "95c7309d44143ebb3f11a7e0f6b4cee8b076c17a423ab14c8288f450b54ae4db",
"plans/concept/retreat-garage-plan.svg": "225985399ed62625b0280ef9e6a802e276e3c6aad6c35e47c744628868c8022e",
"plans/concept/wind-turbine-plan-v009.svg": "d4e7cf9aad22559f61f123f37775315934a06f3769198099062a756f4c379107",
"plans/engineering/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"references/UNREAL-PROJECT-SCOPE.md": "9727e4447a772756fae2456465f4677d63772858d3433e68c901adbd3a2a5632",
"renders/bedroom-sleep-setup.png": "5e12a5303615695093b61ef70111ee3d75c41ebe119c9efe0645f70725fbb707",
@@ -78,9 +85,17 @@
"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",
"renders/v009-wind-overview.png": "1aa727e37a263eed860718c758624af416f0a094aac7ca6368e4a555851b60e8",
"site/lidar/processed/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"site/lidar/raw/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"site/metadata/llms.txt": "5810cb29ffa7f9b1521babb3cedf1a7b8a95cd5af5f66e3072ef466489cdc9ed",
"site/metadata/sitemap.xml": "6af5dec5ef6d887c751becc9549970e7251fce6e164037f3d80da02ecda63c27",
"site/photos/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"site/samford-valley-home/index.html": "7cbd30f42a4e23a5d9d5bdb939c1beec20c5dd9d8dfe697e607b8099e9d3bade",
"site/surveys/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"source/samford-modular/README.md": "e4dd2ed10b0e4f33ddfae86e753cc572d7872bce67ba9aecf66557befc05324d",
"source/samford-modular/build_scene.py": "0bce8490a7f078880c0902b464e9f0202e30f2b44673a7b5378d248850264aa9",
@@ -147,6 +162,23 @@
"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",
"source/samford-v009-wind/README.md": "fc9f6f3f18686445fe270808bf3a4db479f8b7292168ea11a4b626ed63835fb0",
"source/samford-v009-wind/add_wind_turbine.py": "c1e9b7112473b888d6f5d34c137f8e166be7e4dc0679d2e0074f37a822b326cb",
"source/samford-v009-wind/publication-sha256.json": "5bc8d2358c3eef904b2ee3533696dc24f920477ba10c8d26a8c85acddef13b60",
"source/samford-v009-wind/verify_wind_turbine.py": "ef54260f1c66079f59af06a551bf077f14af1fa5da3311eefcb83297e5b58c71",
"unreal/MeditationRoom.fbx": "7540b71e6cf075e51748db7dc829cf7330c1bfa8cfd8c713041f2127f17ceceb",
"unreal/MeditationRoom.glb": "529770faf5d746f74cc33ccaa84bc1315b1dced2a2e6d14209add716983a9fb6",
"unreal/SamfordHomestead/Config/DefaultEngine.ini": "3448b132adc8ac3f9690fec0a0895d7f3f6d0b1463bf65c81b0d4c822f4c9000",
@@ -856,4 +888,4 @@
"walkthroughs/video/render-checks.json": "307987c6a052f2f0e6140bbe0640eae8295838d8888d87ad7c59335d788e788f",
"walkthroughs/video/video-verification.json": "fa0e585f0c30795fb7ba8b8a831ed945318c91402eec98f68c50ae4f3f62ac63"
}
}
}

45
site/metadata/llms.txt Normal file
View File

@@ -0,0 +1,45 @@
# Marcus Rehbock
> Technical product manager and builder from Brisbane, Australia, now in San Francisco building startups. Co-founder of The Pai Company. Formerly Technical Product Manager at Updoc (healthtech) and Associate Product Manager intern at Atlassian. BSc Computer Science + BCom Finance, University of Queensland. Runs a ~35-container self-hosted server, writes a friends & family newsletter, and ships side projects across web, mobile and ML.
Canonical site: https://rehbock.xyz (marcusrehbock.com is the same person). Contact: marcus@rehbock.xyz.
Core values, in his own words: Health · Relationships · Wealth · Flow.
## Identity
- [Home](https://rehbock.xyz/): who I am, newsletter issues, a random quote
- [Now](https://rehbock.xyz/now/): what I'm doing right now (Sivers-style /now page)
- [Resume](https://rehbock.xyz/resume/): experience, education, awards — Updoc, Atlassian, The Pai Company, UQ
- [LinkedIn](https://www.linkedin.com/in/marcus-rehbock-52673b159/): professional profile
- [Code](https://git.rehbock.xyz/marcus): self-hosted Gitea with public repositories
## Things I've built
- [Samford Valley home](https://rehbock.xyz/projects/samford-valley-home/): extendible homestead design with solar, a freestanding wind turbine concept, gardens and an editable Blender model; an earlier whole-site Unreal walking prototype and concept film are available. Real-site surveys, wind assessment and engineering remain future work.
- [Projects](https://rehbock.xyz/projects/): the full list with what/why/stack for each
- [maPPP](https://mappp.rehbock.xyz): interactive 3D globe of purchasing power on live World Bank data (three.js, globe.gl)
- [Sonora](https://sonora.rehbock.xyz): local 3D audio visualizer — spectral peaks as an orbiting constellation, plus texture/frequency/modulation plots (three.js, Web Audio API); source at https://git.rehbock.xyz/marcus/sonora
- [BJJ injury visualizer](https://bjj.rehbock.xyz): interactive 3D anatomy of a T2–T5 costovertebral joint sprain from a jiu-jitsu neck crank — mechanism animation plus six rehab exercises with the targeted structures highlighted (three.js, single file)
- [BuddhaGPT](https://git.rehbock.xyz/marcus/buddha-gpt): Qwen2.5-7B QLoRA fine-tune on the Pali Canon, RAG with sutta citations, CompassionBench eval harness (Python)
- [Friends & Family Newsletter](https://blog.rehbock.xyz): seven long-form issues, self-hosted and self-sent; custom admin, editor and voice-memo tooling
- [Budgy](https://budgyai.xyz): AI budget meal planner — seven dinners and a priced shopping list from a weekly budget (iOS + web)
- [GoalHound](https://goalhound-app.vercel.app/): AI accountability partner on WhatsApp — set a SMART goal, send photo proof, get chased until it's done
- [Kin](https://git.rehbock.xyz/marcus/kin): self-hosted relational-wealth CRM — Bun/Hono API, web UI, Expo Android app
- [GTD](https://git.rehbock.xyz/marcus/gtd): minimal Getting Things Done app — Expo/React Native + Bun + Postgres
- [Meditation timer](https://git.rehbock.xyz/marcus/meditation-timer): Jhana timer for GrapheneOS, CI-built APKs via Gitea Actions + Obtainium
- Private, self-hosted: a personal health platform (bloodwork, DNA, DEXA, workouts, sleep, meditation; Bun + SQLite API + MCP server + Expo app), ClaudeClaw (a Claude Code ops agent on the server, over Telegram), a voice-memo → newsletter pipeline, and the homelab itself (Docker Compose behind Caddy, restic backups to BorgBase)
## Taste
- [Heroes](https://rehbock.xyz/heroes/): people I learn from
- [Quotes](https://rehbock.xyz/quotes/): quotes I keep coming back to
- [Media](https://rehbock.xyz/media/): books, films, albums, YouTube, articles
- [Hobbies](https://rehbock.xyz/hobbies/): meditation, travel, reading, building, training (basketball, Jiu Jitsu), writing
- [Uses](https://rehbock.xyz/uses/): hardware, software and the self-hosted stack
## Machine-readable
- [Sitemap](https://rehbock.xyz/sitemap.xml)
- [Newsletter RSS](https://blog.rehbock.xyz/feed.xml)
- JSON-LD Person schema is embedded in https://rehbock.xyz/ (@id https://rehbock.xyz/#person) with sameAs links

13
site/metadata/sitemap.xml Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://rehbock.xyz/</loc><lastmod>2026-09-01</lastmod><changefreq>monthly</changefreq><priority>1.0</priority></url>
<url><loc>https://rehbock.xyz/projects/</loc><lastmod>2026-09-10</lastmod><changefreq>monthly</changefreq><priority>0.9</priority></url>
<url><loc>https://rehbock.xyz/now/</loc><lastmod>2026-07-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://rehbock.xyz/resume/</loc><lastmod>2026-08-25</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://rehbock.xyz/uses/</loc><lastmod>2026-08-09</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url>
<url><loc>https://rehbock.xyz/heroes/</loc><lastmod>2026-07-27</lastmod><changefreq>yearly</changefreq><priority>0.5</priority></url>
<url><loc>https://rehbock.xyz/quotes/</loc><lastmod>2026-08-06</lastmod><changefreq>yearly</changefreq><priority>0.5</priority></url>
<url><loc>https://rehbock.xyz/media/</loc><lastmod>2026-09-12</lastmod><changefreq>monthly</changefreq><priority>0.5</priority></url>
<url><loc>https://rehbock.xyz/hobbies/</loc><lastmod>2026-08-09</lastmod><changefreq>yearly</changefreq><priority>0.5</priority></url>
<url><loc>https://rehbock.xyz/projects/samford-valley-home/</loc><lastmod>2026-09-24</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
</urlset>

View File

@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Samford Valley home — Marcus Rehbock</title>
<meta name="description" content="A long-term design project for a simple, extendible homestead in Samford Valley: Blender models, natural materials, food gardens and a walkable Unreal Engine prototype.">
<link rel="canonical" href="https://rehbock.xyz/projects/samford-valley-home/">
<meta property="og:title" content="Samford Valley home — a home that can grow">
<meta property="og:type" content="website"><meta property="og:url" content="https://rehbock.xyz/projects/samford-valley-home/">
<meta property="og:description" content="A family homestead, designed slowly over years. Explore the early Blender and Unreal Engine studies.">
<meta property="og:image" content="https://rehbock.xyz/projects/samford-valley-home/images/v007-presentation-overview.jpg"><meta name="twitter:card" content="summary_large_image">
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,500;0,600;1,400&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "CreativeWork", "name": "Samford Valley home", "url": "https://rehbock.xyz/projects/samford-valley-home/", "dateCreated": "2026-09-10", "dateModified": "2026-09-24", "author": {"@id": "https://rehbock.xyz/#person"}, "image": "https://rehbock.xyz/projects/samford-valley-home/images/v007-presentation-overview.jpg"}</script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
--text: #1a1a1a;
--text-secondary: #555;
--text-light: #888;
--bg: #faf6ec;
--bg-card: #ffffff;
--border: #e8e5e0;
--serif: 'EB Garamond', Georgia, serif;
--sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
html { scroll-behavior: smooth; }
body { font-family: var(--sans); background: var(--bg); color: var(--text); line-height: 1.7; -webkit-font-smoothing: antialiased; }
nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(250, 246, 236, 0.85); backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); }
.nav-inner { max-width: 900px; margin: 0 auto; padding: 16px 32px; display: flex; justify-content: space-between; align-items: center; }
.nav-name { font-family: var(--serif); font-size: 20px; font-weight: 600; color: var(--text); text-decoration: none; }
.nav-back { font-size: 14px; color: var(--text-secondary); text-decoration: none; letter-spacing: 0.3px; }
.nav-back:hover { color: var(--text); }
main { max-width: 760px; margin: 0 auto; padding: 130px 32px 80px; }
h1 { font-family: var(--serif); font-size: 42px; font-weight: 500; letter-spacing: -0.5px; line-height: 1.2; margin-bottom: 12px; }
.lede { font-size: 17px; color: var(--text-secondary); max-width: 560px; margin-bottom: 8px; }
.updated { font-size: 13px; color: var(--text-light); letter-spacing: 0.3px; margin-bottom: 56px; }
h2 { font-family: var(--serif); font-size: 28px; font-weight: 500; letter-spacing: -0.3px; margin: 56px 0 8px; padding-top: 40px; border-top: 1px solid var(--border); }
h2 + p.section-note { font-size: 15px; color: var(--text-light); margin-bottom: 28px; }
.project { display: grid; grid-template-columns: 1fr; gap: 18px; padding: 28px 0; border-top: 1px solid var(--border); }
.project:first-of-type { border-top: 0; }
.shot { display: block; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: var(--bg-card); box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
.shot img { display: block; width: 100%; height: auto; }
.project h3 { font-family: var(--serif); font-size: 24px; font-weight: 600; letter-spacing: -0.2px; display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.project h3 a { color: var(--text); text-decoration: none; }
.project h3 a:hover { text-decoration: underline; text-underline-offset: 4px; text-decoration-color: var(--border); }
.status { font-family: var(--sans); font-size: 11px; font-weight: 600; letter-spacing: 1.1px; text-transform: uppercase; padding: 3px 8px; border-radius: 999px; border: 1px solid var(--border); color: var(--text-light); }
.status.live { color: #2f6b3a; border-color: #cfe3d3; background: #eef7f0; }
.status.private { color: #7a5a1e; border-color: #ead9b8; background: #fbf3e2; }
.status.wip { color: #4a5a7a; border-color: #cdd6e6; background: #eef2f9; }
.project p { font-size: 15.5px; color: var(--text-secondary); margin-bottom: 10px; }
.project p a { color: var(--text); text-decoration: underline; text-decoration-color: var(--border); text-underline-offset: 3px; }
.project p a:hover { text-decoration-color: var(--text); }
.why { font-style: italic; }
.why strong { font-style: normal; font-weight: 600; color: var(--text); }
.stack { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 12px; }
.stack li { font-size: 12px; color: var(--text-secondary); background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; padding: 2px 8px; letter-spacing: 0.2px; }
.links { font-size: 14px; }
.links a { color: var(--text); text-decoration: none; border-bottom: 1px solid var(--border); padding-bottom: 1px; margin-right: 14px; }
.links a:hover { border-color: var(--text); }
.links .muted { color: var(--text-light); margin-right: 14px; }
.earlier { list-style: none; }
.earlier li { padding: 14px 0; border-top: 1px solid var(--border); font-size: 15.5px; color: var(--text-secondary); }
.earlier li:first-child { border-top: 0; }
.earlier strong { color: var(--text); font-weight: 600; }
.earlier .year { color: var(--text-light); font-size: 13px; margin-left: 8px; }
.colophon { margin-top: 64px; padding-top: 24px; border-top: 1px solid var(--border); font-size: 14px; color: var(--text-light); }
.colophon a { color: var(--text-secondary); }
footer { max-width: 900px; margin: 0 auto; padding: 32px; border-top: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; font-size: 13px; color: var(--text-light); }
.footer-links { display: flex; gap: 18px; flex-wrap: wrap; }
.footer-links a { color: var(--text-light); text-decoration: none; }
.footer-links a:hover { color: var(--text); }
@media (min-width: 720px) {
.project.has-shot { grid-template-columns: 260px 1fr; align-items: start; }
}
@media (max-width: 768px) {
main { padding: 110px 20px 48px; }
.nav-inner { padding: 14px 20px; }
h1 { font-size: 32px; }
h2 { font-size: 24px; }
}
main{max-width:1080px} .intro{max-width:730px} .lede{max-width:720px} p{margin-bottom:18px} figure{margin:32px 0 48px} figure img{display:block;width:100%;height:auto;border-radius:8px;border:1px solid var(--border)} figcaption{font-size:14px;color:var(--text-secondary);margin-top:10px;max-width:760px} .roadmap{padding-left:22px;margin:22px 0} .roadmap li{margin-bottom:15px} .note{padding:20px 24px;background:#f0eadf;border-left:3px solid #83916b;border-radius:3px} .intro a,main>p a{color:inherit;text-underline-offset:4px} .updated{margin-bottom:28px} blockquote{font-family:var(--serif);font-size:27px;line-height:1.4;margin:30px 0} blockquote cite{display:block;font:13px var(--sans);margin-top:9px;color:var(--text-secondary)}
</style></head><body>
<nav><div class="nav-inner"><a href="/" class="nav-name">Marcus Rehbock</a><a href="/projects/" class="nav-back">&larr; Projects</a></div></nav>
<main><div class="intro"><p class="updated">Started September 2026 · Concept design · A project for the coming years</p>
<h1>A home that can grow.</h1><p class="lede">A simple family homestead in Samford Valley, Queensland. Warm timber, soft clay walls, solar and wind power, food gardens and room to change my mind.</p>
<p>I want to spend the next few years getting this house right. Inspired by Derek Sivers’ article <a href="https://sive.rs/fit">Building without predicting</a>, the starting point is a few straightforward spaces, with future additions left visible as outlines. The house should adapt to life as it unfolds.</p>
<blockquote>“All buildings are predictions. All predictions are wrong.”<cite>— Stewart Brand</cite></blockquote>
<p>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. A freestanding wind turbine is now part of the concept alongside container-enclosed rainwater storage, solar panels, a greenhouse and garden beds are part of the homesteading idea.</p></div>
<div class="intro"><h2 id="wind-turbine">A wind turbine of my own</h2><p><strong>24 September 2026 — Version 009.</strong> A three-blade turbine on a freestanding mast joins the homestead concept, set beyond the northwestern edge of the homestead to keep the central garden and future pavilions open. I want wind generation to sit alongside the existing solar and energy-storage plans.</p><p>The model shows an 18-metre hub height and a 6-metre rotor to explore its scale in the landscape. These are provisional study dimensions. The actual property’s wind, trees, terrain, neighbours and approval requirements will determine the location and equipment.</p></div>
<figure><a href="images/v009-wind-overview.png"><img src="images/v009-wind-overview.png" alt="Actual Blender concept render of the Samford Valley homestead with a three-blade wind turbine on a freestanding mast beyond the northwestern edge of the homestead" width="1536" height="864" loading="lazy"></a><figcaption>Version 009: the wind turbine in the full homestead model. Illustrative terrain and equipment scale; no surveyed location or energy yield has been established.</figcaption></figure>
<div class="intro"><p>The editable Blender models include the turbine and a new inspection-tour chapter. The <a href="https://git.rehbock.xyz/marcus/samford-valley-home">public project repository</a> contains the distributable version, source script, updated plan and design notes. The Unreal walkthrough and version 007 film shown below retain their earlier contents.</p><p class="note">Next: assess wind at the proposed hub height, then resolve siting, noise, tower engineering, maintenance access and electrical integration. The <a href="https://www.yourhome.gov.au/energy/renewable-energy">Australian Government’s Your Home guide</a> explains why household wind needs an exposed site with smooth, consistent wind. Any grid connection will also need assessment through <a href="https://www.energex.com.au/our-services/connections/residential-and-commercial-connections/solar-connections-and-other-technologies">Energex’s generation-connection process</a>.</p></div>
<figure><a href="images/v007-presentation-overview.jpg"><img src="images/v007-presentation-overview.jpg" alt="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." width="1600" height="900" loading="lazy"></a><figcaption>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.</figcaption></figure>
<figure><video controls playsinline preload="metadata" poster="images/v007-presentation-overview.jpg" style="display:block;width:100%;height:auto;border-radius:8px"><source src="videos/Samford-Valley-Concept-Film-v007.mp4" type="video/mp4">Your browser can download the film using the link below.</video><figcaption>A 30-second concept film: open living, natural materials, shared meals and room to grow. <a href="videos/Samford-Valley-Concept-Film-v007.mp4">Download the MP4</a>.</figcaption></figure>
<figure><a href="images/v007-presentation-kitchen.jpg"><img src="images/v007-presentation-kitchen.jpg" alt="Detailed timber kitchen with woven pendants, clay walls, copper cookware and marble island" width="1600" height="900" loading="lazy"></a><figcaption>Version 007 adds woven pendants, softer construction edges, natural-finish variation, table settings and fuller garden planting.</figcaption></figure>
<figure><a href="images/v007-unreal-verandah.jpg"><img src="images/v007-unreal-verandah.jpg" alt="Actual Unreal Engine view into the main homestead pavilion" width="1600" height="900" loading="lazy"></a><figcaption>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.</figcaption></figure>
<figure><a href="images/buddha-garden.jpg"><img src="images/buddha-garden.jpg" alt="Seated stone Buddha beside the meditation pavilion and curved garden walk" width="1536" height="864" loading="lazy"></a><figcaption>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.</figcaption></figure>
<figure><a href="images/container-water.jpg"><img src="images/container-water.jpg" alt="Dark-green corrugated shipping-container water module with cargo doors and rainwater plumbing" width="1536" height="864" loading="lazy"></a><figcaption>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.</figcaption></figure>
<figure><a href="images/garden-court.jpg"><img src="images/garden-court.jpg" alt="The central oval garden court, paired flower beds, curved walkway and balanced future pavilion outlines" width="1536" height="864" loading="lazy"></a><figcaption>The garden gives the separate pavilions a shared centre. A north–south axis, paired planting and gently curving connections bring the composition together.</figcaption></figure>
<figure><a href="images/kitchen-copper-marble.jpg"><img src="images/kitchen-copper-marble.jpg" alt="Kitchen refinement: a marble-topped timber island, oven, four-zone induction cooktop, detailed drawers, copper cookware and a recessed sink." width="1536" height="864" loading="lazy"></a><figcaption>Kitchen refinement: a marble-topped timber island, oven, four-zone induction cooktop, detailed drawers, copper cookware and a recessed sink.</figcaption></figure>
<figure><a href="images/garden-flow-dining.jpg"><img src="images/garden-flow-dining.jpg" alt="A ten-place outdoor table with timber benches and end chairs, pergola shade and a nearby tea and matcha preparation counter." width="1536" height="864" loading="lazy"></a><figcaption>A ten-place outdoor table with timber benches and end chairs, pergola shade and a nearby tea and matcha preparation counter.</figcaption></figure>
<figure><a href="images/garden-flow-training.jpg"><img src="images/garden-flow-training.jpg" alt="Covered training beside the garage: a dedicated pull-up and wooden-rings frame, adjustable dumbbells and bench, movable mats and timber access steps." width="1536" height="864" loading="lazy"></a><figcaption>Covered training beside the garage: a dedicated pull-up and wooden-rings frame, adjustable dumbbells and bench, movable mats and timber access steps.</figcaption></figure>
<figure><a href="images/reading-corner.jpg"><img src="images/reading-corner.jpg" alt="Reading-corner study: a timber library filled with books, a linen reading chair and a small side table." width="1600" height="900" loading="lazy"></a><figcaption>Reading-corner study: a timber library filled with books, a linen reading chair and a small side table.</figcaption></figure>
<figure><a href="images/meditation-room.jpg"><img src="images/meditation-room.jpg" alt="The first actual Unreal Engine 5.8.2 render: clay walls, timber, a meditation cushion and candles." width="1600" height="900" loading="lazy"></a><figcaption>The first actual Unreal Engine 5.8.2 render: clay walls, timber, a meditation cushion and candles.</figcaption></figure>
<figure><a href="images/garage.jpg"><img src="images/garage.jpg" alt="The garage study: a Tesla, workshop bench, bicycle storage and rooftop solar." width="1600" height="900" loading="lazy"></a><figcaption>The garage study: a Tesla, workshop bench, bicycle storage and rooftop solar.</figcaption></figure>
<figure><a href="images/bedroom-sleep.jpg"><img src="images/bedroom-sleep.jpg" alt="Bedroom with an Eight Sleep-style cooling cover and bedside hub, oatmeal blackout curtains and a wall-mounted split air conditioner" width="1536" height="864" loading="lazy"></a><figcaption>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.</figcaption></figure>
<div class="intro"><h2>Space for everyday life</h2><p>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.</p><p>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.</p><p>The latest Blender inspection tour has 32 chapters and lasts 2 minutes 40 seconds, with views of the garden layout, future pavilions, kitchen and the new wind turbine.</p></div>
<div class="intro"><h2>Where the project goes next</h2>
<p>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.</p>
<ol class="roadmap"><li><strong>Keep refining the house.</strong> Test room proportions, circulation, materials, storage and where future buildings belong.</li><li><strong>Bring in the real site.</strong> Add boundary and contour surveys, site photographs and LiDAR when a property is available.</li><li><strong>Develop coordinated plans.</strong> Bring architectural, structural and services models together with the landscape and access design.</li><li><strong>Develop the Unreal experience.</strong> Refine materials and performance, add interactions and camera tours, then package and test the walkthrough for clients.</li><li><strong>Record the build.</strong> Keep dated decisions, construction photographs and revised models as the house becomes real.</li></ol>
<p><a href="images/wind-turbine-plan-v009.svg">View the updated concept site plan &rarr;</a></p>
<p class="note">These images are early design studies. The terrain is illustrative; surveyed land, LiDAR and construction drawings have not been added yet.</p>
<h2>Tesla and a daylight walkthrough</h2><p>15 September 2026 — The garage now uses an existing Tesla Model 3 by <a href="https://www.blendkit.com/asset-gallery-detail/1fc56739-2fd9-447e-b2c1-fee5d9e276b7/">7K Studio</a>. 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.</p><figure><a href="images/v008-tesla-garage.png"><img src="images/v008-tesla-garage.png" alt="7K Studio Tesla Model 3 in the timber and clay garage, rendered in Blender" width="1600" height="1000" loading="lazy"></a><figcaption>The imported artist model in Blender, with the existing workshop and bikes.</figcaption></figure><figure><a href="images/v008-daylight-overview.png"><img src="images/v008-daylight-overview.png" alt="Actual Unreal Engine daylight view of the homestead" width="1600" height="900" loading="lazy"></a><figcaption>Actual Unreal Engine daylight scene. Walking and Tesla collision have been tested.</figcaption></figure><h2>Project journal</h2><p><strong>24 September 2026 — Wind turbine.</strong> Added a freestanding three-blade turbine to the Blender concept, with matched lightweight display geometry, a 32nd camera-tour chapter, a revised plan and a new overview render. Siting, capacity and equipment remain subject to assessment.</p><p><strong>12 September 2026 — Presentation and walking prototype.</strong> 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.</p><p><strong>10 September 2026 — Garden Buddha.</strong> 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.</p><p><strong>10 September 2026 — Container water storage.</strong> 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 <a href="https://git.rehbock.xyz/marcus/samford-valley-home">project repository is now public</a>, including Blender models, design context and revision history.</p><p><strong>10 September 2026 — A home held together by its garden.</strong> 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.</p><p><strong>10 September 2026 — Movement, meals and a detailed kitchen.</strong> 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.</p><p><strong>10 September 2026 — Bedroom comfort.</strong> 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.</p><p><strong>10 September 2026 — First saved milestone.</strong> 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.</p>
<p class="colophon"><a href="/projects/">&larr; Back to all projects</a></p></div></main>
<footer><span>Marcus Rehbock</span><div class="footer-links"><a href="/">Home</a><a href="/projects/">Projects</a><a href="/now/">Now</a></div></footer>
<script async src="https://scripts.simpleanalyticscdn.com/latest.js" data-collect-dnt="true"></script>
</body></html>

View File

@@ -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/"
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.5<r['car_length']<4.9
assert .61<r['car_bounds'][2][0]<.65
assert len(old.objects)>10
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)

View File

@@ -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": "<Struct 'Rotator' (0x3e3ac12d0) {pitch: -52.465094, yaw: 130.601295, roll: -0.000000}>",
"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."
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 200<bounds.box_extent.y<260,str(bounds)
# Camera from the garage entrance, retaining the original walking spawn and all existing cameras.
cp=u.Vector(-280,1200,245);target=u.Vector(-120,1920,145);cam=A.spawn_actor_from_class(u.CameraActor,cp,u.MathLibrary.find_look_at_rotation(cp,target));cam.set_actor_label('CAM - Licensed Tesla garage');cam.camera_component.set_field_of_view(50);prop(cam.camera_component,'aspect_ratio',1.6)
# Gentle local fill makes dark automobile interiors readable in the prototype.
light=A.spawn_actor_from_class(u.RectLight,u.Vector(-150,1550,300),u.Rotator(-20,90,0));light.set_actor_label('Garage presentation fill');light.light_component.set_mobility(u.ComponentMobility.MOVABLE);light.light_component.set_intensity(800);prop(light.light_component,'attenuation_radius',700);prop(light.light_component,'source_width',300);prop(light.light_component,'source_height',180)
E.save_current_level();L.save_directory('/Game/LicensedTesla',only_if_is_dirty=True,recursive=True)
report={'removed_placeholder_groups':len(old),'new_meshes':len(meshes),'materials':len(materials),'car_bounds_cm':str(bounds),'level_saved':True,'source':'7K Studio Tesla Model 3','public_distribution':False}
(P/'unreal-tesla-checks.json').write_text(json.dumps(report,indent=2))
state={'start':time.monotonic(),'task':None}
def tick(dt):
if time.monotonic()-state['start']<25:return
if state['task'] is None:
u.AutomationLibrary.finish_loading_before_screenshot();state['task']=u.AutomationLibrary.take_high_res_screenshot(1600,1000,str(P/'renders/unreal-tesla-garage.png'),camera=cam,delay=3)
elif state['task'].is_task_done():
u.unregister_slate_post_tick_callback(handle);u.log('TESLA_UNREAL_READY');u.SystemLibrary.quit_editor()
handle=u.register_slate_post_tick_callback(tick)

View File

@@ -0,0 +1,46 @@
import unreal as u,json,time,math,traceback
from pathlib import Path
ROOT=Path(__file__).resolve().parents[3];LEVEL=u.get_editor_subsystem(u.LevelEditorSubsystem);EDITOR=u.get_editor_subsystem(u.UnrealEditorSubsystem);report={'floor_traces':{},'movement':None};u.EditorPythonScripting.set_keep_python_script_alive(True)
state={'start':time.monotonic(),'phase':'load','t':0,'positions':[]}
def pos(v):return u.Vector(v[0]*100,-v[1]*100,v[2]*100)
def tick(dt):
try:
elapsed=time.monotonic()-state['start']
if state['phase']=='finish':
if time.monotonic()-state['t']>3:
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 170<p.z<240,('Spawn not on floor',p.z);state['phase']='car_settle';state['t']=time.monotonic();pawn.set_actor_location(u.Vector(-170,1500,153),False,True)
elif state['phase']=='car_settle':
if time.monotonic()-state['t']<1:return
state['phase']='car_walk';state['t']=time.monotonic()
elif state['phase']=='car_walk':
pawn.add_movement_input(u.Vector(0,1,0),1)
if time.monotonic()-state['t']>2.5:
q=pawn.get_actor_location();assert 1570<q.y<1680,('Car did not stop walking capsule',q)
report['tesla_collision']={'walk_stopped_before_car':True,'position_cm':[q.x,q.y,q.z]}
pawn.set_actor_location(u.Vector(*state['initial']),False,True);state['phase']='walk_reset';state['t']=time.monotonic()
elif state['phase']=='walk_reset':
if time.monotonic()-state['t']<1:return
state['phase']='walk';state['t']=time.monotonic()
elif state['phase']=='walk':
p=pawn.get_actor_location();state['positions'].append([p.x,p.y,p.z]);pawn.add_movement_input(u.Vector(0,1,0),1)
if time.monotonic()-state['t']>2.5:
a=state['initial'];dist=math.hypot(p.x-a[0],p.y-a[1]);assert dist>100,('No meaningful movement',dist);assert 170<p.z<240,('Pawn left walking floor',p.z)
report['movement']={'pawn':pawn.get_class().get_name(),'start_cm':a,'end_cm':[p.x,p.y,p.z],'distance_cm':dist,'movement_mode':str(pawn.character_movement.movement_mode),'controller_possessed':pawn.get_controller() is not None,'sampled_positions':len(state['positions'])};report['status']='PASS: daylight level, Tesla blocks walking, eight floor traces and possessed character walking from verandah into living entry';(ROOT/'unreal-walkthrough-verification.json').write_text(json.dumps(report,indent=2));LEVEL.editor_request_end_play();state['phase']='finish';state['t']=time.monotonic()
except Exception:
report['status']='FAILED';report['error']=traceback.format_exc();(ROOT/'unreal-walkthrough-verification.json').write_text(json.dumps(report,indent=2));u.log_error(report['error']);u.unregister_slate_post_tick_callback(handle);LEVEL.editor_request_end_play();u.SystemLibrary.quit_editor()
handle=u.register_slate_post_tick_callback(tick)

View File

@@ -0,0 +1,39 @@
{
"floor_traces": {
"verandah": "hit",
"living": "hit",
"corridor": "hit",
"bedroom": "hit",
"meditation": "hit",
"garage": "hit",
"garden": "hit",
"training": "hit"
},
"movement": {
"pawn": "BP_HomesteadWalker_C",
"start_cm": [
0.0,
-455.0,
208.91514610554694
],
"end_cm": [
0.0,
-109.60077457824171,
204.1499967251696
],
"distance_cm": 345.3992254217583,
"movement_mode": "<MovementMode.MOVE_WALKING: 1>",
"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."
}

View File

@@ -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']))

View File

@@ -0,0 +1,26 @@
# v009 wind turbine concept
`add_wind_turbine.py` is an incremental Blender 5.2.1 script. Use the public
v007 presentation model or the private licensed v008 model as input; do not
run it on a v009 output. It adds the turbine, matching lightweight geometry,
a separate overview camera and tour chapter 32. Existing scenes are preserved.
```sh
blender --background blender/samford-solarpunk-presentation-tour.blend \
--python source/samford-v009-wind/add_wind_turbine.py -- \
--output blender/samford-solarpunk-wind-tour-v009.blend \
--render renders/v009-wind-overview.png
blender --background blender/samford-solarpunk-wind-tour-v009.blend \
--python source/samford-v009-wind/verify_wind_turbine.py
```
Rendering uses Cycles/Metal on macOS; adapt device selection for other hosts.
The verification script reopens the saved file and checks turbine geometry,
viewport copies, retained features, future outlines, material references and
all 32 caption intervals. It writes a sibling `.verification.json` report.
Private v008 inputs must write exclusively to a private directory. Never
publish a `.blend` containing the licensed Tesla. The public render uses the
distributable v007 vehicle. The turbine is original concept geometry, not a
manufacturer model or engineering design. Read the v009 decision for siting
and equipment assumptions. No Unreal assets or existing film were rebuilt.

View File

@@ -0,0 +1,192 @@
"""Run with Blender --background INPUT.blend --python this.py -- --output OUTPUT.blend.
Add an illustrative turbine to either public v007 or private v008. Never publish
an output based on the licensed v008 scene. Dimensions are visual placeholders.
"""
import argparse
import bpy
import json
import math
import sys
from pathlib import Path
from mathutils import Vector
parser = argparse.ArgumentParser()
parser.add_argument('--output', required=True)
parser.add_argument('--render')
args = parser.parse_args(sys.argv[sys.argv.index('--') + 1:])
output = Path(args.output).resolve()
output.parent.mkdir(parents=True, exist_ok=True)
s = bpy.context.scene
assert '39 WIND - property turbine concept' not in bpy.data.collections, 'Already added'
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
coll = bpy.data.collections.new('39 WIND - property turbine concept')
detail.children.link(coll)
def material(name, color, metallic=0):
m = bpy.data.materials.new(name)
m.diffuse_color = (*color, 1)
m.use_nodes = True
shader = m.node_tree.nodes.get('Principled BSDF')
shader.inputs['Base Color'].default_value = (*color, 1)
shader.inputs['Metallic'].default_value = metallic
shader.inputs['Roughness'].default_value = .38
return m
white = material('WIND - warm ivory composite', (.79, .80, .74))
steel = material('WIND - galvanised mast', (.42, .47, .45), .65)
dark = material('WIND - dark service enclosure', (.095, .14, .12), .35)
concrete = material('WIND - foundation concept', (.37, .35, .29))
def adopt(ob, name, mat):
ob.name = 'WIND - ' + name
for c in list(ob.users_collection):
c.objects.unlink(ob)
coll.objects.link(ob)
ob.data.materials.append(mat)
return ob
def box(name, p, dimensions, mat):
bpy.ops.mesh.primitive_cube_add(size=1, location=p)
ob = adopt(bpy.context.object, name, mat)
ob.scale = dimensions
return ob
def cone(name, a, b, r1, r2, mat):
a, b = Vector(a), Vector(b)
bpy.ops.mesh.primitive_cone_add(vertices=40, radius1=r1, radius2=r2,
depth=(b-a).length, location=(a+b)/2)
ob = adopt(bpy.context.object, name, mat)
ob.rotation_euler = (b-a).to_track_quat('Z', 'Y').to_euler()
for face in ob.data.polygons:
face.use_smooth = True
return ob
x, y = -36., 40.
ground = lambda x, y: -.024*y + .004*x + .12*math.sin(x*.19)*math.cos(y*.14) + .055*math.sin(x*.72+y*.32)
z = ground(x, y)
hub = z + 18.
box('foundation cap - indicative only', (x, y, z+.10), (2.1, 2.1, .30), concrete)
cone('tapered freestanding mast', (x,y,z+.25), (x,y,hub), .27, .13, steel)
cone('base flange', (x,y,z+.23), (x,y,z+.30), .42, .42, steel)
for i in range(8):
angle = i*math.tau/8
bx, by = x+.34*math.cos(angle), y+.34*math.sin(angle)
cone('anchor bolt %02d' % i, (bx,by,z+.3), (bx,by,z+.37), .025, .025, dark)
cone('nacelle', (x,y-.35,hub), (x,y+.7,hub), .24, .18, white)
cone('rotor hub', (x,y-.32,hub), (x,y-.73,hub), .23, .07, white)
cone('tail boom', (x,y+.45,hub), (x,y+2.0,hub), .055, .035, steel)
box('tail vane', (x,y+1.9,hub+.32), (.055,.8,.65), white)
# Three tapered swept blades, with closed airfoil-like cross sections.
for blade in range(3):
angle = blade*math.tau/3
vs, faces = [], []
stations = [(.19,.10,0),(.55,.25,0),(1.1,.23,.04),(2.,.16,.13),(2.8,.08,.22),(3.,.025,.25)]
for r, halfwidth, sweep in stations:
for tangent, depth in [(-halfwidth,0),(0,-.055),(halfwidth,0),(0,.045)]:
t = tangent+sweep
vs.append((x+t*math.cos(angle)+r*math.sin(angle), y-.48+depth,
hub-t*math.sin(angle)+r*math.cos(angle)))
for j in range(len(stations)-1):
for k in range(4):
faces.append((4*j+k,4*j+(k+1)%4,4*(j+1)+(k+1)%4,4*(j+1)+k))
faces.extend([(3,2,1,0),tuple(range(len(vs)-4,len(vs)))])
mesh = bpy.data.meshes.new('WIND blade mesh')
mesh.from_pydata(vs, [], faces)
mesh.update()
ob = bpy.data.objects.new('WIND - rotor blade %d' % (blade+1), mesh)
coll.objects.link(ob)
mesh.materials.append(white)
for face in mesh.polygons:
face.use_smooth = True
box('lockable isolation cabinet - indicative', (x+.72,y,z+.92), (.45,.3,.65), dark)
cone('service conduit', (x+.72,y,z+.1), (x+.72,y,z+.63), .045,.045,steel)
# Exact low-poly display copies keep the lightweight viewport aligned.
bpy.context.view_layer.update()
for ob in list(coll.objects):
proxy = ob.copy()
proxy.data = ob.data.copy()
proxy.name = 'FAST | ' + ob.name
fast.objects.link(proxy)
proxy.hide_render = True
tour = bpy.data.collections['22 PLAY - guided camera tour']
cam = bpy.data.objects['PLAY TOUR camera']
title = '32 / WIND POWER - PROPERTY CONCEPT'
for frame, position in [(3721,(-57,66,25)),(3840,(-54,62,24))]:
s.frame_set(frame)
cam.location = position
cam.rotation_euler = (Vector((x,y,hub*.57))-cam.location).to_track_quat('-Z','Y').to_euler()
cam.keyframe_insert('location', frame=frame)
cam.keyframe_insert('rotation_euler', frame=frame)
cam.data.lens = 38
cam.data.keyframe_insert('lens', frame=frame)
ref = next(o for o in tour.objects if o.type=='FONT' and o.data.body.startswith('31 /'))
ref.scale = (0,0,0)
ref.keyframe_insert('scale', frame=3721)
caption = ref.copy()
caption.data = ref.data.copy()
caption.animation_data_clear()
tour.objects.link(caption)
caption.name = 'Tour caption 32 - wind turbine concept'
caption.data.body = title
caption.location = (-36/38*.91,36/38*9/16*.84,-2)
for frame, value in [(1,0),(3720,0),(3721,1),(3840,1)]:
caption.scale = (value,value,value)
caption.keyframe_insert('scale', frame=frame)
for ob in (ref,caption):
for layer in ob.animation_data.action.layers:
for strip in layer.strips:
for bag in strip.channelbags:
for curve in bag.fcurves:
for key in curve.keyframe_points:
key.interpolation = 'CONSTANT'
s.frame_end = 3840
s.timeline_markers.new(title, frame=3721)
s['Wind turbine concept'] = 'v009: three-blade freestanding turbine at (-36,40); 18 m hub / 6 m rotor are visual placeholders. No measured wind resource, selected product, yield, engineering or approvals.'
s['PLAY THE TOUR'] = 'Hover over the 3D view and press Space. 32 chapters, 2 min 40 sec. Shift+Left Arrow restarts. Wind turbine: chapter 32.'
text = bpy.data.texts.get('START HERE - PRESS PLAY')
if text:
text.write('\n\n'+s['PLAY THE TOUR']+'\n'+s['Wind turbine concept'])
# A separate overview camera leaves all existing inspection chapters intact.
camera_data = bpy.data.cameras.new('Wind property overview')
overview = bpy.data.objects.new('Wind property overview', camera_data)
s.collection.objects.link(overview)
overview.location = (-85,90,60)
overview.rotation_euler = (Vector((-5,5,4))-overview.location).to_track_quat('-Z','Y').to_euler()
camera_data.type = 'ORTHO'
camera_data.ortho_scale = 108
camera_data.clip_end = 1000
s.frame_set(3721)
s.camera = cam
detail.hide_viewport = True
fast.hide_viewport = False
s.render.resolution_x, s.render.resolution_y = 2560, 1440
s.render.resolution_percentage = 100
bpy.ops.wm.save_as_mainfile(filepath=str(output))
if args.render:
s.camera = overview
for ob in tour.objects:
if ob.type == 'FONT':
ob.hide_render = True
detail.hide_viewport = False
fast.hide_viewport = True
s.render.engine = 'CYCLES'
s.render.resolution_percentage = 60
s.cycles.samples = 32
s.cycles.use_denoising = True
prefs = bpy.context.preferences.addons['cycles'].preferences
prefs.compute_device_type = 'METAL'
prefs.get_devices()
for device in prefs.devices:
device.use = device.type == 'METAL'
s.cycles.device = 'GPU'
s.render.filepath = str(Path(args.render).resolve())
bpy.ops.render.render(write_still=True)
print('WIND_REVISION_SAVED', output, flush=True)

View File

@@ -0,0 +1,19 @@
{
"AGENTS.md": "f20c3f60e3d8d27b5d4d89a99ebff9e8a23499530f836263ece51d9f806a009f",
"README.md": "2d6e86ac8a38799f984bc95e055df7bd1fcc0d58c7078dbf276b2eb9b08c8801",
"docs/PROJECT-CONTEXT.md": "f44ba333fcf5a6955cd35f281c21677e7c732ea67956e52ea643d2e2349bca95",
"docs/REQUEST-HISTORY.md": "555ec31c40f80a04ee0d24db0fcc766768d66e91a7f692a6b70f9eab2c1d28a7",
"decisions/2026-09-24-v009-wind-turbine.md": "26118e95b1fe9f716bb3a7ed6e7df8c31eff2fcb038500f2b4e6c81e1ec5e228",
"blender/samford-solarpunk-wind-tour-v009.blend": "a02c3898da7f2e385a0a57b5610c0b1035997116f747919a46cebfed8cd12c8a",
"blender/samford-solarpunk-wind-tour-v009.verification.json": "48f5a3909abecb42fcde45efc5800b94f749d00902af2e973d87c10db298f3af",
"blender/wind-turbine-layout-v009.json": "3e9d06c55ff24bdce810b33d1942fde9f082cf8bd24b46f24126abc3000e4dab",
"blender/tour-chapters-wind-v009.json": "378b08b048d8c480772c76bc7a141cbede17c531b919658130b033edacd2d735",
"plans/concept/wind-turbine-plan-v009.svg": "d4e7cf9aad22559f61f123f37775315934a06f3769198099062a756f4c379107",
"renders/v009-wind-overview.png": "1aa727e37a263eed860718c758624af416f0a094aac7ca6368e4a555851b60e8",
"site/samford-valley-home/index.html": "7cbd30f42a4e23a5d9d5bdb939c1beec20c5dd9d8dfe697e607b8099e9d3bade",
"site/metadata/sitemap.xml": "6af5dec5ef6d887c751becc9549970e7251fce6e164037f3d80da02ecda63c27",
"site/metadata/llms.txt": "5810cb29ffa7f9b1521babb3cedf1a7b8a95cd5af5f66e3072ef466489cdc9ed",
"source/samford-v009-wind/add_wind_turbine.py": "c1e9b7112473b888d6f5d34c137f8e166be7e4dc0679d2e0074f37a822b326cb",
"source/samford-v009-wind/verify_wind_turbine.py": "ef54260f1c66079f59af06a551bf077f14af1fa5da3311eefcb83297e5b58c71",
"source/samford-v009-wind/README.md": "fc9f6f3f18686445fe270808bf3a4db479f8b7292168ea11a4b626ed63835fb0"
}

View File

@@ -0,0 +1,42 @@
"""Reopen either saved v009 scene and validate geometry, preservation and tour."""
import bpy
import json
from pathlib import Path
s = bpy.context.scene
detail = bpy.data.collections['DETAIL - full geometry for renders']
detail.hide_viewport = False
bpy.context.view_layer.update()
objects = bpy.data.collections['39 WIND - property turbine concept'].objects
assert len([o for o in objects if o.name.startswith('WIND - rotor blade')]) == 3
mast = bpy.data.objects['WIND - tapered freestanding mast']
assert abs(mast.location.x + 36) < .001 and abs(mast.location.y - 40) < .001
assert abs(mast.dimensions.z - 17.75) < .001
assert all('FAST | '+o.name in bpy.data.objects for o in objects)
assert all(bpy.data.objects['FAST | '+o.name].hide_render for o in objects)
assert len(bpy.data.collections['24 LATER - Shadow spaces only'].objects) == 26
required = ['ISLAND - honed marble countertop', 'FAST | Garden Buddha statue',
'CONTAINER WATER - steel base frame', 'Living woven jute rug',
'Fuller garden borders - curved lanceolate leaves']
assert all(name in bpy.data.objects for name in required)
assert not any('table tennis' in o.name.lower() for o in s.objects)
assert all(m in bpy.data.materials.values() for o in s.objects if o.type=='MESH' for m in o.data.materials if m)
fonts = [o for o in bpy.data.collections['22 PLAY - guided camera tour'].objects if o.type=='FONT']
captions = []
for frame in range(1,3841,120):
s.frame_set(frame+20)
visible = [o.data.body for o in fonts if o.scale.length > .5]
assert len(visible)==1, (frame,visible)
captions.extend(visible)
assert captions[-1].startswith('32 / WIND') and captions[-2].startswith('31 /')
assert s.frame_end == 3840
assert s.camera.name == 'PLAY TOUR camera'
report = dict(status='PASS', model=Path(bpy.data.filepath).name,
turbine_objects=len(objects), rotor_blades=3, hub_height_m=18,
rotor_diameter_m=6, concept_xy=[-36,40], tour_chapters=32,
tour_seconds=160, captions=captions, preserved_features=required,
future_outline_objects=26, material_references_valid=True,
dimensions_status='Illustrative placeholders, not engineered')
target = Path(bpy.data.filepath).with_suffix('.verification.json')
target.write_text(json.dumps(report,indent=2)+'\n')
print('WIND_VERIFIED',target,flush=True)