Conveyors and producers: goods flow from presses down the belts
Deploy web Studio / deploy (push) Successful in 1m4s
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:
1 parent
a202283a60
commit
18dd324543
20 files changed
+617
-18
No files matched your search
@@ -148,6 +148,7 @@ def main():
|
||||
shutil.copy2(ROOT / src, out / "assets" / dst / Path(src).name)
|
||||
(web / "demo.json").write_text(json.dumps(demo_files(), ensure_ascii=False), encoding="utf-8")
|
||||
(web / "house.json").write_text(json.dumps(demo_files("house"), ensure_ascii=False), encoding="utf-8")
|
||||
(web / "factory.json").write_text(json.dumps(demo_files("factory"), ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
h = hashlib.sha256()
|
||||
for p in sorted((out / "assets").rglob("*")):
|
||||
|
||||
@@ -345,6 +345,48 @@ with sync_playwright() as p:
|
||||
pg.wait_for_timeout(600)
|
||||
pg.evaluate("__studio.select(null)")
|
||||
|
||||
# a conveyor runs the way it was drawn; started at a producer's output it carries what the producer
|
||||
# makes, spaced by its rate (changed in the producer's properties) and the belt's speed
|
||||
pg.evaluate("__studio.select(null)")
|
||||
pg.evaluate("__studio.view.focus([25, -4.5, 0], 3)")
|
||||
pg.wait_for_timeout(400)
|
||||
n4 = len(doc()["objects"])
|
||||
pg.locator('.st-tile[data-type="conveyor"]').click()
|
||||
a, b2 = at(27, -4.5), at(21, -4.5)
|
||||
pg.mouse.move(*a)
|
||||
pg.mouse.down()
|
||||
for i in range(1, 11):
|
||||
pg.mouse.move(a[0] + (b2[0] - a[0]) * i / 10, a[1] + (b2[1] - a[1]) * i / 10)
|
||||
pg.wait_for_timeout(15)
|
||||
check("running from where you started" in pg.locator("#hint").inner_text(), "the conveyor preview says which way it runs")
|
||||
pg.mouse.up()
|
||||
pg.wait_for_timeout(800)
|
||||
cv = doc()["objects"][-1]
|
||||
check(cv["type"] == "conveyor" and cv.get("rot") == 180 and abs(cv["x"] - 24) < 1e-6 and abs(cv["props"]["w"] - 6) < 1e-6,
|
||||
f"a conveyor dragged right to left runs that way (rot {cv.get('rot')}, x {cv['x']})")
|
||||
pg.evaluate("__studio.op({op: 'add', type: 'producer', x: 28.6, y: -4.5, rot: 180, props: {rate: 20}})")
|
||||
pg.wait_for_timeout(900)
|
||||
pid = doc()["objects"][-1]["id"]
|
||||
rows = lambda: dict(pg.evaluate(f"(__studio.view.info('{cv['id']}') || {{}}).rows || []"))
|
||||
check(f"(from {pid})" in rows().get("Carries", "") and "20 cartons a minute, 1.5 m apart" in rows().get("Carries", ""),
|
||||
"the belt carries what the producer at its start makes: " + rows().get("Carries", "?"))
|
||||
check(pg.evaluate(f"document.querySelectorAll('.iso-svg [data-obj=\"{cv['id']}\"] .iso-ride').length") == 1 and
|
||||
pg.evaluate(f"document.querySelectorAll('.iso-svg [data-obj=\"{pid}\"] .iso-ram').length") == 1,
|
||||
"goods ride the belt, the press's ram goes up and down")
|
||||
pg.locator(f'#objects li[data-id="{pid}"]').click()
|
||||
pg.wait_for_timeout(300)
|
||||
pg.locator('#right input[type="number"][data-prop="rate"]').fill("30")
|
||||
pg.locator('#right input[type="number"][data-prop="rate"]').press("Enter")
|
||||
pg.wait_for_timeout(900)
|
||||
check("30 cartons a minute, 1 m apart" in rows().get("Carries", ""), "a faster producer packs the belt closer: " + rows().get("Carries", "?"))
|
||||
pg.screenshot(path=str(OUT / "studio-conveyor.jpg"), type="jpeg", quality=80)
|
||||
for _ in range(3):
|
||||
pg.locator("#undo").click()
|
||||
pg.wait_for_timeout(500)
|
||||
check(len(doc()["objects"]) == n4, "undo takes the producer and the belt back")
|
||||
pg.evaluate("__studio.select(null)")
|
||||
pg.wait_for_timeout(300)
|
||||
|
||||
# performance: animations step about ten times a second by default (no CSS animation runs on its
|
||||
# own), the toolbar button switches smooth / off / light; a pan moves the drawing as one layer and
|
||||
# draws it again (viewBox) only when the drag ends
|
||||
|
||||
@@ -309,6 +309,20 @@ try:
|
||||
check(an[0] == "light" and an[1] >= 6 and an[2] == 0 and t1 > an[3] and pg.locator('.iso-bar [data-a="anim"]').is_visible(),
|
||||
f"animations are light by default: {an[1]} stepped, none running, time moves on; the toolbar can switch")
|
||||
|
||||
# ---------------------------------------------------------------- the factory demo: presses and conveyors
|
||||
pg.locator("#wb-projects").click()
|
||||
pg.locator("#wb-nfactory").click()
|
||||
pg.wait_for_load_state()
|
||||
ready(pg)
|
||||
pg.wait_for_timeout(500)
|
||||
nf = len(doc(pg)["objects"])
|
||||
rides = pg.evaluate("() => document.querySelectorAll('.iso-svg .iso-ride').length")
|
||||
check(title(pg) == "isokit factory" and nf > 15 and rides >= 5 and pg.evaluate("() => __studio.S.warnings.length") == 0,
|
||||
f"Factory demo opens a production yard ({nf} objects, goods riding {rides} belts, no warnings)")
|
||||
carries = pg.evaluate("() => Object.fromEntries((__studio.view.info('belt-a3') || {rows: []}).rows)['Carries'] || ''")
|
||||
check("20 cartons a minute" in carries and "(from belt-a2)" in carries, "goods come down the line: " + carries)
|
||||
shot(pg, "web-factory.jpg")
|
||||
|
||||
# ---------------------------------------------------------------- folder project (OPFS stands in for a picked folder)
|
||||
demo = {f.relative_to(ROOT / "examples" / "demo").as_posix(): f.read_text(encoding="utf-8")
|
||||
for f in (ROOT / "examples" / "demo").rglob("*") if f.is_file() and "dist" not in f.parts}
|
||||
|
||||
Reference in new issue
Block a user