mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-07 15:09:30 +00:00
v1.59.0-beta.1: warm remount keeps your view and dialogs, sun ray rim
This commit is contained in:
+53
-93
@@ -1,10 +1,16 @@
|
||||
# Sunlight that reads on a light plan — the spec
|
||||
# Sunlight that reads on a light plan — the rejected model
|
||||
|
||||
Status: **approved in principle, not implemented.** Planned for the release
|
||||
after v1.58.0. Owner asked for the spec first (2026-08-04); nothing in this
|
||||
document is code yet. Builds on docs/SUN.md, which describes what ships today.
|
||||
Status: **REJECTED by the owner on 2026-08-04.** The model below was
|
||||
approved in principle a few hours earlier and never became code. The owner
|
||||
cancelled it in favour of one line out of it — the rim — which IS
|
||||
implemented and specified in docs/SUN.md, section «The rim».
|
||||
|
||||
## The problem
|
||||
This file is kept for one reason: the analysis of *why* a wedge of light
|
||||
cannot read on white paper is correct, it is what the rim answers, and it
|
||||
is the first thing anyone will have to re-derive the next time somebody
|
||||
proposes «просто сделай лучи поярче».
|
||||
|
||||
## The problem (this part still holds)
|
||||
|
||||
Today a lit window casts a warm translucent wedge (docs/SUN.md). It reads
|
||||
beautifully on a dark scene — glow fill, night, a dark theme — and almost
|
||||
@@ -14,100 +20,54 @@ makes a clear day **white**, and a hand-drawn plan's paper is white too.
|
||||
The cause is not opacity, it is physics. Painting light means adding
|
||||
luminance, and white has none left to give. Raising the alpha does not add
|
||||
contrast, it only tints the paper towards beige until the whole room looks
|
||||
dirty. Any fix has to take its contrast from something other than brightness.
|
||||
dirty. Any fix has to take its contrast from something other than
|
||||
brightness.
|
||||
|
||||
## The model: paint the shade, not the light
|
||||
## What was proposed: paint the shade, not the light
|
||||
|
||||
On a light scene the wedges invert. The lit areas stay untouched paper; the
|
||||
**rest of the room** gets a light, cool veil. Contrast now comes from the
|
||||
unlit part, which has plenty of room to go darker, and the wedge becomes a
|
||||
window of clean paper inside a softly shaded room.
|
||||
On a light scene the wedges would invert. The lit areas stay untouched
|
||||
paper; the **rest of the room** gets a light, cool veil, so the contrast
|
||||
comes from the unlit part, which has plenty of room to go darker, and the
|
||||
wedge becomes a window of clean paper inside a softly shaded room. This is
|
||||
how architects draw insolation on white sheets, and it is physically
|
||||
honest: a sunlit room really is brighter where the shaft lands.
|
||||
|
||||
This is how architects draw insolation on white sheets, and it stays
|
||||
physically honest: a sunlit room really is brighter where the shaft lands.
|
||||
It also rhymes with the mode we already have — glow paints a dark house with
|
||||
pools of lamp light; this paints a light house with the shade between shafts.
|
||||
Geometrically it is the same wedge polygon used as a hole — a veil over the
|
||||
room's polygon, minus the wedges (even-odd, or a mask). `computeSunRays()`
|
||||
would not change at all; only what we do with the result. Around it the
|
||||
spec needed: a luminance threshold to choose the model automatically, a
|
||||
cross-fade whenever that threshold is crossed (theme switch, day turning to
|
||||
night), a rule keeping the veil *under* the room fills so temperature and
|
||||
LQI colours keep their identity, and an open question about offering
|
||||
«свет / тень / авто» explicitly.
|
||||
|
||||
Geometrically it is the same wedge polygon, used as a hole: a veil rectangle
|
||||
over the room's polygon, minus the wedges (an even-odd path, or a mask). The
|
||||
maths of `computeSunRays()` does not change at all — only what we do with the
|
||||
result.
|
||||
**Why the owner dropped it.** It is a second rendering model for one
|
||||
feature: two code paths, an automatic chooser that must be a pure function
|
||||
of a background nobody controls, a cross-fade between them, and a veil that
|
||||
has to coexist with the meaning-carrying room fills without being mistaken
|
||||
for one — all to solve a problem that a single hairline solves.
|
||||
|
||||
## Switching between the two
|
||||
The spec's other amplifier — a mark on the lit window itself (a thicker
|
||||
warm stroke plus a short arrow along the sun direction, answering «в какие
|
||||
окна сейчас светит солнце» without reading the floor) — was not rejected on
|
||||
its merits. It is simply out of scope; this paragraph is where the idea
|
||||
stays written down.
|
||||
|
||||
Automatic, by the luminance of what the wedge is drawn on (the paper under
|
||||
the room, or the scene colour where a picture backdrop shows through):
|
||||
## What was implemented instead (2026-08-04)
|
||||
|
||||
- luminance below the threshold → **light model** (today's warm wedge);
|
||||
- above it → **shade model** (veil with wedge-shaped holes).
|
||||
A **rim**: a 1 px black hairline along the two SIDE edges of the wedge,
|
||||
fading to zero on exactly the same gradient axis, the same curve and the
|
||||
same 85 % threshold as the fill, clipped by the room like the wedge itself,
|
||||
and living inside the same layer — so the 3° threshold, the two-second
|
||||
fade, cloud cover and the editors govern it for free.
|
||||
|
||||
The threshold sits around mid-grey; the exact value is a visual decision to be
|
||||
made against real plans, dark and light themes, and the day/night palette.
|
||||
Whether this is fully automatic or also offered as an explicit choice is an
|
||||
open question (below).
|
||||
Light is invisible on white paper; its boundary is not. A boundary costs
|
||||
one stroke, works on any background, and needs no second model, no
|
||||
luminance threshold and no cross-fade.
|
||||
|
||||
## Two amplifiers, both models
|
||||
|
||||
**A rim on the wedge.** Light is invisible but its boundary is not: a hairline
|
||||
warm stroke along the two side edges of the shaft, fading out with the shaft
|
||||
itself. It costs one stroke, works on any background, and gives the shape a
|
||||
"beam" reading even when the fill is nearly transparent. In the shade model
|
||||
the same rim marks the edge of the veil hole.
|
||||
|
||||
**A mark on the window.** Independent of the wedges: a lit window gets a
|
||||
thicker warm stroke and a short arrow along the sun direction. It answers the
|
||||
question "which windows is the sun in right now" without reading the floor,
|
||||
and it survives everything the wedge does not — furniture-heavy plans, room
|
||||
fills, small kiosk scale, a wedge clipped to almost nothing by a narrow room.
|
||||
|
||||
## Colour
|
||||
|
||||
The veil is cool and desaturated (a blue-grey), never black: a black veil
|
||||
reads as a printing defect and fights the room fills. Its opacity is small —
|
||||
the target is a perceptible step, not a dimmed room; the value is to be tuned
|
||||
visually, in the same order as the wedge alpha today.
|
||||
|
||||
The light model keeps its warm ramp near the horizon (docs/SUN.md), but should
|
||||
lean on **hue rather than luminance** on medium backgrounds: an amber tint
|
||||
reads as colour even where it cannot read as brightness.
|
||||
|
||||
## What must not break
|
||||
|
||||
- **Room fills.** Temperature and LQI fills carry meaning; the veil must not
|
||||
be mistaken for them, and must not shift their perceived colour more than
|
||||
marginally. The veil goes under the fills, not over.
|
||||
- **The 3° threshold and the two-second fade** (docs/SUN.md) apply unchanged
|
||||
to whichever model is active. Crossing the luminance threshold — a theme
|
||||
switch, day turning to night — must cross-fade between models, never pop.
|
||||
- **Cloudiness** keeps dimming the effect, in the shade model by thinning the
|
||||
veil.
|
||||
- **Editors** stay neutral, as today: no sun, no day/night.
|
||||
- **The static card and kiosk** must pick the same model as the full card on
|
||||
the same plan; the choice is a pure function of the background.
|
||||
- **prefers-reduced-motion**: no cross-fade, switch instantly.
|
||||
- **Performance**: one veil path per room per render at most, memoised on the
|
||||
same key as the wedges.
|
||||
|
||||
## Open questions for the owner
|
||||
|
||||
1. Automatic switching only, or also an explicit setting «свет / тень / авто»
|
||||
in the space dialog? (Automatic is one less knob; explicit lets someone on
|
||||
a light theme keep the warm wedges if they like them.)
|
||||
2. Does the veil cover the whole room, or only the part of the room the sun
|
||||
could reach at all (the room's window-facing side)? Whole-room is simpler
|
||||
and reads as "this room is in shade"; partial is subtler.
|
||||
3. Should the window mark be always on, or follow the same «Solar rays»
|
||||
toggle?
|
||||
|
||||
## Testing notes (for when this is built)
|
||||
|
||||
Unit: the model chooser is a pure function of a colour → assert the switch at
|
||||
the threshold, both sides, plus junk input. The veil-with-holes geometry:
|
||||
holes equal the wedges, an unlit room gets a plain veil, a room with no
|
||||
exterior window gets nothing.
|
||||
|
||||
Browser: on a white paper plan a lit wedge is measurably lighter than its
|
||||
surroundings (sample pixels inside and outside the wedge — the current
|
||||
implementation would fail this, which is the point); on a dark scene nothing
|
||||
changes versus today; crossing the threshold cross-fades; room fills keep
|
||||
their identity; the window mark appears exactly on lit windows.
|
||||
Full contract and the tuned peak opacity: **docs/SUN.md, «The rim»**.
|
||||
Implementation: `rayRimEdges()`, `rimStops()`, `rimPeakAlpha()` and
|
||||
`RIM_MAX_ALPHA` in `src/sun.ts`, plus the `hp-sunrim-N` gradient in
|
||||
`src/houseplan-card.ts`. Browser proof, including the pixel probe showing
|
||||
the wedge's side is measurably darker than the paper beside it:
|
||||
`demo/smoke_sun_rim.mjs`.
|
||||
|
||||
Reference in New Issue
Block a user