Optical QC: one station for both presses, after the cooling racks
Deploy test site / deploy (push) Successful in 55s
Deploy test site / deploy (push) Successful in 55s
User, 18 Oct 2026: for now one QC station for both machines; let the records cool in a queue before testing them. - inline-optical-qc.md "Where it sits": launch setup. Spindle stacks from the Duplex system and the Classic, labelled at the press (press, stamper set, first and last cycle), cool in FIFO racks (24 h accepted practice, 8 h at the shortest, Stamper Discs; about one day of output, 2,800 to 3,100 records); the finishing operator feeds the station from the cooled stacks. Gains: warp and centring measured on settled records (the release value), one station instead of two, no Classic unloader change, no warm-record sag or thermal camera. Cost: defects found hours later, covered by the Duplex operator, per-cycle telemetry and an early lane for the first records of each run and after stamper changes. Record key from the stack label and stack position, checked against the run-out stamper number. Capacity 10 to 12 a minute against 5 to 6: one station to about two Duplex systems and two Classics. A station at each press stays the later option. Cost table, open points, infeed row, thermal camera note and the Newbilt question follow. - Fleet calculator: the per-press stations and the release station are gone; the finishing block shows the cooling racks with record stacks and the one optical station by the corridor glass; tooltips, corridor and conveyor texts; machine park back to its legend, finishing box "cooling, QC, packing". - quality-automation.md layer 1, digital-factory.md QC row, process-flow.md stage 6, site-candidates.md block ground floor, crane-workshop-tours.md tour stop 6. - Investor render: infeed label "the operator sets each cooled record down". Checks: node --check; pw_bp_calc.py 0 fails; pw_iso_view_check.py OK; info for every data-id at all presets, levels and rotations; GF nodes 2,414 at the full preset; zoomed shots in two rotations.
This commit is contained in:
1 parent
9ffcfe62f1
commit
8c2143630c
9 files changed
+142
-95
No files matched your search
+33
-36
@@ -38,7 +38,7 @@ document.documentElement.setAttribute("data-theme",t);})();
|
||||
.pk-press { fill: var(--pk-press); stroke: var(--pk-pressS); stroke-width: 1.2; }
|
||||
.pk-col { fill: var(--pk-pressS); }
|
||||
.pk-ex50 { fill: var(--dstd); } .pk-ex35 { fill: var(--dspec); }
|
||||
.pk-op { fill: #e8b400; } .pk-trim { fill: var(--mute); } .pk-qc { fill: #c9d0d8; stroke: #5d6878; } .pk-qct { fill: #2c3442; } .pk-disc { fill: #111; stroke: var(--mute); }
|
||||
.pk-op { fill: #e8b400; } .pk-trim { fill: var(--mute); } .pk-disc { fill: #111; stroke: var(--mute); }
|
||||
.pk-glyph { fill: var(--pk-glyph); stroke: var(--pk-pressS); }
|
||||
.pk-feed { stroke: var(--mute); stroke-width: 1; fill: none; stroke-dasharray: 2 3; }
|
||||
.pk-t { fill: var(--fg); font-size: 12px; font-weight: 600; }
|
||||
@@ -808,9 +808,9 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
<section class="card">
|
||||
<h2>Machine park and stamper production</h2>
|
||||
<p class="note" style="margin-top:0">The fleet above as a schematic, not to scale: each Duplex cell as
|
||||
in the cell sketch (presses either side of the operator, EX 50 and EX 35 behind him, trimmer and
|
||||
inline optical QC station in front), each Classic with its built-in extruder and a QC station at its
|
||||
unload side; above it the stamper line that feeds the presses,
|
||||
in the cell sketch (presses either side of the operator, EX 50 and EX 35 behind him, trimmer in
|
||||
front), each Classic with its built-in extruder; on the right finishing, where the records cool and
|
||||
one optical station checks them; above it the stamper line that feeds the presses,
|
||||
sized from the cycle times in galvanics.md; below it the central utilities. Bars show how busy
|
||||
each station is; an amber box exceeds the plant as planned today.</p>
|
||||
<div class="tscroll"><svg id="park" viewBox="0 0 1200 600" role="img" aria-label="Machine park and stamper production schematic"></svg></div>
|
||||
@@ -1393,9 +1393,10 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
s.led(cx, (y0 + y1) / 2, z + h + 0.02, "iso-ledo");
|
||||
return s;
|
||||
}
|
||||
// inline optical QC station (equipment/inline-optical-qc.md, FreeCAD concept model): 1.9 x 0.65 x 1.5 m
|
||||
// aluminium profile frame with the rim-belt conveyor, a light-tight tunnel over the cameras, stack light on
|
||||
// the tunnel exit and the reject bin beside the outfeed; records run toward -x, the bin stands on the -y side
|
||||
// optical QC station (equipment/inline-optical-qc.md, FreeCAD concept model): 1.9 x 0.65 x 1.5 m aluminium
|
||||
// profile frame with the rim-belt conveyor, a light-tight tunnel over the cameras, stack light on the tunnel
|
||||
// exit and the reject bin beside the outfeed; records run toward -x, the bin stands on the -y side.
|
||||
// Launch setup (October 2026): one station for both presses, at the start of finishing, after the cooling racks
|
||||
function qcStation(sc, id, xa, ya, z, tag) {
|
||||
var s = sc.sprite(id), xb = xa + 1.9, yb = ya + 0.65;
|
||||
s.seq([
|
||||
@@ -1410,9 +1411,6 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
if (tag) sc.tag(xa + 0.95, ya + 0.33, z + 2.1, tag, 3, id);
|
||||
return s;
|
||||
}
|
||||
var QC_INFO = "Checks every record on both faces in one turn: surface (a line-scan camera per side), label (a colour camera per side), " +
|
||||
"warp (two lasers) and centring; a failed record is pushed into the bin. 1.9 x 0.65 x 1.5 m on a 40 x 40 aluminium profile frame, " +
|
||||
"cycle about 5 to 6 s, hardware about USD 16k to 33k (estimate), inside the metrology budget (inline-optical-qc.md)";
|
||||
function duplexCell(sc, n, cx, cy, z, running) {
|
||||
var id = "duplex-" + n;
|
||||
pressM(sc, id, cx - 1.75, cy - 0.1, z, true, running);
|
||||
@@ -1423,12 +1421,8 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
t.box(cx + 0.75, cy - 1.65, cx + 1.35, cy - 1.05, z, z + 1.0, "iso-steel");
|
||||
t.disc(cx + 1.05, cy - 1.35, z + 1.02, 0.22, "iso-vinylc");
|
||||
sc.sprite(id).person(cx, cy - 0.35, z);
|
||||
// inline QC in front of the operator: trimmed record on the infeed (trimmer side), good records out at the far end
|
||||
qcStation(sc, "qc-" + id, cx - 1.25, cy - 1.85, z, "Inline QC");
|
||||
sc.inf("qc-" + id, "Inline optical QC, Duplex " + n,
|
||||
"After the trimmer, in front of the operator: he puts each trimmed record on the infeed and still sees every record. " + QC_INFO);
|
||||
sc.inf(id, "Duplex system " + n + ": 2 HRP 12 presses, EX 50 + EX 35",
|
||||
"One operator's cell (~5 x 3 m): presses turned 45 degrees to the operator, EX 50 main and EX 35 colour extruder behind him, trimmer front-left, inline optical QC station in front of him. HRP 12 ~150 t; steam 150 to 180 kg/h and cooling up to 125 kW per press (Newbilt).");
|
||||
"One operator's cell (~5 x 3 m): presses turned 45 degrees to the operator, EX 50 main and EX 35 colour extruder behind him, trimmer front-left; trimmed records go on spindle stacks to the cooling racks. HRP 12 ~150 t; steam 150 to 180 kg/h and cooling up to 125 kW per press (Newbilt).");
|
||||
}
|
||||
function classicM(sc, n, cx, cy, z, running) {
|
||||
var id = "classic-" + n, s = sc.sprite(id), P = sc.P;
|
||||
@@ -1442,10 +1436,7 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
s.led(p, cy, z + 1.47, "iso-ledg");
|
||||
if (running) s.puffs(cx - 0.55, cy, z + 2.6, "iso-puff", 2, 3.9);
|
||||
sc.inf(id, "Classic " + n + ": Newbilt Classic, fully automatic",
|
||||
"Built-in extruder, automatic cake loading, label feed and spindle stacking; 28 s cycle at 180 g, ~128 records/h (vendor flyer). Inline optical QC station in front of it.");
|
||||
qcStation(sc, "qc-" + id, cx - 1.2, cy - 1.6, z, "Inline QC");
|
||||
sc.inf("qc-" + id, "Inline optical QC, Classic " + n,
|
||||
"In front of the Classic's unload side. Open point for Newbilt: can the unloader set the record down on the station's infeed instead of the spindle? If not, a fixed camera over the unload position covers surface and label, and warp and centring go to samples. " + QC_INFO);
|
||||
"Built-in extruder, automatic cake loading, label feed and spindle stacking; 28 s cycle at 180 g, ~128 records/h (vendor flyer); the stacks go to the cooling racks.");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ the site
|
||||
@@ -1580,7 +1571,7 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
|
||||
// ------------------------------------------------------------ factory
|
||||
// finishing and print block, 14 x 25 m on two levels at fx 92..106 (site-candidates.md, block floor plans):
|
||||
// ground floor release inspection, QC lab, stair + goods lift along the corridor, packaging behind; upper floor at +3.8 m
|
||||
// ground floor cooling racks + optical inspection, QC lab, stair + goods lift along the corridor, packaging behind; upper floor at +3.8 m
|
||||
var BLK = { fx0: 92, fx1: 106, up: 3.8 };
|
||||
function zoneList(cfg, up) {
|
||||
var z = [
|
||||
@@ -1618,14 +1609,15 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
sc.inf("colourstore", "Colour store, ~180 m2", "About 100 pallet positions on four levels for tens of colours (estimate); weighing, mixing and vacuum conveying");
|
||||
sc.inf("plantroom", "Central hydraulic and air plant room, ~62 m2", "Pump sets on one manifold with the accumulators, one compressed-air plant; ring mains with a valved tee at every press position (pressing-line.md)");
|
||||
sc.inf("aisle", "Crane and forklift aisle, 4.5 m", "Along the back wall from the machine door to the finishing block: heavy moves need a floor-level path");
|
||||
sc.inf("trim", "Release inspection, cooled samples", "Every record is already inspected inline at its press. Records settle for about 24 h, so warp and centring for the release are measured here on cooled samples, on a second station of the same design (inline-optical-qc.md). No separate trimmer: every Duplex cell and the Classic trim inline (pressing-line.md)");
|
||||
sc.inf("trim", "Optical inspection after cooling", "One station checks every record of both presses after the cooling racks: surface (a line-scan camera per side), label, warp and centring in one turn. The finishing operator feeds it from the cooled stacks; good records go on to sleeving, rejects into the bin with the reason on the screen. Early lane: the first records of each run and after each stamper change go through warm. 1.9 x 0.65 x 1.5 m, about 10 to 12 records a minute against 5 to 6 from the launch plant; hardware about USD 16k to 33k (estimate) (inline-optical-qc.md). No separate trimmer: every Duplex cell and the Classic trim inline (pressing-line.md)");
|
||||
sc.inf("cooling", "Cooling racks", "Spindle stacks from both presses, labelled at the press (press, stamper set, first and last cycle), first in, first out. 24 h of cooling before sleeving is accepted practice, 8 h at the shortest (Stamper Discs, in inline-optical-qc.md): about one day of output, 2,800 to 3,100 records at the launch plant");
|
||||
sc.inf("qc", "QC and listening", "Sampled audio comparison (about 1 in 50) and the listening point on the tour (quality-automation.md)");
|
||||
sc.inf("packaging", "Finishing and packaging", "Packing tables, shrink wrap and pallet wrapper, ~170 m2 on the ground floor of the finishing and print block (14 x 25 m on two levels, print room reserved upstairs)");
|
||||
sc.inf("block-stair", "Stair and goods lift", "Connect the two levels of the finishing and print block. The crane runway ends at the press hall, so loads here move by forklift and goods lift; heavy compound stays on the ground floor (site-candidates.md, crane-workshop-tours.md)");
|
||||
if (cfg.cassette) sc.inf("cassette", "Cassette duplication", "Bench line, ~40 to 80 m2 (project-timeline.md)");
|
||||
if (cfg.cdr) sc.inf("cdr", "CD-R duplication, short run", "Tower duplicator and printer bench, ~20 to 40 m2 (project-timeline.md)");
|
||||
sc.inf("printblock", "Finishing and print block, 14 x 25 m",
|
||||
"Two levels: release inspection, the QC lab and packaging (~170 m2) on the ground floor; print room (reserve), print stock and packaging materials on the upper floor at +3.8 m (site-candidates.md)");
|
||||
"Two levels: cooling racks, optical inspection, the QC lab and packaging (~170 m2) on the ground floor; print room (reserve), print stock and packaging materials on the upper floor at +3.8 m (site-candidates.md)");
|
||||
sc.inf("printroom", "Print room (kept in reserve)", "Upper floor at +3.8 m. In-house printing is not decided; jackets come from a print partner today (site-candidates.md, production-timeline.md)");
|
||||
sc.inf("printstock", "Print stock", "Paper and board, upper floor at +3.8 m (site-candidates.md)");
|
||||
sc.inf("packmat", "Packaging materials", "Sleeves, inner bags, mailers and cartons, upper floor at +3.8 m (site-candidates.md)");
|
||||
@@ -1636,12 +1628,12 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
sc.inf("wc-w", "Toilets at the staff entry", "Women: 2 WC and a basin; men: 1 WC, 1 urinal and a basin; an accessible WC. Thai minimum for a factory, per up to 15 workers of each sex (Ministerial Regulation No. 39, B.E. 2537, table 2); separate toilets for women, men and disabled staff (labour welfare regulation B.E. 2548). Showers are in the office changing rooms.");
|
||||
sc.inf("wc-e", "Toilets, finishing block", "Second set at the east end of the press hall, so nobody walks ~90 m back to the staff entry: women 2 WC and a basin, men 1 WC, 1 urinal and a basin. Proposed (October 2026), not yet in the parametric floor plans.");
|
||||
sc.inf("corridor", cfg.corridor ? "Visitor corridor, glazed, ~98 m" : "Visitor corridor: later",
|
||||
cfg.corridor ? "Along the car-park wall in process order: cutting, galvanics, stamper prep, material lab, press hall with an optical QC station at every press, release inspection, QC and listening, finishing. No PPE, filtered air." :
|
||||
cfg.corridor ? "Along the car-park wall in process order: cutting, galvanics, stamper prep, material lab, press hall, cooling racks and optical inspection, QC and listening, finishing. No PPE, filtered air." :
|
||||
"The strip along the car-park wall stays free; the glazed corridor is built later.");
|
||||
sc.inf("crane", cfg.crane === "buy" ? "Overhead crane, 5 t" : "Crane-ready frame (crane rented)",
|
||||
cfg.crane === "buy" ? "EOT crane over the production compartment, runway to the end of the press hall, rail at ~5.6 m; parks over the workshop (crane-workshop-tours.md)" :
|
||||
"Runway brackets and rails in the frame; a crane is rented for installations");
|
||||
sc.inf("conveyor", "Records to finishing", "Schematic: inspected records travel from the presses to finishing");
|
||||
sc.inf("conveyor", "Records to finishing", "Schematic: records travel from the presses to the cooling racks (in practice as spindle stacks)");
|
||||
sc.inf("pipebridge", "Pipe bridge", "Steam, condensate and cooling water from the yard to the service trench along the press rows");
|
||||
}
|
||||
function factoryRoof(sc, cfg, pv) {
|
||||
@@ -1729,7 +1721,7 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
} else fl.flat(pts, z + 0.015, "iso-slot", sl.t === "D" ? "duplex-" + sl.n : "classic-" + sl.n);
|
||||
if (!sl.e && sl.t === "D") {
|
||||
var cx = (sl.x0 + sl.x1) / 2, cy = (sl.y0 + sl.y1) / 2;
|
||||
fl.flat(rect(cx - 2.6, cy - 2.4, cx + 2.6, cy + 2.15), z + 0.02, "iso-cell", "duplex-" + sl.n);
|
||||
fl.flat(rect(cx - 2.6, cy - 2.0, cx + 2.6, cy + 2.15), z + 0.02, "iso-cell", "duplex-" + sl.n);
|
||||
}
|
||||
});
|
||||
// walls cut: back walls taller than front walls (cutaway)
|
||||
@@ -1914,7 +1906,7 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
sc.sprite("plantroom").box(X(45.4), Y(17.3), X(47.3), Y(19.0), z, z + 1.5, "iso-comp");
|
||||
sc.sprite("plantroom").box(X(41), Y(16.0), X(43.6), Y(17.2), z, z + 1.2, "iso-oil");
|
||||
sc.tag(X(44), Y(16.5), z + 3, "Plant room", 4, "plantroom");
|
||||
// finishing and print block, ground floor (block floor plans): along the corridor release inspection, QC lab,
|
||||
// finishing and print block, ground floor (block floor plans): along the corridor cooling + optical inspection, QC lab,
|
||||
// stair + goods lift; packaging behind with the cassette and CD-R benches; the upper floor is drawn at 1F
|
||||
if (!up) finishingGF(sc, cfg, z);
|
||||
// warehouse: three racking rows; dispatch: staged pallets and a forklift
|
||||
@@ -1937,10 +1929,18 @@ html[data-theme=light] .iso-svg .iso-glint { display: inline; }
|
||||
}
|
||||
// finishing and print block, ground floor (fx 92..106)
|
||||
function finishingGF(sc, cfg, z) {
|
||||
// release inspection (fx 92..96): every record is inspected inline at its press (October 2026); here a second
|
||||
// station of the same design measures cooled samples before release. No trimmer: the presses trim inline
|
||||
qcStation(sc, "trim", X(93.1), Y(5.2), z, "");
|
||||
sc.tag(X(94), Y(5.5), z + 2.6, "Release inspection", 4, "trim");
|
||||
// cooling racks and optical inspection (fx 92..96): spindle stacks from both presses cool first in, first out,
|
||||
// then one station checks every record (inline-optical-qc.md, October 2026). No trimmer: the presses trim inline
|
||||
// the station stands by the corridor glass (tour stop), the racks behind it
|
||||
var cr = sc.sprite("cooling");
|
||||
cr.box(X(92.4), Y(5.7), X(95.6), Y(6.4), z, z + 0.45, "iso-shelf");
|
||||
cr.seq([0, 1, 2, 3, 4, 5].map(function (i) {
|
||||
var fx = 92.68 + i * 0.53;
|
||||
return [X(fx), Y(6.05), function (q) { q.cyl(X(fx), Y(6.05), 0.16, z + 0.45, z + 0.45 + (i % 3 === 1 ? 0.3 : 0.48), "iso-dome"); }];
|
||||
}));
|
||||
sc.tag(X(94), Y(6.05), z + 1.5, "Cooling racks", 3, "cooling");
|
||||
qcStation(sc, "trim", X(93.6), Y(3.85), z, "");
|
||||
sc.tag(X(94.5), Y(4.2), z + 2.4, "Optical QC", 4, "trim");
|
||||
// QC lab (fx 96..100): bench on the packaging side
|
||||
var qb = sc.sprite("qc"); qb.box(X(96.3), Y(6.7), X(99.7), Y(7.5), z, z + 0.85, "iso-bench");
|
||||
qb.seq([[X(97), Y(7.1), function (q) { q.box(X(96.5), Y(6.8), X(97.5), Y(7.4), z + 0.85, z + 1.0, "iso-instr"); q.disc(X(97), Y(7.1), z + 1.02, 0.24, "iso-vinylc"); }],
|
||||
@@ -3910,11 +3910,10 @@ function drawPark(r, b) {
|
||||
const y1 = y0 + bh + 44, hh = Math.max(230, 46 + L.h + 18);
|
||||
box(hx, y1, hw, hh, "pk-hall", 8);
|
||||
T(hx + 14, y1 + 20, "pk-lane", `PRESS HALL · ${r.D} DUPLEX SYSTEM${r.D === 1 ? "" : "S"} + ${r.C} CLASSIC${r.C === 1 ? "" : "S"} · ${r.P} PRESSES · ~${f0(r.floor)} M² PRESS FLOOR`);
|
||||
o.push(`<g transform="translate(${hx + hw - 375},${y1 + hh - 22})"><rect width="10" height="10" class="pk-ex50"/><text x="14" y="9" class="pk-s">EX 50</text>` +
|
||||
o.push(`<g transform="translate(${hx + hw - 300},${y1 + 10})"><rect width="10" height="10" class="pk-ex50"/><text x="14" y="9" class="pk-s">EX 50</text>` +
|
||||
`<rect x="62" width="10" height="10" class="pk-ex35"/><text x="76" y="9" class="pk-s">EX 35 colour</text>` +
|
||||
`<circle cx="160" cy="5" r="5" class="pk-op"/><text x="169" y="9" class="pk-s">operator</text>` +
|
||||
`<rect x="225" width="10" height="10" class="pk-trim"/><text x="239" y="9" class="pk-s">trimmer</text>` +
|
||||
`<rect x="290" y="1" width="16" height="8" class="pk-qc"/><rect x="295" y="1" width="6" height="8" class="pk-qct"/><text x="310" y="9" class="pk-s">inline QC</text></g>`);
|
||||
`<rect x="225" width="10" height="10" class="pk-trim"/><text x="239" y="9" class="pk-s">trimmer</text></g>`);
|
||||
if (!items.length) T(hx + hw / 2, y1 + hh / 2, "pk-s", "no presses", "middle");
|
||||
items.forEach(([k, n], i) => {
|
||||
const [px, py] = L.pos[i], tx = hx + 15 + px, ty = y1 + 34 + py;
|
||||
@@ -3927,7 +3926,6 @@ function drawPark(r, b) {
|
||||
`<rect x="77" y="14" width="11" height="24" rx="2" class="pk-ex35"/>` +
|
||||
`<circle cx="73" cy="57" r="5.5" class="pk-op"/>` +
|
||||
`<rect x="48" y="66" width="13" height="13" rx="1" class="pk-trim"/>` +
|
||||
`<rect x="65" y="68" width="40" height="11" class="pk-qc"/><rect x="78" y="68" width="16" height="11" class="pk-qct"/>` +
|
||||
`<text x="75" y="96" class="pk-s" text-anchor="middle">Duplex ${n} · ${pct(r.dUse)}</text></g>`);
|
||||
else o.push(`<g transform="translate(${tx},${ty}) scale(${sc})">` +
|
||||
`<rect width="84" height="104" rx="6" class="pk-cell"/>` +
|
||||
@@ -3935,7 +3933,6 @@ function drawPark(r, b) {
|
||||
`<rect x="28" y="22" width="36" height="36" rx="3" class="pk-press"/>` +
|
||||
`<circle cx="33" cy="27" r="3.5" class="pk-col"/><circle cx="59" cy="27" r="3.5" class="pk-col"/><circle cx="46" cy="53" r="3.5" class="pk-col"/>` +
|
||||
`<circle cx="66" cy="73" r="7" class="pk-disc"/>` +
|
||||
`<rect x="12" y="68" width="40" height="11" class="pk-qc"/><rect x="24" y="68" width="16" height="11" class="pk-qct"/>` +
|
||||
`<text x="42" y="96" class="pk-s" text-anchor="middle">Classic ${n} · ${pct(r.cUse)}</text></g>`);
|
||||
});
|
||||
// compound in
|
||||
@@ -3957,7 +3954,7 @@ function drawPark(r, b) {
|
||||
// finished records out to finishing
|
||||
const fy = ry + 108;
|
||||
box(rx0, fy, 130, 104, "pk-box");
|
||||
T(rx0 + 8, fy + 17, "pk-t", "Finishing"); T(rx0 + 8, fy + 33, "pk-s", "QC, sleeves, packing");
|
||||
T(rx0 + 8, fy + 17, "pk-t", "Finishing"); T(rx0 + 8, fy + 33, "pk-s", "cooling, QC, packing");
|
||||
T(rx0 + 8, fy + 54, "pk-v", `${f0(r.X / days)} a day`);
|
||||
T(rx0 + 8, fy + 72, "pk-s", `${r.fin} ${r.fin === 1 ? "person" : "people"} per shift`);
|
||||
T(rx0 + 8, fy + 88, "pk-s", `${f0(r.perHour)} records an hour`);
|
||||
|
||||
Reference in new issue
Block a user