Multi-select, select joined walls and fences, pond with swimming fish
Deploy web Studio / deploy (push) Successful in 1m27s
Deploy web Studio / deploy (push) Successful in 1m27s
Selection: S.sel stays the object picked last; S.selIds holds everything selected. - In the object list, Ctrl+click adds or removes an object and Shift+click selects a range. - On the map, Ctrl/Shift+click toggles an object and Shift+drag draws a box that selects what lies wholly inside it (locked and hidden objects are left out). - Ctrl+A selects everything that is not locked; Esc selects nothing. - Clicking a wall or fence a second time selects every piece of the same type joined to it; another click goes back to that one piece. - Dragging one selected object moves them all, together with the windows and doors on them, as one undo step. Arrow keys, R (turns the group about its middle), Ctrl+D, Delete, Lock and Hide all work on the whole selection. - When all selected objects share a type, the property form edits them all; fields where they differ show "mixed". - The agent's system prompt lists the selected objects. The viewer outlines several objects with selectObj([ids]) and passes the click event to onPick. A batch op now answers `ids`, one per operation, so the copies from a group duplicate get selected. Pond (Nature): natural, round or square, with a stone or grass edge, fish, lily pads, spreading ripples and reed clumps. The fish come from a new Swim primitive (script: s.swim). One matrix maps the object's frame to the screen. Each fish turns round its ellipse with a CSS rotation, so off-screen pausing and reduced motion apply as for the other animations. The house demo gets a koi pond in the back garden. Tests: ponds in every shape and rotation have the right number of fish, no NaN and no depth-sort cycles, and stay inside their rectangle. check_studio covers list and map multi-select, a group drag undone in one step, joined-fence selection, a mixed-value form applied to all, box select, delete and undo, Ctrl+A, Esc, and a new pond's fish.
This commit is contained in:
1 parent
e4017ce2a8
commit
19f4c83ae8
21 files changed
+759
-59
No files matched your search
@@ -49,3 +49,137 @@ fn prefab_hedge(o) {
|
||||
let p = o.p;
|
||||
sprite().box(-p.w / 2.0, -p.d / 2.0, p.w / 2.0, p.d / 2.0, 0.0, p.h, "hedge");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- pond
|
||||
|
||||
fn meta_pond() {
|
||||
#{ label: "Pond", category: "Nature", icon: "◍", shape: "rect",
|
||||
help: "A garden pond with fish swimming round under lily pads, reeds at the back and a stone or grass edge. Drag a rectangle on the map.",
|
||||
props: [
|
||||
#{ key: "w", type: "float", def: 6.0, min: 1.5, max: 60.0, step: 0.5, label: "Width (m)" },
|
||||
#{ key: "d", type: "float", def: 4.0, min: 1.5, max: 60.0, step: 0.5, label: "Length (m)" },
|
||||
#{ key: "shape", type: "choice", def: "natural", choices: ["natural", "round", "square"], label: "Shape" },
|
||||
#{ key: "fish", type: "int", def: 5, min: 0, max: 16, step: 1, label: "Fish" },
|
||||
#{ key: "lilies", type: "int", def: 3, min: 0, max: 12, step: 1, label: "Lily pads" },
|
||||
#{ key: "reeds", type: "bool", def: true, label: "Reeds" },
|
||||
#{ key: "edge", type: "choice", def: "stone", choices: ["stone", "grass"], label: "Edge" },
|
||||
] }
|
||||
}
|
||||
|
||||
/// The pond's outline inset by `ins` metres: a kidney ("natural"), an
|
||||
/// ellipse ("round") or a rectangle with round corners ("square").
|
||||
fn pond_outline(p, ins) {
|
||||
let a = p.w / 2.0 - ins;
|
||||
let b = p.d / 2.0 - ins;
|
||||
let pts = [];
|
||||
if p.shape == "square" {
|
||||
let r = fmax(0.05, fmin(a, b) * 0.35);
|
||||
for k in 0..4 {
|
||||
let cx = if k == 0 || k == 3 { a - r } else { -a + r };
|
||||
let cy = if k < 2 { b - r } else { -b + r };
|
||||
for j in 0..7 {
|
||||
let t = (k * 90 + j * 15) * PI() / 180.0;
|
||||
pts.push([cx + r * t.cos(), cy + r * t.sin()]);
|
||||
}
|
||||
}
|
||||
return pts;
|
||||
}
|
||||
for j in 0..48 {
|
||||
let t = j * PI() / 24.0;
|
||||
let k = 1.0;
|
||||
if p.shape == "natural" {
|
||||
// a dent at the back (+y) and a slight wobble, never past the box
|
||||
let dt = (t - PI() / 2.0) / 0.6;
|
||||
k = (1.0 - 0.3 * (-dt * dt).exp()) * (0.965 + 0.035 * (3.0 * t + 1.0).sin());
|
||||
}
|
||||
pts.push([a * k * t.cos(), b * k * t.sin()]);
|
||||
}
|
||||
pts
|
||||
}
|
||||
|
||||
fn prefab_pond(o) {
|
||||
let p = o.p;
|
||||
let a = p.w / 2.0;
|
||||
let b = p.d / 2.0;
|
||||
let rim = if p.edge == "stone" { fmin(0.35, fmin(a, b) * 0.18) } else { fmin(0.2, fmin(a, b) * 0.1) };
|
||||
layer("ground");
|
||||
let s = sprite();
|
||||
let outer = pond_outline(p, 0.0);
|
||||
let inner = pond_outline(p, rim);
|
||||
if p.edge == "stone" {
|
||||
s.flat([outer], 0.03, "capst t");
|
||||
// joints across the stone rim
|
||||
let segs = [];
|
||||
let step = if outer.len() > 30 { 2 } else { 1 };
|
||||
for j in range(0, outer.len(), step) { segs.push([outer[j][0], outer[j][1], inner[j][0], inner[j][1]]); }
|
||||
s.lines(segs, 0.031, "seam");
|
||||
} else {
|
||||
s.flat([outer], 0.02, "pondbank t");
|
||||
}
|
||||
s.flat([inner], 0.032, "pondw t");
|
||||
s.flat([pond_outline(p, rim + fmin(a, b) * 0.28)], 0.033, "ponddp t");
|
||||
// the water the fish keep to: an ellipse well inside, off the natural shape's dent
|
||||
let wa = (a - rim) * 0.72;
|
||||
let wb = (b - rim) * 0.72;
|
||||
let oy = if p.shape == "natural" { -0.12 * b } else { 0.0 };
|
||||
if p.shape == "natural" { wb *= 0.82; }
|
||||
let n = p.fish;
|
||||
for i in 0..n {
|
||||
let f = 0.45 + 0.55 * ((i * 37 + 11) % 10) / 10.0;
|
||||
let rx = wa * f;
|
||||
let ry = wb * f;
|
||||
let cx = 0.0;
|
||||
// long ponds: smaller rounds spread along the long side
|
||||
if rx > ry * 1.6 { cx = (((i * 53) % 9) / 8.0 - 0.5) * (rx - ry * 1.6) * 2.0; rx = ry * 1.6; }
|
||||
if ry > rx * 1.6 { ry = rx * 1.6; }
|
||||
let len = fmin(0.9, fmax(0.3, fmin(a, b) * 0.24)) * (0.85 + 0.1 * (i % 3));
|
||||
let dur = fmax(8.0, 2.0 * PI() * (rx + ry) / 2.0 / 0.32);
|
||||
s.swim(cx, oy, 0.036, [#{ rx: rx, ry: ry, dur: dur, delay: (i * 7.3) % dur, cw: i % 3 == 1, len: len,
|
||||
cls: ["koi", "koiw", "koig"][i % 3] }]);
|
||||
}
|
||||
// lily pads over the fish, some in flower; rings spreading where a fish came up
|
||||
for i in 0..p.lilies {
|
||||
let t = i * 2.4 + 0.7;
|
||||
let q = 0.35 + 0.4 * ((i * 29 + 3) % 10) / 10.0;
|
||||
let x = wa * q * t.cos();
|
||||
let y = oy + wb * q * t.sin();
|
||||
s.disc(x, y, 0.04, fmin(0.4, fmax(0.18, fmin(a, b) * 0.1)), "lily t");
|
||||
if i % 2 == 0 { s.disc(x + 0.08, y + 0.05, 0.05, 0.07, "lilyf t"); }
|
||||
}
|
||||
if n > 0 {
|
||||
for i in 0..fmin(3, n).to_int() {
|
||||
let t = i * 2.1 + 1.9;
|
||||
s.begin("a rip", `animation-delay:-${i * 1.7}s`);
|
||||
s.disc(wa * 0.5 * t.cos(), oy + wb * 0.5 * t.sin(), 0.04, fmin(0.6, fmin(a, b) * 0.15), "ripple");
|
||||
s.end();
|
||||
}
|
||||
}
|
||||
// reeds in clumps on the back edge, upright, so with the other sprites
|
||||
if p.reeds {
|
||||
layer("main");
|
||||
for t in [1.15, 1.95, 2.55] {
|
||||
let q = pond_outline(p, rim * 0.5 + 0.3);
|
||||
let j = ((t / (2.0 * PI())) * q.len()).round().to_int() % q.len();
|
||||
let c = q[j];
|
||||
// tapered blades leaning out from the clump, cattail heads on some
|
||||
let blades = [];
|
||||
let heads = [];
|
||||
for k in 0..7 {
|
||||
let x = c[0] + ((k * 37) % 7 - 3) * 0.04;
|
||||
let y = c[1] + ((k * 53) % 5 - 2) * 0.04;
|
||||
let h = 0.75 + ((k * 31) % 6) * 0.09;
|
||||
let lx = ((k * 17) % 7 - 3) * 0.06;
|
||||
let ly = ((k * 23) % 5 - 2) * 0.06;
|
||||
blades.push([[x - 0.06, y, 0.03], [x + 0.06, y, 0.03], [x + lx, y + ly, h]]);
|
||||
blades.push([[x, y - 0.06, 0.03], [x, y + 0.06, 0.03], [x + lx, y + ly, h]]);
|
||||
if k % 3 == 0 {
|
||||
let f = 0.62;
|
||||
let hx = x + lx * f;
|
||||
let hy = y + ly * f;
|
||||
heads.push([[hx - 0.035, hy, h * f], [hx + 0.035, hy, h * f], [hx + 0.035 + lx * 0.18, hy + ly * 0.18, h * (f + 0.18)], [hx - 0.035 + lx * 0.18, hy + ly * 0.18, h * (f + 0.18)]]);
|
||||
}
|
||||
}
|
||||
sprite().poly(blades, "reed t").poly(heads, "cattail t");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user