Diagonals: streets, walls, fences, hedges and house walls at any angle
Deploy web Studio / deploy (push) Successful in 1m5s

Object frames turn by any angle (quarter turns stay exact, so scenes along
the axes render byte for byte as before); a box in a turned frame is a
prism with its own corners. Rotation is kept as given (normalised to
0..360), no longer snapped to quarter turns.

Depth sort: sprites whose plan outline is not their box carry their convex
outline; when boxes overlap, an outline edge that separates two sprites
orders them. A long diagonal wall sorts right against both sides.

Joints (line_meet, end_cut, cut_box in util.rhai): where a piece off the
axes is involved, corners are mitred and T-junctions slanted; fences put a
corner post or pillar in its own sprite and mitre stone bases; Y joints let
the lowest id run through. Streets: every end part is a cut e + k*w, so
side streets come in at any angle (slanted sidewalk gaps), two streets meet
in a mitre with seam patches; fixes a curve's outer sidewalk that was
skipped when its kerb and back lines had different point counts.

Studio: runs and drags keep to x/y or snap to 45 degree diagonals, Ctrl
gives any angle; a road run turning 45 degrees gets a 45 degree curve;
Rotation is a number box. Streets demo: a diagonal lane with a hedge.
MCP guidance, SCRIPTING/README/ROADMAP.

Tests: Rust 76, Studio and web checks green.
This commit is contained in:
grabowski committed 2026-10-25 13:22:59 +07:00
1 parent c91d63663b
commit 96d472625f
18 files changed
+1051 -178

No files matched your search

+14 -1
View File
@@ -68,7 +68,8 @@ Each phase ends with tests, a Studio/viewer check in Edge, commit and push.
(hover preview) and move, turn, copy and delete with them, new parts land on the storey
shown, collapsible palette that scrolls on its own
- [x] `examples/house` (a furnished house built from parts), House demo in the web Studio
- [ ] Openings across two walls; diagonal walls; floor openings for stairs
- [x] Diagonal walls (any angle, mitred corners, windows and doors on them)
- [ ] Openings across two walls; floor openings for stairs
## Backlog (2026-10)
@@ -81,6 +82,8 @@ Each phase ends with tests, a Studio/viewer check in Edge, commit and push.
7. ~~Roundabouts~~ (done, see below)
8. Waypoint animation: a person or car moving along a path of waypoints
9. ~~Build your own house~~ (done, see above)
10. ~~Diagonal streets, walls, fences, hedges~~ (done, see below)
11. Wildlife and nature: deer, bushes, beehives and more
Done since: the middle mouse button only moves the camera; fences and site walls join like house
walls (`line_joint`); fence designs (mesh, wood, bars, half stone, cobble, brick with pillars);
@@ -119,6 +122,16 @@ apron (tree, grass or paved). A road run drawn corner by corner gets a curve in
meta `corner`). Tooltips list the streets each one meets. New `polyline` primitive (open paths, so
dashes run on round curves). `examples/streets`, Streets demo in the web Studio.
Diagonals: object frames turn by any angle (quarter turns stay exact, so scenes along the axes
draw as before, byte for byte). Roads, walls, fences, hedges and house walls run at any angle;
where a piece off the axes meets another, corners are mitred and T-junctions slanted
(`line_meet`, `cut_box`), fence corners get a post or pillar of their own, side streets come in at
a slant and open the sidewalk along them, two streets meet in a mitre. The depth sort orders
sprites whose plan outline is not their box by outline edges, so a long diagonal wall sorts right
against everything on either side. Studio: runs and drags keep to x or y or go diagonal at 45°
(Ctrl: any angle), a road run turning 45° gets a 45° curve, Rotation takes any angle. The
streets demo has a diagonal lane.
## Phase 2: richer editing
- [x] Interior prefabs (see Build your own house); a building `rooms` prop is still open
+38 -8
View File
@@ -66,7 +66,7 @@ shaded automatically by face direction.
| `objects_on(types, x, y, tol)` | … whose centre line (local x, length `p.w`) passes within `p.t / 2 + tol` of the point, with `u, v` = the point in their frame |
| `mount_of(o, hosts[, tol])` | the host o sits on (nearest centre line within `p.t / 2 + tol`, default 0.3 m, same height), with `u, v` = o's position in the host's frame; `()` if none |
| `mounted(h, types, hosts[, tol])` | the objects of `types` whose host is h, each with `u, v` |
| `frame(o)`, `frame(x, y, z, rot)` | draw in another frame from here on (a window draws in its wall's frame) |
| `frame(o)`, `frame(x, y, z, rot)` | draw in another frame from here on (a window draws in its wall's frame); `rot` is any angle in degrees (quarter turns stay exact) |
| `to_world(x, y)`, `to_local(x, y)`, `local_of(o, x, y)`, `world_of(o, u, v)` | between the current frame (or o's) and world plan coordinates |
| `vis(nx, ny)` | is a face with that outward normal turned to the viewer? |
| `dv(dx, dy, dz)` | screen vector of a world vector (CSS motion) |
@@ -122,6 +122,29 @@ depth sort needs. `fence` (designs `style`: mesh, wood, bars, half stone,
cobble, brick) and the site `wall` use it; `house_wall` has its own version
(`wall_ext`, house.rhai).
### Diagonal pieces
Objects turn by any angle (`rot` in degrees); a box drawn in a turned frame
becomes a prism with its own four corners. Where a piece off the axes is
involved, `line_meet(o, e, same, stops)` (util.rhai) replaces the rules above
for that end: `#{ kind, ext, k, ... }` with kind `axis` (every piece there
keeps to the axes: use the old rules, so such scenes draw as before),
`free`, `run` (in line), `corner` (a mitre on the bisector; `owner` draws a
fence's corner post) or `tee` (stop at the other's face). The end is
slanted: the line `v` to the piece's left reaches `ext + k * v` past it.
`end_cut(w, e, m)` turns that into `#{ x, k }` and `s.cut_box(x0, k0, x1, k1,
y0, y1, z0, z1, mat[, opts])` draws a box with such ends. Fences put their
corner post (or brick pillar) in its own sprite and stop their panels at it;
stone bases and cobble walls are mitred. Helpers: `on_axes(rot)`,
`dir_of(o)`, `dot2(a, b)`.
The depth sort keeps diagonal pieces right through outlines: a sprite whose
plan outline is not its box (turned or mitred pieces) carries its convex
outline, and when two boxes overlap an outline edge that separates them
orders them, the one on the viewer's side going later. A long diagonal wall
therefore sorts right against everything on either side of it, and mitred
pieces against each other.
## Production lines
`producer`, `conveyor` and `robot_arm` (stdlib/industry.rhai) work together
@@ -166,12 +189,16 @@ ground.rhai) meet by their centre lines:
arcs when cut and offset, so a curve meets a straight road exactly.
- End to end (a curve continuing a road, a road continuing a roundabout arm)
the pieces carry on, overlapping by 4 cm so no hairline shows.
- A street ending on a road's centre line makes a T: the road leaves a gap in
its kerb and sidewalk on that side, the street stops its centre line and
kerbs at the road's edge and its sidewalks at the road's sidewalk.
- Two roads ending at one point at right angles close the corner: both run
over it, the inner sidewalks stop at the other road's kerb, the outer ones
go round.
- A street ending on a road's centre line makes a T, at any angle: the road
leaves a gap in its kerb and sidewalk on that side (slanted along the
street coming in), the street ends its asphalt on the road's centre line,
its centre line and kerbs at the road's edge and its sidewalks at the
road's sidewalk.
- Two streets ending at one point at any angle meet in a mitre on the
bisector (thin seam patches reach over it, so no hairline shows).
- Every part of a street end is a cut `#{ e, k }`: the line `w` to the left
looking out reaches `e + k * w` past the end (`street_join`); gaps are
`#{ lo, hi, c }` ranges that slant with the side offset (`street_gaps`).
- A roundabout's arms end `r + arm_len` from its centre, along its local
+x, +y, -x, -y. Its kerbs flare into the ring with a fillet; splitter
islands and give-way lines sit on the entry side for `drive` left or right.
@@ -220,7 +247,10 @@ These are lessons from the CNX/Mooban views, and the engine relies on them:
the same sprite as the storey below. Start walls and furniture standing on
them a little above the floor (+0.02 m).
- **Movers** (`drive`) run along the axis the sort compares second
(`along_x()`). Along the other axis they stay still.
(`along_x()`). Along the other axis (and on diagonals) they stay still.
- **Diagonal pieces** sort by their outlines (see Diagonal pieces), so they
need no extra splitting; things standing exactly on a wall's line still
interpenetrate it and sort by their centres.
- Street furniture stays off drive areas, and pipe runs end on walls or supports.
## Themes