Deploy web Studio / deploy (push) Successful in 3m27s
House parts (stdlib isokit/house): house_wall drawn along a line, with ends that adapt at corners, T-junctions and straight runs so no two walls overlap; window and door that sit on a wall and cut its opening (door styles panel, glass, double, sliding, opening; swing and hinge by rotation); floor (boards, tiles, carpet, stone); roof (hip, gable, flat, optional solar); stairs. Furniture (stdlib isokit/furniture): chair, sofa / armchair, table with chairs, desk with monitor and chair, TV, bed, cupboard, bookshelf, kitchen run, bathtub, shower, toilet, washbasin, plant, rug, floor lamp. Cut-open levels: on gf / 1f the walls in front of a room are cut low (rooms are found by their floors), the roof becomes an outline on the floor, and storeys above are left out. A part's storey comes from z (storey_h, default 3 m). Scripting: objects_of, objects_at, objects_on, mount_of, mounted, frame, to_world, to_local, local_of. Prefab meta: shape (line / rect), mount, storey. Studio: drag to draw lines and rectangles (walls, roads, fences, hedges, floors, areas, buildings, roofs). The Room tool draws a floor plus walls, without doubling walls that already stand on an edge. Windows and doors snap onto walls with a hover preview, and they move, turn, copy and delete with their wall in one undo step. New parts land on the storey the view shows. Palette categories collapse, and the palette scrolls apart from the object list. The MCP instructions explain house building, and list_prefabs shows sits_on. examples/house is a furnished bungalow; the web Studio gets a House demo button. Tests: wall corners and junctions, zero depth-sort cycles in every view, cut levels, and the house demo in every view; check_studio covers the room / window / door / storey flow, check_web the House demo.
155 lines
5.9 KiB
Plaintext
155 lines
5.9 KiB
Plaintext
// isokit/ground: site plate, paved and green areas, roads, parking, walls,
|
|
// fences and lamps. Ground surfaces go to the unsorted "ground" layer in
|
|
// document order (later objects lie on top).
|
|
|
|
fn ground_materials() {
|
|
["g-grass", "g-grass2", "g-green", "g-garden", "g-asph", "g-conc", "g-pad", "g-path", "g-sand", "g-court", "dirt"]
|
|
}
|
|
|
|
fn meta_site() {
|
|
#{ label: "Site ground", category: "Ground", icon: "▭", shape: "rect",
|
|
help: "The ground plate: a surface with earth sides. Frames the view.",
|
|
props: [
|
|
#{ key: "w", type: "float", def: 60.0, min: 4.0, max: 1000.0, step: 1.0, label: "Width (m)" },
|
|
#{ key: "d", type: "float", def: 40.0, min: 4.0, max: 1000.0, step: 1.0, label: "Depth (m)" },
|
|
#{ key: "mat", type: "material", def: "g-grass", choices: ground_materials(), label: "Surface" },
|
|
#{ key: "base", type: "float", def: 1.6, min: 0.2, max: 10.0, step: 0.1, label: "Earth depth (m)" },
|
|
] }
|
|
}
|
|
fn prefab_site(o) {
|
|
let p = o.p;
|
|
let w = p.w / 2.0;
|
|
let d = p.d / 2.0;
|
|
layer("ground");
|
|
sprite().box(-w, -d, w, d, -p.base, 0.0, "dirt", #{ top: p.mat });
|
|
bounds(-w, -d, w, d, -p.base);
|
|
}
|
|
|
|
fn meta_area() {
|
|
#{ label: "Area", category: "Ground", icon: "▱", shape: "rect",
|
|
help: "A paved or planted area lying on the ground.",
|
|
props: [
|
|
#{ key: "w", type: "float", def: 10.0, min: 0.5, max: 1000.0, step: 0.5, label: "Width (m)" },
|
|
#{ key: "d", type: "float", def: 6.0, min: 0.5, max: 1000.0, step: 0.5, label: "Depth (m)" },
|
|
#{ key: "mat", type: "material", def: "g-conc", choices: ground_materials(), label: "Surface" },
|
|
] }
|
|
}
|
|
fn prefab_area(o) {
|
|
let p = o.p;
|
|
layer("ground");
|
|
let s = sprite();
|
|
if o.pts != () && o.pts.len() >= 3 {
|
|
s.flat(o.pts, 0.006, p.mat + " t");
|
|
} else {
|
|
s.flat(rect(-p.w / 2.0, -p.d / 2.0, p.w / 2.0, p.d / 2.0), 0.006, p.mat + " t");
|
|
}
|
|
}
|
|
|
|
fn meta_road() {
|
|
#{ label: "Road", category: "Ground", icon: "═", shape: "line",
|
|
help: "A straight road along its length, with a dashed centre line.",
|
|
props: [
|
|
#{ key: "w", type: "float", def: 40.0, min: 2.0, max: 2000.0, step: 1.0, label: "Length (m)" },
|
|
#{ key: "d", type: "float", def: 6.0, min: 2.0, max: 40.0, step: 0.5, label: "Width (m)" },
|
|
#{ key: "dashed", type: "bool", def: true, label: "Centre line" },
|
|
#{ key: "kerb", type: "bool", def: true, label: "Kerb lines" },
|
|
] }
|
|
}
|
|
fn prefab_road(o) {
|
|
let p = o.p;
|
|
let w = p.w / 2.0;
|
|
let d = p.d / 2.0;
|
|
layer("ground");
|
|
let s = sprite();
|
|
s.flat(rect(-w, -d, w, d), 0.007, "g-asph t");
|
|
if p.dashed { s.lines([[-w, 0.0, w, 0.0]], 0.012, "dash"); }
|
|
if p.kerb { s.lines([[-w, -d, w, -d], [-w, d, w, d]], 0.012, "kerb"); }
|
|
}
|
|
|
|
fn meta_parking() {
|
|
#{ label: "Parking bays", category: "Ground", icon: "P",
|
|
props: [
|
|
#{ key: "n", type: "int", def: 6, min: 1, max: 60, step: 1, label: "Bays" },
|
|
#{ key: "bay_w", type: "float", def: 2.5, min: 2.0, max: 4.0, step: 0.1, label: "Bay width (m)" },
|
|
#{ key: "bay_d", type: "float", def: 5.0, min: 4.0, max: 7.0, step: 0.1, label: "Bay depth (m)" },
|
|
] }
|
|
}
|
|
fn prefab_parking(o) {
|
|
let p = o.p;
|
|
let w = p.n * p.bay_w / 2.0;
|
|
let d = p.bay_d / 2.0;
|
|
layer("ground");
|
|
let s = sprite();
|
|
s.flat(rect(-w, -d, w, d), 0.008, "g-pad t");
|
|
let segs = [];
|
|
for i in 0..(p.n + 1) {
|
|
let x = -w + i * p.bay_w;
|
|
segs.push([x, -d, x, d]);
|
|
}
|
|
s.lines(segs, 0.014, "bayline");
|
|
}
|
|
|
|
fn meta_wall() {
|
|
#{ label: "Wall", category: "Site", icon: "▬", shape: "line",
|
|
props: [
|
|
#{ key: "w", type: "float", def: 20.0, min: 0.5, max: 500.0, step: 0.5, label: "Length (m)" },
|
|
#{ key: "h", type: "float", def: 2.2, min: 0.3, max: 8.0, step: 0.1, label: "Height (m)" },
|
|
#{ key: "t", type: "float", def: 0.24, min: 0.1, max: 1.0, step: 0.02, label: "Thickness (m)" },
|
|
] }
|
|
}
|
|
fn prefab_wall(o) {
|
|
// long walls in pieces of at most 30 m, each its own sprite for the depth sort
|
|
let p = o.p;
|
|
let n = (p.w / 30.0).ceiling().to_int();
|
|
let L = p.w / n;
|
|
for i in 0..n {
|
|
let x0 = -p.w / 2.0 + i * L;
|
|
sprite().box(x0, -p.t / 2.0, x0 + L, p.t / 2.0, 0.0, p.h, "wallp", #{ top: "wallt" });
|
|
}
|
|
}
|
|
|
|
fn meta_fence() {
|
|
#{ label: "Fence", category: "Site", icon: "┼", shape: "line",
|
|
props: [
|
|
#{ key: "w", type: "float", def: 20.0, min: 1.0, max: 500.0, step: 0.5, label: "Length (m)" },
|
|
#{ key: "h", type: "float", def: 1.8, min: 0.5, max: 4.0, step: 0.1, label: "Height (m)" },
|
|
] }
|
|
}
|
|
fn prefab_fence(o) {
|
|
let p = o.p;
|
|
let n = (p.w / 30.0).ceiling().to_int();
|
|
let L = p.w / n;
|
|
for i in 0..n {
|
|
let x0 = -p.w / 2.0 + i * L;
|
|
let s = sprite();
|
|
s.box(x0, -0.03, x0 + L, 0.03, 0.0, p.h, "fence");
|
|
let k = (L / 2.5).floor().to_int();
|
|
for j in 0..(k + 1) {
|
|
let x = x0 + j * L / fmax(k, 1);
|
|
s.box(x - 0.04, -0.04, x + 0.04, 0.04, 0.0, p.h + 0.05, "steel");
|
|
}
|
|
}
|
|
}
|
|
|
|
fn meta_lamp() {
|
|
#{ label: "Street lamp", category: "Site", icon: "†",
|
|
help: "Keep lamps on verges and kerbs, not on drive areas.",
|
|
props: [ #{ key: "h", type: "float", def: 5.0, min: 2.0, max: 12.0, step: 0.5, label: "Height (m)" } ] }
|
|
}
|
|
fn prefab_lamp(o) {
|
|
let s = sprite();
|
|
s.box(-0.07, -0.07, 0.07, 0.07, 0.0, o.p.h, "lampost", #{ no_top: true });
|
|
s.circle(0.0, 0.0, o.p.h + 0.1, 1.2, "lamp");
|
|
}
|
|
|
|
fn meta_marker() {
|
|
#{ label: "Marker", category: "Site", icon: "⚑",
|
|
help: "A pin with a label: set the label in Tag and the tooltip in Info.",
|
|
props: [ #{ key: "h", type: "float", def: 1.5, min: 0.3, max: 20.0, step: 0.1, label: "Height (m)" } ] }
|
|
}
|
|
fn prefab_marker(o) {
|
|
let s = sprite();
|
|
s.box(-0.05, -0.05, 0.05, 0.05, 0.0, o.p.h, "steel", #{ no_top: true });
|
|
s.circle(0.0, 0.0, o.p.h, 2.0, "led ledo");
|
|
}
|