Sunlight House Lab is a compact Python project for exploring direct sunlight inside a simple rectangular room.
Public live app: https://sunlight-house-project.onrender.com/
It includes:
- a small Flask app for interactive exploration
- a CLI demo that regenerates example plots
- a lightweight solar and geometry model that stays intentionally narrow
The current app is designed around editable wall windows on a rectangular room. The room stays axis-aligned internally, and the selected compass facing rotates the room relative to the real-world sun.
- computes solar elevation and azimuth from latitude, longitude, local datetime, and timezone
- models a rectangular room with one or more wall windows
- projects direct sunlight from each window onto the floor
- renders a top-down room snapshot for a selected moment
- renders an interactive, orbitable 3D room with live window and sunlight geometry
- estimates daily direct-sun-hours exposure across the floor
- estimates yearly and seasonal floor exposure using representative-day sampling
- imports one rectangular room and nearby windows from an IFC file
- exposes the model through a Flask web UI suitable for local use or Render deployment
The default scenario is a Melbourne daylight demo moment: 2025-01-15 10:00 in Australia/Melbourne. This keeps the first load visually useful even when the real current time is after sunset. Use the Now button to jump to the current time in the selected timezone.
Default room and window values:
- location:
Melbourne, Australia - timezone:
Australia/Melbourne - window facing:
NE - room:
4.0 mwidth,5.0 mdepth,3.0 mceiling - Window 1: front wall, centre from left
3.0 m, sill0.1 m, width1.5 m, height2.0 m - Window 2: right wall, centre from left
2.8 m, sill0.1 m, width1.5 m, height2.0 m
The primary workflow is intentionally simple: choose a location, set the room and window geometry, then compare the current moment, today's direct-sun map, and the estimated yearly view. IFC import, custom maps, outdoor reference data, and baseline comparison are advanced tools.
The core solar calculations use a local East-North-Up frame:
x: easty: northz: up
Solar azimuth is measured clockwise from north:
0 deg= north90 deg= east180 deg= south270 deg= west
Solar elevation is measured above the horizon:
0 deg= horizon90 deg= overhead
The sun vector uses:
x = cos(elevation) * sin(azimuth)
y = cos(elevation) * cos(azimuth)
z = sin(elevation)Run locally:
PORT=5001 python3 app.pyThen open http://127.0.0.1:5001.
The app currently includes:
- preset locations for Melbourne, Jakarta, and Boston
- a custom location mode with draggable map marker
- manual latitude and longitude fields
- manual timezone override under a collapsible advanced section
- an 8-direction window-facing selector
- compact multi-window editing controls
- collapsible room geometry controls
- day-of-year and time-of-day scrubbers
- a
Nowbutton for the selected timezone - a
Current Momentroom snapshot - a lazy-loaded
3D roomview with real window openings, named window selection, compass/front indicators, camera-aware walls, orbit, zoom, pan, and camera reset - optional 3D details: an exterior door, sunlight-blocking internal divider and roof eaves, outside fence/building presets, and scale furniture
- cached 3D day playback with a time scrubber plus morning, solar-noon, and evening presets
- a
Direct Sun Hours Todayfloor map with legend, stats, and in-chart tooltip - a
Yearly / Seasonalfloor map withYear,Winter,Spring,Summer, andFall - an advanced IFC room/window import workflow
- a frontend-only baseline compare tool using
localStorage
Daily exposure uses the selected day with the configured day step.
Yearly and seasonal exposure are estimated rather than fully simulated. The current long-range method:
- chooses
8representative days per month - samples each representative day at the configured yearly step (1–12 hours; larger values can skip daylight)
- keeps only daylight hours where solar elevation is above the horizon
- weights each representative day by how many calendar days it stands in for
- renders long-range results on a coarser floor grid than the daily map
- aggregates into
Year,Winter,Spring,Summer, andFall
Season labels are hemisphere-aware:
- northern hemisphere:
- winter:
Dec-Feb - spring:
Mar-May - summer:
Jun-Aug - fall:
Sep-Nov
- winter:
- southern hemisphere:
- winter:
Jun-Aug - spring:
Sep-Nov - summer:
Dec-Feb - fall:
Mar-May
- winter:
Long-range maps should be treated as estimated planning views, not engineering-grade annual simulations.
Run:
python3 run_demo.pyThe demo regenerates example plots in outputs/ using the default Melbourne scenario.
sunlight_house_project/
├── app.py
├── README.md
├── render.yaml
├── requirements.txt
├── run_demo.py
├── outputs/
├── static/
│ ├── app.js
│ ├── room3d.bundle.js
│ ├── src/room3d.js
│ └── styles.css
├── templates/
│ └── index.html
├── tests/
│ ├── test_analysis.py
│ ├── test_app.py
│ └── test_config.py
└── sunlight_house/
├── __init__.py
├── analysis.py
├── config.py
├── geometry.py
├── ifc_import.py
├── insights.py
├── plotting.py
└── solar.py
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtThe model and API use Python's built-in unittest runner:
python3 -m unittest discover -s testsCritical UI interactions use Playwright so dragging, resizing, tabs, window selection, the interactive 3D room, WebGL fallback, and the laptop layout are exercised in a real browser:
npm install
npx playwright install chromium
PYTHON=./.venv/bin/python npm run test:browserThe repo includes render.yaml for a simple Python web service.
Render uses:
- build command:
pip install -r requirements.txt - start command:
python3 -m gunicorn app:app --bind 0.0.0.0:$PORT - health check path:
/healthz
- The geometry model is intentionally simple and axis-aligned.
- The web app exposes compact controls for multiple axis-aligned wall windows.
- IFC import uses bounding boxes and assumes the imported room is rectangular and axis-aligned. Verify the imported room bearing and windows before relying on the result.
- Internal walls, eaves, and the selected outside fence/building shade direct-sun calculations using sampled ray-box occlusion; doors and furniture remain visual-only context.
- The model does not include blinds, diffuse sky light, reflections, curved obstructions, vegetation, or detailed neighbouring-building geometry.
- Floor patches are generated from projected window corners and clipped into room bounds, so edge behavior is still a simplification.
- Outdoor conditions are historical 2025 reference data for Melbourne, Jakarta, and Boston; they are contextual samples rather than a live forecast.