You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This leaves the sunlight implementation alone, since it already ignored furniture. Now furniture also gets ignored and light gets just drawn on top.
I think this is not the best option, I think on the long run it should mask out furniture exactly. And then also use this mask on the sunlight layer, since sunlight and normal lamp light should not differ.
Updates furniture light masks to follow each symbol’s geometry, improving lighting for non-rectangular furniture.
Changes:
Adds fill-color overrides for symbol rendering.
Renders furniture masks from symbol geometry.
Updates regression tests and authoring guidance.
File
Summary and final review findings
src/symbols.ts
Supports fill-color overrides. Moderate (1 vote): Preserve none when applying color overrides. Moderate (1 vote): Use fillC in the path template so path-based shapes honor overrideFill.
src/render.ts
Renders furniture glow masks from symbol geometry. Moderate (3 votes): Handle overrideOp: 0 correctly. Nit (2 votes): Fix fo to of. Moderate (2 votes): Avoid filling open paths unless they contain Z. Moderate (1 vote): Preserve or update the documented footprint contract. Moderate (1 vote): Suppress or attenuate mask strokes.
src/render.test.ts
Updates glow-mask expectations. Moderate (3 votes): Add sectional/L-shaped geometry assertions that verify the notch rather than only the transform and primitive type.
furniture/README.md
Documents closed-shape requirements. Nit (1 vote): Replace correct displaying with clearer wording such as the lighting mask to display correctly.
- Honor overrideOp: 0 (was skipped by a truthiness check).
- Only closed geometry dims in the mask: an open path's fill was
implicitly closing in SVG and smearing a wedge the glyph never draws.
- Let a sealed path carry overrideFill; unsealed paths keep fill="none".
- Update the stale renderGlowMask docs and test the sectional's L notch.
Honor zero opacity overrides — if (overrideOp) → overrideOp !== undefined, so 0 is applied rather than skipped.
No filling open paths — the mask only dims sealed, closed geometry (rect/circle/ellipse, closed polygon, path sealed with Z). partTemplate also renders an unsealed path as fill="none", so the tub's rim and a stair's rail block only their strokes instead of smearing a wedge the glyph never draws. (Behavior for all built-in symbols' normal rendering is unchanged — verified against the furniture JSONs.)
Geometry regression coverage — added a test asserting the sectional's L polygon reaches the notch vertex 18.4, which the old bounding-box mask could never produce; also rewrote the now-misnamed "footprint" test, which was passing for the wrong reason.
Comment typo + docs — fixed fo → of, added a doc comment to renderFurnitureMask, and updated renderGlowMask's stale "rect/ellipse footprint" docstring to describe the symbol-geometry mask (Light is not correctly drawn onto couch #248).
One finding I deliberately did not change: "suppress/attenuate mask strokes". Line art in the mask blocks light at full strength under the stroke while the body blocks 0.5 × — the screenshots in this PR show that look, it matches the furniture's own line art drawn above the glow, and making it uniform would need a stroke-opacity override for a purely cosmetic gain. Happy to switch if you disagree.
Verified locally: typecheck, full vitest suite (1676 passed), and vite build.
The sealed-path fill logic in partTemplate changed ordinary furniture
rendering, not just the mask: a custom symbol with a filled open path
used to render its fill and silently lost it. The mask never needed it
either - renderFurnitureMask already limits its dim to closed geometry.
Revert partTemplate to fill=${fill} and keep all mask decisions in
closedGeometry.
closedGeometry checks the last path command now: SVG fills an open
subpath by closing it implicitly, so a path like "M .. Z M .." must
count as open or it still smears a wedge.
Document that SymbolDef.footprint is parsed but unused by the mask.
Three things Copilot caught on the mask geometry:
`closedGeometry` read only the last command, so `M … M … Z` passed as
sealed while its first subpath was still open — SVG closes that one
implicitly and fills it. Walk the commands instead and reject a fresh
`M` while a subpath is open.
An open path with a filled role (`body`, `solid`, an explicit
`fillOpacity`) still reached `partTemplate` with a fill, so the mask
painted the black wedge the closed-geometry check was meant to prevent.
The mask now zeroes those parts' fill opacity, which leaves ordinary
furniture rendering untouched.
The mask group carried `data-id`/`data-entity`. Those are card-mod's
styling hooks, and this group is mask *source* geometry: an unscoped
`[data-entity="light.kitchen"] { filter: … }` would repaint the mask
and bend the pool it cuts. They stay on `renderFurniture` only.
The L-notch assertion now parses the polygon coordinate instead of
matching float printing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This predicate only checks whether the primitive is geometrically closed, so it turns every closed outline/detail into a filled mask area. That overrides the symbol role contract: for example, stove.json's burner circles and toilet.json's bowl ellipse use line, and custom parts may explicitly set fillOpacity: 0; the mask will now dim their interiors instead of only their strokes. Preserve the original fill intent when deciding whether a closed part should be filled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements option (b) from #248
This leaves the sunlight implementation alone, since it already ignored furniture. Now furniture also gets ignored and light gets just drawn on top.
I think this is not the best option, I think on the long run it should mask out furniture exactly. And then also use this mask on the sunlight layer, since sunlight and normal lamp light should not differ.