Conveyors and producers: goods flow from presses down the belts
Deploy web Studio / deploy (push) Successful in 1m4s

- Producer (category Industry): a press making cartons, crates, drums, sacks or parts at a set
  rate per minute; its ram goes down once per item, a green / red light shows running / stopped.
- Conveyor: drawn the way it runs (new prefab meta `directed`: the Studio turns the piece from
  where the drag starts), belt width, height, rise (inclines), speed, goods and spacing; legs,
  rails and a drive motor. Corners join without overlap (the receiving belt runs through, the
  feeding one stops at its side).
- A conveyor starting on a producer's output side carries its goods at its rate; one starting at
  another's end carries on with what that one carries. The gap is speed / rate. A stopped press or
  belt stops the goods after it. Tooltips show speed, rate and source.
- The goods ride a group moving one gap per loop (no reordering), first fading in, last out.
- Script API: world_of(o, u, v), info_row(key, value); objects_on falls back to half of p.d.
- Theme: industry colours, LED colours (the marker's LED had none).
- examples/factory + Factory demo in the web Studio; MCP instructions on production lines.

Checks: 68 Rust tests (conveyor joints, feed and spacing, every view of the factory demo),
Studio 108/108 (draw direction, feed from a producer, rate change), web 89/89.
This commit is contained in:
grabowski committed 2026-10-24 21:46:10 +07:00
1 parent a202283a60
commit 18dd324543
20 files changed
+617 -18

No files matched your search

+17 -1
View File
@@ -652,6 +652,16 @@ pub(crate) fn register_scene(e: &mut Engine, st: &Shared) {
tag(&s, x, y, z, t, n(&p)?, Some(id), k)
},
);
// a row more in the tooltip of the object being drawn
let s = st.clone();
e.register_fn("info_row", move |k: D, v: D| {
let mut b = s.borrow_mut();
if let Some(id) = b.obj.clone() {
if let Some(i) = b.scene.info.get_mut(&id) {
i.rows.push((k.to_string(), v.to_string()));
}
}
});
let s = st.clone();
e.register_fn("info", move |id: &str, name: &str| {
s.borrow_mut().scene.info(id, name, "")
@@ -933,7 +943,8 @@ fn register_objects(e: &mut Engine, st: &Shared) {
let m = d.read_lock::<Map>()?;
let l = xf_of(&m).inv(x, y);
let half = prop(&m, "w").unwrap_or(1.0) / 2.0;
let lim = prop(&m, "t").unwrap_or(0.0) / 2.0 + tol;
// half the thickness (walls), else half the width (conveyors)
let lim = prop(&m, "t").or_else(|| prop(&m, "d")).unwrap_or(0.0) / 2.0 + tol;
(l[0].abs() <= half + 1e-6 && l[1].abs() <= lim + 1e-6)
.then(|| with_uv(d, l[0], l[1]))
})
@@ -1008,4 +1019,9 @@ fn register_objects(e: &mut Engine, st: &Shared) {
let p = xf_of(&o).inv(n(&x)?, n(&y)?);
Ok(vec![Dynamic::from_float(p[0]), Dynamic::from_float(p[1])])
});
// the world plan point of (u, v) in object o's frame
e.register_fn("world_of", |o: Map, u: D, v: D| -> RR<Array> {
let p = xf_of(&o).p(n(&u)?, n(&v)?);
Ok(vec![Dynamic::from_float(p[0]), Dynamic::from_float(p[1])])
});
}