diff --git a/README.md b/README.md index d67dc54..5f0e1d4 100644 --- a/README.md +++ b/README.md @@ -296,14 +296,20 @@ The detail lives in dedicated documents: (1.25M records, EBITDA ~3.1M USD, payback ~2.2 years on ~224M THB, if the records sell), the five-press table, and the levers and caveats behind the numbers -- [Business plan](docs/business-plan/CNX-Vinyl-Business-Plan.docx): the - investor-facing roll-up of everything above, built from - `docs/business-plan/build/` (run `python build_plan.py` to regenerate - after the numbers move; the PDF is exported with LibreOffice so the - table of contents is filled in). Draft 0.2 (October 2026) is built on - the launch plant: the whole chain at launch, the investor's budget - question, the launch plant's operating picture, the commissioning order - and its risks +- Business plan, draft 0.3 (October 2026), in two versions: + [Plan A, ~180M THB](docs/business-plan/CNX-Vinyl-Business-Plan-A.pdf) + ([docx](docs/business-plan/CNX-Vinyl-Business-Plan-A.docx)) and + [Plan B, ~225M THB](docs/business-plan/CNX-Vinyl-Business-Plan-B.pdf) + ([docx](docs/business-plan/CNX-Vinyl-Business-Plan-B.docx)): the + investor-facing roll-up of everything above, each a complete plan with + one table comparing it with the other, both priced without contingency + and with the ramp-up reserve. Each carries renders of the + [plant and business plan calculator](docs/fleet-calculator.html) with + its own preset (plant view, budget check, ten years of cash; in + `docs/renders/calculator/`). Built from `docs/business-plan/build/` + (`python build_plan.py` makes both versions; the PDFs are exported with + LibreOffice so the table of contents is filled in). Draft 0.2, a single + launch-plant plan with contingency, is in the git history ## Repository Layout @@ -311,7 +317,8 @@ The detail lives in dedicated documents: docs/ ├── brand/ Poy Records logo (1536 px PNG) ├── business-plan/ -│ ├── CNX-Vinyl-Business-Plan.docx Investor business plan (generated) +│ ├── CNX-Vinyl-Business-Plan-A.docx / .pdf Investor business plan, Plan A (generated) +│ ├── CNX-Vinyl-Business-Plan-B.docx / .pdf Investor business plan, Plan B (generated) │ └── build/ Python source of the plan; regenerate with │ build_plan.py ├── consulting/ Consultancy proposals and overviews diff --git a/docs/business-plan/CNX-Vinyl-Business-Plan.docx b/docs/business-plan/CNX-Vinyl-Business-Plan-A.docx similarity index 64% rename from docs/business-plan/CNX-Vinyl-Business-Plan.docx rename to docs/business-plan/CNX-Vinyl-Business-Plan-A.docx index a8c0309..243497d 100644 Binary files a/docs/business-plan/CNX-Vinyl-Business-Plan.docx and b/docs/business-plan/CNX-Vinyl-Business-Plan-A.docx differ diff --git a/docs/business-plan/CNX-Vinyl-Business-Plan.pdf b/docs/business-plan/CNX-Vinyl-Business-Plan-A.pdf similarity index 54% rename from docs/business-plan/CNX-Vinyl-Business-Plan.pdf rename to docs/business-plan/CNX-Vinyl-Business-Plan-A.pdf index cbb8b62..2c46172 100644 Binary files a/docs/business-plan/CNX-Vinyl-Business-Plan.pdf and b/docs/business-plan/CNX-Vinyl-Business-Plan-A.pdf differ diff --git a/docs/business-plan/CNX-Vinyl-Business-Plan-B.docx b/docs/business-plan/CNX-Vinyl-Business-Plan-B.docx new file mode 100644 index 0000000..2378857 Binary files /dev/null and b/docs/business-plan/CNX-Vinyl-Business-Plan-B.docx differ diff --git a/docs/business-plan/CNX-Vinyl-Business-Plan-B.pdf b/docs/business-plan/CNX-Vinyl-Business-Plan-B.pdf new file mode 100644 index 0000000..3f7a179 Binary files /dev/null and b/docs/business-plan/CNX-Vinyl-Business-Plan-B.pdf differ diff --git a/docs/business-plan/build/build_plan.py b/docs/business-plan/build/build_plan.py index ae70f51..9b0ff07 100644 --- a/docs/business-plan/build/build_plan.py +++ b/docs/business-plan/build/build_plan.py @@ -1,9 +1,12 @@ -"""Build the CNX Vinyl business plan .docx. +"""Build the CNX Vinyl business plan .docx, in its two versions (October 2026). - python build_plan.py -> ../CNX-Vinyl-Business-Plan.docx - python build_plan.py out.docx -> custom path + python build_plan.py -> ../CNX-Vinyl-Business-Plan-A.docx and -B.docx + python build_plan.py A -> ../CNX-Vinyl-Business-Plan-A.docx + python build_plan.py B out.docx -> Plan B to a custom path -Images are resolved relative to docs/ (the parent of business-plan/). +Plan A (~180M THB) and Plan B (~225M THB) share every chapter; the content modules +switch the plan-specific text with plan_variant.pick(). Images are resolved relative +to docs/ (the parent of business-plan/). """ from __future__ import annotations @@ -14,14 +17,21 @@ HERE = Path(__file__).resolve().parent sys.path.insert(0, str(HERE)) from plan_lib import Renderer # noqa: E402 +import plan_variant # noqa: E402 import content_a, content_b, content_c # noqa: E402 DOCS = HERE.parent.parent # .../docs -OUT = HERE.parent / "CNX-Vinyl-Business-Plan.docx" +VERSION = "draft 0.3, October 2026" -def main(out: Path = OUT) -> Path: - r = Renderer(DOCS, header_text="CNX Vinyl / Poy Records: Business plan, draft 0.2, October 2026", +def out_path(plan: str) -> Path: + return HERE.parent / f"CNX-Vinyl-Business-Plan-{plan}.docx" + + +def main(plan: str = "A", out: Path | None = None) -> Path: + plan_variant.PLAN = plan + out = out or out_path(plan) + r = Renderer(DOCS, header_text=f"CNX Vinyl / Poy Records: Business plan, {plan_variant.label()}, {VERSION}", footer_text="Confidential") r.render(content_a.blocks() + content_b.blocks() + content_c.blocks()) r.save(out) @@ -29,5 +39,8 @@ def main(out: Path = OUT) -> Path: if __name__ == "__main__": - target = Path(sys.argv[1]) if len(sys.argv) > 1 else OUT - print(main(target)) + args = sys.argv[1:] + plans = [args.pop(0).upper()] if args and args[0].upper() in ("A", "B") else ["A", "B"] + target = Path(args[0]) if args else None + for p in plans: + print(main(p, target if len(plans) == 1 else None)) diff --git a/docs/business-plan/build/content_a.py b/docs/business-plan/build/content_a.py index 66e5a0a..e9824d5 100644 --- a/docs/business-plan/build/content_a.py +++ b/docs/business-plan/build/content_a.py @@ -1,9 +1,15 @@ -"""Part A: cover, reading guide, executive summary, opportunity, anatomy of the plant.""" +"""Part A: cover, reading guide, executive summary, opportunity, anatomy of the plant. + +Builds Plan A (~180M THB) or Plan B (~225M THB): plan-specific text is switched with +plan_variant.pick() inside blocks(), never at import time. +""" from plan_lib import H1, H2, H3, P, B, N, T, KV, IMG, CALL, PB, TOC, COVER +from plan_variant import pick, is_a, is_b, label, name def blocks(): out = [] + LP = pick("Launch plant", "At launch") # 'When' column of the 4.0 checklist # ------------------------------------------------------------ cover out.append(COVER( @@ -17,12 +23,19 @@ def blocks(): "**Prepared by:** Simona Meesaiyati (Project Lead) and Alexander Grabowski (Technical Consultant), " "supported by buildfor.life, with Ploy Printing (Chiang Mai) as packaging partner and " "strategic co-investor", - "**Version:** Draft 0.2, October 2026", + f"**Version:** Draft 0.3, October 2026: **{name()}, {pick('~180M THB', '~225M THB')}**", ], note="Confidential. All figures in USD and THB at 1 USD = 33 THB (August 2026). Vendor quotes are " "snapshots at their file dates, not commitments. Every number in this plan is labelled as quoted, " - "researched, or estimated; see section 2. Draft 0.2 replaces draft 0.1 (September 2026): the plant " - "now launches with the whole chain, cutting and galvanics included, in one capital round.", + "researched, or estimated; see section 2. " + pick( + "This version is Plan A: the launch plant with the whole chain, cutting and galvanics " + "included, three presses, brought to ~180M THB (~177M) with six cost levers. A second " + "version, Plan B (~225M THB), launches with five presses and takes none of the levers. ", + "This version is Plan B: the whole chain, cutting and galvanics included, with five presses " + "at launch and everything in, at ~225M THB (~224M). A second version, Plan A (~180M THB), " + "launches with three presses and six cost levers. ") + + "The plan price includes the ramp-up reserve and carries no contingency. Draft 0.3 replaces " + "draft 0.2 (October 2026), which described a single launch plant priced with a contingency.", )) out.append(TOC()) @@ -41,40 +54,79 @@ def blocks(): "could go wrong. It is built from the project's planning repository and vendor documents, and it " "keeps the honest parts: where a number is an estimate, it says so; where the evidence is thin, it " "says that too."), - P("**What changed since draft 0.1.** In October 2026 the plan moved from a phased entry (one press at " - "launch, stampers bought in from the UK, cutting bought in from Europe) to a **launch plant** that " - "has the whole chain from the first day, bought in one capital round and commissioned in sequence. " - "There are no bridge stampers and no outsourced cutting in the plan any more. Every section below " - "is written for that plant."), + P("**What changed since the earlier drafts.** In October 2026 the plan moved from a phased entry (one " + "press at launch, stampers bought in from the UK, cutting bought in from Europe) to a **launch plant** " + "that has the whole chain from the first day, bought in one capital round and commissioned in " + "sequence. There are no bridge stampers and no outsourced cutting in the plan any more. Draft 0.3 " + "prices that plant in **two versions**, both including the ramp-up reserve and neither carrying a " + "contingency: **Plan A (~180M THB)**, the launch plant's three presses with six cost levers, and " + "**Plan B (~225M THB)**, five presses with everything in. " + pick( + "**This document is Plan A**, and every section below is written for it; a short table after " + "the numbers compares the two versions.", + "**This document is Plan B**, and every section below is written for it; a short table after " + "the numbers compares the two versions.")), H2("What we will build"), B([ "**The complete vinyl chain under one roof:** mastering, lacquer cutting, galvanics (growing the " "nickel stampers), stamper preparation, pressing, finishing, packaging with our Chiang Mai print " "partner Ploy Printing, and fulfilment including direct-to-fan dropshipping.", - "**Three presses at launch:** one Newbilt Duplex system (two semi-automatic presses with a main " - "and a colour extruder, for colour, splatter and short runs) and one Newbilt Classic fully " - "automatic press for long standard runs. Special prints are the focus (60 % and more of the " - "records), and specials run only on the Duplex, so together they make about 0.58 to 0.90 million " - "records a year on two shifts (0.71 to 0.97 million at a standard-heavy mix; estimates). A second " - "Duplex system is a growth option with its floor, utility " - "positions and pipe connections reserved, not part of the investment.", + pick( + "**Three presses at launch:** one Newbilt Duplex system (two semi-automatic presses with a main " + "and a colour extruder, for colour, splatter and short runs) and one Newbilt Classic fully " + "automatic press for long standard runs. Special prints are the focus (60 % and more of the " + "records), and specials run only on the Duplex, so together they make about 0.58 to 0.90 " + "million records a year on two shifts (0.71 to 0.97 million at a standard-heavy mix; " + "estimates). A second Duplex system is a growth step from revenue, with its floor, utility " + "positions and pipe connections reserved, not part of the investment.", + "**Five presses at launch:** two Newbilt Duplex systems (each two semi-automatic presses with a " + "main and a colour extruder, for colour, splatter and short runs) and one Newbilt Classic fully " + "automatic press for long standard runs. Special prints are the focus (60 % and more of the " + "records) and run only on the Duplex systems; with four semi-automatic presses they no longer " + "set the pace, so the five presses make about 1.0 to 1.5 million records a year on two shifts " + "(1.25 million in the central case; estimates). The press hall keeps room for more Duplex " + "systems and Classics as an option, not part of the investment."), "**The metal path in-house:** a Sillitoe SDMS cutting room, a Pheenix Alpha galvanics line with " "zero-discharge water treatment, and the Sibert stamper-prep line. The father and the mother of " "every side are archived, so represses start from our own metal.", "**A modular utility plant:** a boiler hall and a chiller compound built once for four modules " - "each, with two 500 kg/h boiler modules and two 250 kW chiller modules installed at launch; " - "further presses add modules, not rooms. The steam fuel (electric or biomass) is still open.", - "**Cassette duplication and CD-R duplication in-house** from launch. Full CD replication " + "each, with " + pick( + "two 500 kg/h boiler modules (B-1, B-2, bought through the Chinese route) and two 250 kW " + "chiller modules (CH-1, CH-2)", + "two 500 kg/h boiler modules (B-1, B-2) and three 250 kW chiller modules (CH-1 to CH-3)") + + " installed at launch; further presses add modules, not rooms. The steam fuel (electric or " + "biomass) is still open.", + pick("**Cassette duplication and CD-R duplication as a growth step** after launch, not in the " + "plan price; both fit inside the building programme. ", + "**Cassette duplication and CD-R duplication in-house** from launch. ") + + "Full CD replication " "(injection-moulded discs) is a separate, much larger decision, outside the totals; both CD " "routes are set out in section 4.10 for the investor to decide.", "**A purpose-built ~1,500 m² plant on long-term leased land**, with a detached utility yard, " - "rooftop solar and room for a second building.", + + pick("rooftop solar through a solar power purchase agreement (PPA)", + "owned rooftop solar with a battery") + + " and room for a second building.", "**Commissioned in sequence:** the cutting room and galvanics first (the presses need their " - "stampers), then the Duplex system, then the Classic. That puts galvanics, the hardest skill to " + "stampers), then " + pick("the Duplex system, then the Classic", + "Duplex system 1, then the Classic, then Duplex system 2") + + ". That puts galvanics, the hardest skill to " "hire, on the path to the first paying release. Sibert, the stamper-prep supplier in the plan, " "advised after the Haarlem trade show to get presses, boilers, operators and feedback loops " - "right first; the launch plant was decided anyway, and that advice is carried as a risk " - "(sections 11.2 and 13).", + "right first; " + pick("the launch plant", "the whole chain at launch") + + " was decided anyway, and that advice is carried as a risk (sections 11.2 and 13).", + pick( + "**Six cost levers bring the plant to ~180M THB**, from ~194M to ~162M THB at the midpoint " + "before the ramp-up reserve (estimates, section 8): rooftop solar and battery through a solar " + "PPA (the installer owns and finances the array, the plant buys the power); metrology in two " + "steps (XRF, inline vision and the audio station at launch, the laser confocal and the " + "wide-area profiler bought from revenue); the visitor corridor built later, so no public tours " + "at first; cassette and CD-R duplication later; a mobile crane rented for the installations, " + "with frame, runway and machine door kept crane-ready; boilers and compressor through the " + "Chinese route. Every press, the cutting room, the galvanics line and the stamper-prep line " + "stay in.", + "**Everything in, no cost levers:** owned rooftop solar and battery (and with them the BOI " + "solar measure), the full metrology stack from launch, the visitor corridor and public tours " + "from the start, a bought overhead crane, cassette and CD-R duplication, and Thai-supplied " + "boilers and compressor."), ]), H2("What makes it top-notch"), P("Four things separate this plant from a pressing shop, and they are the reason it can charge " @@ -92,8 +144,11 @@ def blocks(): "regrown from the father without a new cut. At Making Vinyl Europe in Haarlem this was what the " "industry responded to most.", "**Metrology and layered quality control.** The nickel parts are measured without contact " - "(laser confocal, wide-area profiler, XRF thickness) and logged per serial, which is ahead of " - "current industry practice. Every pressed record passes 100% inline optical inspection, every " + + pick("and logged per serial, which is ahead of current industry practice: XRF thickness from " + "launch, the laser confocal and the wide-area profiler bought from revenue. ", + "(laser confocal, wide-area profiler, XRF thickness) and logged per serial, which is ahead " + "of current industry practice. ") + + "Every pressed record passes 100% inline optical inspection, every " "press cycle is logged, and sampled records are compared automatically against the source " "master.", "**Efficiency designed in.** Heat is recovered before energy is generated: in order, a flue-gas " @@ -101,7 +156,11 @@ def blocks(): "heat pump that lifts the presses' ~60 °C cooling return into boiler feedwater. The main roof " "carries **~247 kWp** of solar (about 335 to 360 MWh a year, a quarter to a third of mature " "two-shift use; a second building's roof would take the total to ~498 kWp), with a 271 kWh " - "battery for ride-through. Cooling runs as a closed loop, no process water is discharged, " + "battery for ride-through" + pick( + ", both through the solar PPA: the installer owns and finances them, the plant buys the " + "power. ", + ", both owned by the plant. ") + + "Cooling runs as a closed loop, no process water is discharged, " "galvanics rinse water goes through a zero-discharge evaporator, and 20% of the feedstock is " "in-house regrind. Boilers and chillers come in identical modules, so spares and service are one " "routine. At reported northern fuel prices biomass heat costs a quarter to a tenth of electric " @@ -113,41 +172,114 @@ def blocks(): ]), H2("The numbers"), KV([ - ["Capacity", "Launch plant ~0.58M to 0.90M records/yr at 60 % specials (2 semi-automatic " - "presses + 1 Classic, 2 shifts; the Duplex sets the pace; estimate; the press fleet " - "calculator gives ~0.94M at our planning rates). Second Duplex as growth option: " - "~1.0M to 1.5M"], + ["Capacity", pick( + "~0.58M to 0.90M records/yr at 60 % specials (2 semi-automatic presses + 1 Classic, 2 shifts; " + "the Duplex sets the pace; estimate; the press fleet calculator gives ~0.94M at our planning " + "rates). Second Duplex as a growth step from revenue: ~1.0M to 1.5M", + "~1.0M to 1.5M records/yr at 60 % specials, central case 1.25M (4 semi-automatic presses + 1 " + "Classic, 2 shifts; the four semi-automatic presses carry the specials, so the Duplex does not " + "set the pace; estimate; the press fleet calculator gives ~1.5M at our planning rates). Full " + "hall as a later option: ~2.9M to 4.4M")], ["Site", "~1,500 m² main building plus a ~379 m² utility yard built for four boiler and four " "chiller modules, on leased land (~4 rai minimum, 6 to 8 rai with expansion); second " "building as expansion"], - ["Investment, launch plant", "~USD 4.9M to 8.9M (~THB 161M to 292M) including 15% contingency, " - "midpoint ~USD 6.9M (~THB 227M). Not in it: a ramp-up reserve of " - "~THB 10M to 20M, CD replication, financing costs, the central " - "hydraulic plant (not yet costed)"], - ["The investor's 180M THB question", "**216M THB is a realistic target** for the full equipment " - "list with four levers that keep every machine (~203M to " - "213M with the ramp-up reserve); **180M holds only if the " - "open quotes land low**"], + [pick("Investment, Plan A", "Investment, Plan B"), pick( + "**~THB 177M (~USD 5.35M), rounded to ~180M THB**: the plan investment, ~THB 161.7M (~USD " + "4.90M) at the midpoint with the six levers taken, plus a ramp-up reserve of ~THB 10M to 20M " + "(staff and overheads before volume covers them). From the low to the high end of every " + "block: ~THB 127M to 226M. Estimates: no quote yet for the Classic, the galvanics line " + "(priced at OMS's reference plus 20 %) or the building", + "**~THB 224M (~USD 6.79M), rounded to ~225M THB**: the plan investment, ~THB 209.2M (~USD " + "6.34M) at the midpoint with everything in, plus a ramp-up reserve of ~THB 10M to 20M (staff " + "and overheads before volume covers them). From the low to the high end of every block: ~THB " + "162M to 286M. Estimates: no quote yet for the Classic, the galvanics line (priced at OMS's " + "reference plus 20 %), the EX 35 or the building")], + ["Not in the plan price", "**No contingency** (at the 15 % used in the cost documents, ~THB " + + pick("24M", "31M") + " at the midpoint): quotes that land high are " + "funded outside the plan or by scope steps (section 8). Also not in " + "it: the central hydraulic plant (not yet costed), the archive's mobile " + "shelving (to quote), CD replication, financing costs, currency moves, " + "and Thai duty and import VAT (the blocks assume BOI promotion)"], ["Land lease", "Not negotiated; the plan carries an estimated THB 0.3M to 1.0M per year " "(USD 9k to 30k), section 6.1"], - ["Operating result, mature year", "Central case at 60 % specials: revenue ~USD 3.65M (~THB 120M), " - "EBITDA ~USD 1.73M (~THB 57M), operating profit ~USD 1.21M (~THB " - "40M), payback ~3.8 years (2.8 to 5.1 on the 4.9M to 8.9M band); " - "break-even on operating profit at ~0.25M records a year. **The " - "adverse case loses money:** EBITDA ~USD 0.23M, operating loss " - "~USD 0.66M (~THB 22M). Utilisation and price decide the " - "outcome, not upside (section 9)"], + ["Operating result, mature year", pick( + "Central case at 60 % specials: revenue ~USD 3.65M (~THB 120M), EBITDA ~USD 1.73M (~THB " + "57M), operating profit ~USD 1.34M (~THB 44M); break-even on operating profit at ~0.2M " + "records a year. **The adverse case loses money:** EBITDA ~USD 0.23M, operating loss ~USD " + "0.39M (~THB 13M); it would need ~0.9M records a year to cover depreciation and the three " + "presses make 0.58M at that rate. The solar PPA's power price (~USD 0.03M a year in the " + "calculator) is not in these figures. Utilisation and price decide the outcome, not upside " + "(section 9)", + "Central case at 60 % specials: revenue ~USD 6.05M (~THB 200M), EBITDA ~USD 3.14M (~THB " + "104M), operating profit ~USD 2.63M (~THB 87M); break-even on operating profit at ~0.22M " + "records a year. **The adverse case only just covers depreciation:** EBITDA ~USD 0.83M, " + "operating profit ~USD 0.02M. **All of it needs the records to sell:** ~1.25M a year in the " + "central case, ~0.75M of them specials, and no market evidence shows that demand yet. " + "Utilisation and price decide the outcome, not upside (section 9)")], + ["Payback", pick( + "~3.1 years on the plan price in the central case (2.2 to 4.0 from the low to the high end of " + "the price); ~1.0 year in the favourable case, ~30 years in the adverse case (EBITDA, mature " + "year, ramp-up reserve included; estimates)", + "~2.2 years on the plan price in the central case (1.6 to 2.8 from the low to the high end of " + "the price); ~0.8 year in the favourable case, ~10.5 years in the adverse case (EBITDA, mature " + "year, ramp-up reserve included; estimates)")], ["First paying release", "**Open.** The August 2026 calendar gives Q4 2028 to mid-2029 (27 to 33 " "months from the start of phase 0), but it was drawn for a one-press " "launch. Commissioning the cutting room and galvanics before the presses " "is not yet in it, and the lathe, galvanics line and stamper-prep build " "times are not on file, so the date stays open until those vendors " - "quote. Ordering machinery before the BOI certificate, if allowed, could " + "quote." + pick("", " Plan B commissions its second Duplex system last, " + "after the Classic.") + + " Ordering machinery before the BOI certificate, if allowed, could " "still pull it forward by 6 to 9 months (section 10)"], - ["People", "~15 to 25 across shifts at volume (estimate); the launch plant needs most of that " - "crew, because two shifts still need press, finishing, galvanics, QC and maintenance " - "staff (13 to 19 direct production staff in the revenue model)"], + ["People", pick( + "~15 to 25 across shifts at volume (estimate); the launch plant needs most of that " + "crew, because two shifts still need press, finishing, galvanics, QC and maintenance " + "staff (13 to 19 direct production staff in the revenue model)", + "~15 to 25 across shifts at volume (estimate); two shifts need press, finishing, galvanics, QC " + "and maintenance staff whether the plant runs three presses or five, so Plan B's five presses " + "run on the same direct crews (13 to 19 direct production staff in the revenue model) and " + "spread them over more records")], + ["The ask", pick( + "~THB 177M (~USD 5.35M), the ~180M THB plan, released in tranches against milestones " + "(section 8), starting with phase 0 (~THB 1.3M to 2.6M). BOI caps debt-to-equity at 3:1, so " + "at least a quarter is equity: ~THB 44M (arithmetic, before financing costs)", + "~THB 224M (~USD 6.79M), the ~225M THB plan, released in tranches against milestones " + "(section 8), starting with phase 0 (~THB 1.3M to 2.6M). BOI caps debt-to-equity at 3:1, so " + "at least a quarter is equity: ~THB 56M (arithmetic, before financing costs)")], ]), + H2("Two versions of this plan"), + P("This plan comes in two versions, built from the same documents and the same machine choices. " + pick( + "This document is **Plan A**. The other version, **Plan B (~225M THB)**, puts the second Duplex " + "system in at launch, for five presses, and takes none of the six levers. ", + "This document is **Plan B**. The other version, **Plan A (~180M THB)**, launches with three " + "presses (one Duplex system and the Classic), takes six cost levers and keeps the second Duplex " + "as a growth step from revenue. ") + + "Both carry the ramp-up reserve and neither carries a contingency. What decides between them is " + "demand: Plan B's central case needs about 70 % more records sold than Plan A's (1.25 against 0.74 " + "million a year), and the market validation gate (section 3.2) is the evidence for that. Section 8 " + "sets the two side by side."), + T(["", "Plan A", "Plan B"], [ + ["Plan price (ramp-up reserve in, no contingency)", "~THB 177M (~USD 5.35M); ~127M to 226M from " + "the low to the high end", "~THB 224M (~USD 6.79M); ~162M to 286M from the low to the high end"], + ["Presses", "3: one Duplex system (2 semi-automatic) and one Classic", + "5: two Duplex systems (4 semi-automatic) and one Classic"], + ["Records a year at 60 % specials", "~0.58M to 0.90M (central 0.74M)", + "~1.0M to 1.5M (central 1.25M)"], + ["EBITDA, central case", "~USD 1.73M (~THB 57M)", "~USD 3.14M (~THB 104M)"], + ["Operating profit, central case", "~USD 1.34M (~THB 44M)", "~USD 2.63M (~THB 87M)"], + ["Payback on the plan price, central case", "~3.1 years (2.2 to 4.0)", "~2.2 years (1.6 to 2.8)"], + ["Adverse case", "Loses money: EBITDA ~USD 0.23M, operating loss ~USD 0.39M", + "Just covers depreciation: EBITDA ~USD 0.83M, operating profit ~USD 0.02M"], + ["What Plan A gives up, what Plan B needs", "At launch: solar through a PPA (very likely without " + "the BOI solar measure), no confocal or profiler, no visitor corridor or tours, no cassette or " + "CD-R, a rented crane; Chinese-made boilers and compressor", + "~1.25M records sold a year, ~0.75M of them specials, against 0.74M for Plan A; no market " + "evidence of that demand yet"], + ], widths_mm=[42, 64, 64], font_pt=8.5, + caption="Estimates: mature year at 60 % specials, from the revenue model; payback counted on the " + "whole plan price including the reserve. Central EBITDA margins of ~47 % (A) and ~52 % (B) " + "are far above the 15 to 25 % pressing plants earn; read the adverse case as the honest one."), H2("Where we are, and what we ask"), P("The project is at the planning stage. Industry outreach has run for several years. Alexander and " "Simona attended **Making Vinyl Europe in Haarlem** (30 September to 2 October 2026): most people " @@ -170,18 +302,33 @@ def blocks(): CALL("What the investor is asked to fund now", [ "**Phase 0 (next 3 to 6 months): ~USD 40k to 80k (~THB 1.3M to 2.6M)** for the BOI consultant, " "Thai legal work on the lease and zoning, a soil boring test, and the requests that settle most " - "of the investment band: the Newbilt re-quote for the Duplex and the Classic, a Pheenix quote for " - "the galvanics line, the building price request with the soil test, and metrology distributor " - "quotes.", - "**Then the launch plant round, targeted at ~THB 216M (~USD 6.55M)**, released in tranches " - "against milestones: BOI certificate and lease signed, long-lead orders (lathe, galvanics, " - "stamper prep, presses, first boiler and chiller modules), building contract, fit-out, " - "commissioning in sequence (section 8.3). The full estimate band is THB 161M to 292M; section " - "8.2 shows the levers that bring the midpoint inside 216M.", - "**Decisions needed from the investor:** the equity/debt mix (BOI requires debt-to-equity of at " - "most 3:1); CD replication, yes or no (it must be in the BOI application from the start); the " - "steam fuel, electric or biomass; and which budget levers to take (solar through a PPA, " - "metrology bought in two steps, the visitor corridor later).", + "of the investment band: " + pick( + "the Newbilt re-quote for the Duplex system (with an EX 35 price) and the Classic, a Pheenix " + "quote for the galvanics line, the building price request with the soil test, metrology " + "distributor quotes and a solar PPA offer.", + "the Newbilt re-quote for both Duplex systems (with an EX 35 price) and the Classic, a Pheenix " + "quote for the galvanics line, the building price request with the soil test, and metrology " + "distributor quotes."), + pick( + "**Then the Plan A round, ~THB 177M (~USD 5.35M), rounded to ~180M THB**, including the " + "ramp-up reserve and without contingency, released in tranches against milestones: BOI " + "certificate and lease signed, long-lead orders (lathe, galvanics, stamper prep, presses, " + "boiler and chiller modules), building contract, fit-out, commissioning in sequence " + "(section 8). From the low to the high end of every block the plan runs from ~THB 127M to " + "226M; quotes that land high are funded outside the plan or by scope steps.", + "**Then the Plan B round, ~THB 224M (~USD 6.79M), rounded to ~225M THB**, including the " + "ramp-up reserve and without contingency, released in tranches against milestones: BOI " + "certificate and lease signed, long-lead orders (lathe, galvanics, stamper prep, both Duplex " + "systems and the Classic, boiler and chiller modules), building contract, fit-out, " + "commissioning in sequence (section 8). From the low to the high end of every block the plan " + "runs from ~THB 162M to 286M; quotes that land high are funded outside the plan or by scope " + "steps."), + "**Decisions needed from the investor:** which version to fund, Plan A or Plan B (demand decides " + "first, from market validation; then the Classic, Pheenix and EX 35 quotes, the solar PPA offer " + "and the building quote); the equity/debt mix (BOI requires debt-to-equity of at most 3:1, so at " + "least ~THB " + pick("44M of Plan A's ~177M", "56M of Plan B's ~224M") + " is equity); CD " + "replication, yes or no (it must be in the BOI application from the start); and the steam fuel, " + "electric or biomass.", "**Co-investment:** Ploy Printing, the Chiang Mai print and packaging house that will produce " "the plant's jackets and sleeves, has expressed the intention to invest alongside the lead " "investor. Terms are not yet discussed; the intended structure is described in section 12.", @@ -189,6 +336,12 @@ def blocks(): # ----------------------------------------------- 2 reading guide H1("2. How to read the numbers"), + P("**Two versions.** This business plan comes in two versions, built from the same documents: " + "**Plan A (~180M THB)**, the launch plant's three presses with six cost levers, and **Plan B " + "(~225M THB)**, five presses with everything in. Both plan prices include the ramp-up reserve and " + "neither carries a contingency. This document is **" + label() + "**. Chapters that do not depend " + "on the choice read the same in both; where the plans differ, this version gives its own figures, " + "and sections 1 and 8 compare the two."), P("Every figure in this plan carries one of three confidence levels. Where a table does not say, " "the basis column or caption does."), T(["Label", "Meaning", "Examples"], [ @@ -202,15 +355,18 @@ def blocks(): "pressing invoices (August 2026); the PEA electricity tariff; vendor " "flyers and datasheets; reported biomass fuel prices; BOI measures"], ["Estimate", "Engineering ratio or industry norm with no vendor confirmation. Treat as " - "plus or minus 30 to 50%.", "Building cost per m²; the Pheenix galvanics line and the " - "Newbilt Classic (no price on file); the cutting room " - "beyond the lathe; metrology stack; land lease; all " - "cassette and CD figures"], + "plus or minus 30 to 50%.", "Building cost per m²; the Pheenix galvanics line (no " + "Pheenix price on file; priced at OMS's reference plus " + "20 %) and the Newbilt Classic (no price on file); the " + "cutting room beyond the lathe; metrology stack; land " + "lease; " + pick("the solar PPA power price; ", "") + + "all cassette and CD figures"], ], widths_mm=[22, 70, 78]), P("Currency: USD and THB at 1 USD = 33 THB (5 August 2026). Vendor quotes issued in EUR or GBP are " "kept in their currency next to their source and converted at 1 EUR = 1.155 USD and " "1 GBP = 1.35 USD. Currency exposure is real and is discussed in section 8.5."), - P("Deliberately **not** in this plan: a financing structure or terms (to be agreed with the investor); " + P("Deliberately **not** in this plan: a contingency in the plan price (section 8); a financing " + "structure or terms (to be agreed with the investor); " "a signed customer; a signed lease; firm quotes for the Classic, the galvanics line, the metrology " "stack or the building; a price for the central hydraulic plant; and a year-by-year cash model. " "Each of these is a named next step in section 14."), @@ -236,7 +392,9 @@ def blocks(): "is the gap. It is also the plan's biggest assumption: that enough regional customers will pay for " "a closer, faster, more accountable plant at a price that works. That pricing power is unproven. " "The Haarlem trade show produced strong supplier interest but no buyer prices, and the market " - "validation gate exists to test it before capital is committed."), + "validation gate exists to test it before capital is committed." + pick( + "", " Plan B makes the assumption heavier: its central case sells ~1.25 million records a year, " + "~0.75 million of them special editions, against 0.74 million for the three-press Plan A.")), H2("3.3 What the market shows: two price points"), P("Two sets of real prices now exist: invoices from the one Thai pressing shop we have seen, and the " "published calculator of a European plant. Neither is used to re-base the financial model, which " @@ -260,9 +418,12 @@ def blocks(): P("What the tour showed: the shop operates from a small non-industrial premises; it does not plate " "(stampers are bought in from abroad and resold); there is no temperature, humidity or particulate " "control on the pressing floor; and it runs two Newbilt presses, a Classic fully automatic and one " - "semi-automatic, about 190 to 210 records an hour at nameplate. That is a real capital fleet. Our " - "launch plant's three presses (248 to 288 records an hour at nameplate, planned for two shifts) " - "out-press it on paper, which the one-press launch of draft 0.1 did not. Neither figure is " + "semi-automatic, about 190 to 210 records an hour at nameplate. That is a real capital fleet. " + pick( + "Our launch plant's three presses (248 to 288 records an hour at nameplate, planned for two " + "shifts) ", + "Plan B's five presses (four semi-automatic at 60 to 80 records an hour each plus the Classic at " + "~128, 368 to 448 records an hour at nameplate, planned for two shifts) ") + + "out-press it on paper, which the one-press launch of draft 0.1 did not. Neither figure is " "measured output: their shifts and order book were not observed."), H3("A European plant: Record Industry's calculator"), P("Record Industry (Haarlem, Netherlands) publishes an online calculator. For a 12-inch 140 g black " @@ -287,8 +448,8 @@ def blocks(): "been asked (roadmap item 1)."), P("Four readings follow, each with its caveat:"), B([ - "**Our assumed price sits between the two markets.** The plan prices a record at USD 3.50 to 4.60 " - "blended (115 to 150 THB). The Thai market pays 535 to 780 THB on a comparable scope, several " + "**Our assumed price sits between the two markets.** The plan prices a record at USD 3.76 to 5.27 " + "blended at 60 % specials (124 to 174 THB; 3.50 to 4.60 at a standard-heavy mix). The Thai market pays 535 to 780 THB on a comparable scope, several " "times more, even after allowing 100 to 150 THB for the jacket. A European plant's published " "price for black pressing with labels and an inner sleeve (~USD 2.43 at 300) is below our " "assumption, though our blend also carries colour work and assembly. Two caveats: a sole " @@ -324,7 +485,9 @@ def blocks(): "add-on with modest capital. CDs remain a large format in Asia (Japan and Korea in particular), " "but industrial CD replication is an established, price-competitive business with existing " "capacity across the region. Sections 4.9 and 4.10 lay out both formats and the two very " - "different CD routes; cassette and CD-R duplication are in the launch plant."), + "different CD routes; " + pick( + "Plan A adds cassette and CD-R duplication after launch, as a growth step outside its price.", + "cassette and CD-R duplication are in Plan B from launch.")), # ------------------------------------------ 4 anatomy of the plant H1("4. Anatomy of a top-notch plant: the full chain"), @@ -341,62 +504,63 @@ def blocks(): T(["What a top-notch plant needs", "Why it matters", "This plan", "When"], [ ["A quiet, vibration-free cutting room with a modern lathe", "The groove is born here; every " "defect propagates to every record", "Sillitoe SDMS complete cutting system in-house; Agnew " - "Type 612 as the other candidate", "Launch plant, " - "commissioned first"], + "Type 612 as the other candidate", LP + ", commissioned first"], ["In-house galvanics with zero-discharge water", "The regional bottleneck; enables represses in " "days and short runs", "Pheenix Alpha line (PASU, PPPU, one PDPU, PMPB); evaporator-based " "zero discharge and DI water in a treatment building next to it", - "Launch plant, commissioned first"], + LP + ", commissioned first"], ["Stamper preparation machines", "Turns a raw nickel shell into a press-ready part", - "Sibert back-finisher, punch, coiner (USD 250k budget confirmed)", "Launch plant, with " - "galvanics"], + "Sibert back-finisher, punch, coiner (USD 250k budget confirmed)", LP + ", with galvanics"], ["A mixed press fleet", "Semi-automatic for colour and short runs, automatic for long runs", - "Newbilt Duplex system (2 presses, main + colour extruder) and one Newbilt Classic", - "Launch plant; second Duplex as growth option"], + pick("Newbilt Duplex system (2 presses, main + colour extruder) and one Newbilt Classic", + "Two Newbilt Duplex systems (4 presses, each system with main + colour extruder) and one " + "Newbilt Classic"), + pick("Launch plant; second Duplex as growth option", + "At launch, second Duplex system commissioned last; full hall as an option")], ["Steam, cooling and compressed air engineered locally", "The largest energy loads; efficiency " - "lives here", "Boiler hall and chiller compound for four modules each; 2 x 500 kg/h boilers and " - "2 x 250 kW chillers; heat recovery designed in", "Launch plant; modules added " - "with presses"], + "lives here", "Boiler hall and chiller compound for four modules each; " + pick( + "2 x 500 kg/h boilers (Chinese route) and 2 x 250 kW chillers", + "2 x 500 kg/h boilers and 3 x 250 kW chillers") + "; heat recovery designed in", + LP + "; modules added with presses"], ["Whole-plant climate and particulate control", "Moisture and dust are the two classic record " "defects", "20 to 26 °C, 35 to 60% RH, filtration for the burning season, tighter in clean " - "zones", "Launch plant"], + "zones", LP], ["Metrology for the metal parts", "Data-backed accept/reject before a stamper is mounted", - "Laser confocal, wide-area profiler, XRF thickness, inline vision", "Launch plant (confocal " - "and profiler can follow " - "from revenue)"], + pick("XRF thickness and inline vision at launch; laser confocal and wide-area profiler from " + "revenue", + "Laser confocal, wide-area profiler, XRF thickness, inline vision"), + pick("Launch plant (confocal and profiler from revenue)", "At launch, full stack")], ["Layered QC for every record", "Catch defects at line speed without playing every record", - "100% optical inspection, per-cycle telemetry, sampled audio comparison", "Launch plant"], + "100% optical inspection, per-cycle telemetry, sampled audio comparison", LP], ["Traceability from file to shipment", "Complaints resolve backwards; customers see their " "order; machine data access is a purchasing condition", "ERPNext as the only system of record, " "machine data keyed to it, customer " - "portal", "Launch plant (v1 before " - "the machines arrive)"], + "portal", LP + " (v1 before the " + "machines arrive)"], ["A materials lab", "PVC lots differ; a bad lot is a noisy run", "Per-lot gate: moisture, heat " - "stability, colour, density, granulate; release by test pressing", "Launch plant (day-one " - "tier)"], + "stability, colour, density, granulate; release by test pressing", LP + " (day-one tier)"], ["A packaging partner and packaging QC", "Jackets are the path that slips; the wrong " "record in the right jacket is the classic error", "Ploy Printing (Chiang Mai) for jackets, " "sleeves, J-cards; matrix code scanned " - "against jacket barcode", "Launch plant"], + "against jacket barcode", LP], ["An archive for fathers and mothers", "Irreplaceable metal; repress economics", "Father and mother of every side; fire-rated, climate-controlled room, clean-agent suppression, " - "mobile shelving (to quote)", "Launch plant"], + "mobile shelving (to quote)", LP], ["Renewable energy and closed-loop water", "Cost, resilience, brand, BOI tax value", - "~247 kWp roof PV, 271 kWh battery, closed cooling loop, zero process discharge", "Launch plant " - "(PV possibly " - "through a " - "solar PPA)"], + pick("~247 kWp roof PV and 271 kWh battery through a solar PPA (installer-owned), closed cooling " + "loop, zero process discharge", + "~247 kWp roof PV and 271 kWh battery (owned), closed cooling loop, zero process discharge"), + pick("Launch plant (PV and battery through a solar PPA)", "At launch")], ["Trained people and a safety program", "Steam at 10 bar, hydraulics at 180 bar, plating " - "chemistry", "Vendor commissioning training, in-house program, PPE, clean rooms", "Launch plant; " - "galvanics " - "hiring first"], + "chemistry", "Vendor commissioning training, in-house program, PPE, clean rooms", + LP + "; galvanics hiring first"], ["An ordering platform for every customer", "Short runs need a channel; transparency is the " "brand", "Itemised price calculator, upload checks, fan-funded campaigns (section 4.8)", "Calculator early; campaigns after first releases ship"], ["Cassette and CD lines", "Same customers, one order, one shipment", "In-house cassette " - "duplication; CD-R duplication; CD replication as a separate option", "Launch plant " - "(replication only if " - "chosen)"], + "duplication; CD-R duplication; CD replication as a separate option", + pick("Growth step after launch, not in the plan price (replication only if chosen)", + "At launch (replication only if chosen)")], ], widths_mm=[40, 45, 55, 30], font_pt=8.5), H2("4.1 Mastering and lacquer cutting"), @@ -453,7 +617,8 @@ def blocks(): "treatment and metal recovery system. The chemistry (silver nitrate, nickel salts) sets the safety " "and permitting requirements: decontamination procedures, PPE, locked chemical storage, eyewash " "and emergency shower, and hazardous-substance registration. Because galvanics is now in the " - "launch plant, the site's zoning and the first factory licence have to allow electroplating from " + + pick("launch plant", "plant from launch") + + ", the site's zoning and the first factory licence have to allow electroplating from " "the start."), P("**Who supplies it.** The plan is a **Pheenix Alpha** line (Sweden): the PASU automatic silvering " "unit, the PPPU pre-plating unit (four masters at once), one PDPU dual plating unit (two cells, up " @@ -470,12 +635,16 @@ def blocks(): "gives about 15 to 30 minutes for pre-plate, ~75 minutes for a father, about an hour for a mother " "and ~45 minutes for a stamper (silvering and bench times are estimates). With loading and rinsing, " "a cell turns a part in about 1 to 1.5 hours, so one PDPU makes 20 to 32 parts in a two-shift day " - "against 8 to 20 parts a working day even for the larger five-press fleet. **One PDPU covers the " + "against 8 to 20 parts a working day " + + pick("even for the larger five-press fleet", "for Plan B's five presses") + + ". **One PDPU covers the " "demand; a second would buy redundancy, not capacity.** By OMS's rule of thumb (one person runs " "about 20 stampers a day) that is one galvanics operator per shift."), - P("**Cost and risk.** Estimated USD 320k to 650k (THB 10.6M to 21.4M) for the Pheenix line, with no " - "Pheenix price on file; OMS's reference prices sit at the low end, and pricing near them is one of " - "the four budget levers. The zero-discharge and DI water plant adds an estimated USD 97k to 258k " + P("**Cost and risk.** Pheenix has not quoted, so the plan prices its line at **OMS's reference plus " + "20 %**: OMS's 4-cell wet room with the EUR 10,000 know-how transfer (nobody on the team has run a " + "plating room), EUR 234,000 to 321,000, times 1.2 gives EUR 280,800 to 385,200, ~USD 324k to 445k " + "(THB 10.7M to 14.7M; an estimate, replacing the earlier estimate of USD 320k to 650k). The " + "zero-discharge and DI water plant adds an estimated USD 97k to 258k " "and its building USD 52k to 87k. Galvanics is the hardest skill to hire and it is now on the " "path to the first release, because the presses need its stampers. Sibert advised getting each " "main step right and earning some return before every manufacturing step is in place; that advice " @@ -513,30 +682,48 @@ def blocks(): "Duplex share mould inserts, so the plant runs one mould family, one set of spares and one service " "relationship; the cost is a single-vendor dependency."), T(["Machine", "Role", "Basis", "Cost"], [ - ["Newbilt Duplex system (Alsdorf, Germany)", "Two HRP 12 hydraulic presses (~150 t), EX 50 main " + [pick("Newbilt Duplex system (Alsdorf, Germany)", "Newbilt Duplex system 1 (Alsdorf, Germany)"), + "Two HRP 12 hydraulic presses (~150 t), EX 50 main " "extruder and EX 35 colour extruder, 12-inch book moulds for 140/180 g, trimmer, label dry oven, " "shrink wrapper, PVC grinder, label punch, spindles and plates; one operator's cell", "Quoted: EUR 200,500 (~USD 232k) for the Single 2.1 system incl. sea freight, June 2024, plus " "the quoted second press and extruder (~USD 115k); expired, re-quote required with build time", "USD 350k to 370k (THB 11.6M to 12.2M)"], + *pick([], [[ + "Newbilt Duplex system 2", "Two more HRP 12 presses with an EX 50 main and an EX 35 colour " + "extruder, on the same central hydraulics; commissioned after the Classic", + "Estimate on the 2024 quote: two presses at the quoted ~USD 115k per press and extruder set, " + "plus a hydraulic unit and the EX 35; no EX 35 price on file", + "USD 230k to 300k (THB 7.6M to 9.9M)"]]), ["Newbilt Classic", "Fully automatic press with built-in extruder, automatic patty, label and " "record handling; 28 s cycle, ~128 records/h at 180 g; Siemens safety PLC with OPC UA; " "vendor-claimed 95% yield and uptime", "Estimate: placeholder band; **no Newbilt price on " "file**", "USD 290k to 460k (THB 9.6M to 15.2M)"], - ["Second Duplex system (growth option)", "Two more semi-automatic presses on the same central " - "hydraulics; floor, utility positions and ring-main tees reserved", "Estimate; not in the " - "investment", - "~USD 230k to 300k"], + *pick([["Second Duplex system (growth option)", "Two more semi-automatic presses on the same central " + "hydraulics; floor, utility positions and ring-main tees reserved", "Estimate; not in the " + "investment", + "~USD 230k to 300k"]], []), ], widths_mm=[34, 66, 42, 28], font_pt=8.5), P("The Pheenix Alpha AD12 automatic press left the plan in October 2026 and stays the comparison if " "the Classic re-quote disappoints."), P("**What Newbilt deliberately excludes**, and what is engineered and sourced locally: steam and " - "cooling. At Newbilt's per-machine figures the three presses draw about 450 to 540 kg/h of steam " - "at 10 bar / 180 °C and up to ~390 kW of cooling on a hot afternoon (estimates; the Classic is " - "counted as one press and extruder until Newbilt states its own figures). They are met by **two " - "500 kg/h boiler modules and two 250 kW chiller modules**, in a boiler hall and an open chiller " - "compound built for four modules each; a second Duplex adds a third chiller module, and the fourth " - "positions are reserve and growth. The presses share one central hydraulic plant and one " + "cooling. " + pick( + "At Newbilt's per-machine figures the three presses draw about 450 to 540 kg/h of steam " + "at 10 bar / 180 °C and up to ~390 kW of cooling on a hot afternoon (estimates; the Classic is " + "counted as one press and extruder until Newbilt states its own figures). They are met by **two " + "500 kg/h boiler modules (B-1, B-2) and two 250 kW chiller modules (CH-1, CH-2)**, in a boiler " + "hall and an open chiller compound built for four modules each; a second Duplex adds a third " + "chiller module, and the fourth positions are reserve and growth. Plan A buys the two boiler " + "modules through the Chinese route: ASME-stamped 1.25 MPa units from makers with Thai " + "references, installed by a Thai contractor and verified under the Thai rules for imported " + "boilers (section 5.4). ", + "At Newbilt's per-machine figures the five presses draw about 750 to 900 kg/h of steam " + "at 10 bar / 180 °C and up to ~650 kW of cooling with extruders and hydraulics on a hot " + "afternoon (estimates; the Classic is counted as one press and extruder until Newbilt states " + "its own figures). They are met by **two 500 kg/h boiler modules (B-1, B-2) and three 250 kW " + "chiller modules (CH-1 to CH-3)**, in a boiler hall and an open chiller compound built for four " + "modules each; the fourth positions are reserve and growth. ") + + "The presses share one central hydraulic plant and one " "compressed-air plant through ring mains with a valved tee at every press position, so a new press " "is connected without stopping the others; the standby pump set, accumulators and ring main are " "not yet costed. These are the largest energy systems in the plant and the reason the efficiency " @@ -546,7 +733,7 @@ def blocks(): "materials and finished goods. A press weighs 1,350 kg on under one square metre, so the floor slab " "must carry several tonnes per square metre and is a building-selection criterion; the floor must " "be flat, non-slip and solvent-resistant."), - T(["Stage", "Fleet", "Rough output per year"], [ + T(["Stage", "Fleet", "Rough output per year"], pick([ ["Launch plant", "1 Duplex system (2 semi-automatic) + 1 Classic, 2 shifts", "~0.58 to 0.90 million records at 60 % specials (0.71 to 0.97 at ~20 %)"], ["Growth option: second Duplex", "4 semi-automatic + 1 Classic, 2 shifts; room reserved, not in " @@ -554,13 +741,26 @@ def blocks(): ["Full hall (option)", "5 Duplex systems + 4 Classics, the press hall laid out for Duplex " "(special pressings first, ~73/27 by floor); a utility phase of its own", "~2.9 to 4.4 million records at 60 % specials (estimate)"], - ], widths_mm=[40, 80, 50], - caption="Basis: semi-automatic 60 to 80 records/h assumed; Classic ~128/h (vendor flyer); 16 h/day, " - "300 days/yr, 60 to 70% overall equipment effectiveness; specials (60 % and more) only on the Duplex. " - "The launch plant is 248 to 288 records/h at nameplate, but at 60 % specials the Duplex caps " - "it at 200 to 267/h, ~120 to 187/h after effectiveness; the press fleet calculator at " - "the team's planning rates gives ~0.94 million. Neither option is in the revenue model " - "or the investment."), + ], [ + ["Plan B at launch", "2 Duplex systems (4 semi-automatic) + 1 Classic, 2 shifts", + "~1.0 to 1.5 million records at 60 % specials (central case 1.25 million)"], + ["Full hall (option)", "5 Duplex systems + 4 Classics, the press hall laid out for Duplex " + "(special pressings first, ~73/27 by floor); a utility phase of its own", + "~2.9 to 4.4 million records at 60 % specials (estimate)"], + ]), widths_mm=[40, 80, 50], + caption=pick( + "Basis: semi-automatic 60 to 80 records/h assumed; Classic ~128/h (vendor flyer); 16 h/day, " + "300 days/yr, 60 to 70% overall equipment effectiveness; specials (60 % and more) only on the " + "Duplex. The launch plant is 248 to 288 records/h at nameplate, but at 60 % specials the " + "Duplex caps it at 200 to 267/h, ~120 to 187/h after effectiveness; the press fleet calculator " + "at the team's planning rates gives ~0.94 million. Neither option is in the revenue model " + "or the investment.", + "Basis: semi-automatic 60 to 80 records/h assumed; Classic ~128/h (vendor flyer); 16 h/day, " + "300 days/yr, 60 to 70% overall equipment effectiveness; specials (60 % and more) only on the " + "Duplex systems. The five presses are 368 to 448 records/h at nameplate; the four " + "semi-automatic presses (240 to 320/h) carry the specials, so at 60 % the Duplex does not " + "limit the output; the press fleet calculator at the team's planning rates gives ~1.5 million. " + "The full hall is in neither the revenue model nor the investment.")), P("**On the 60 to 70% effectiveness figure.** Newbilt publishes 95% yield and 95% uptime for the " "Classic. We have not adjusted the plan on that basis, deliberately: a vendor's machine uptime " "excludes stamper and mould changes, colour changeovers, compound lot changes, first-article QC " @@ -687,16 +887,21 @@ def blocks(): "(National Audio Company in the US is the largest tape source; shell moulders exist in China and " "should be sought in Thailand). Supply risk is real and the plan is to hold stock. **Positioning:** " "cassettes are a boutique add-on for the same indie customers, with shells in colours that match " - "the record. **Effect on the plan:** in the launch plant, starting at tier A or a small tier B; " - "cassette and CD-R together are one estimated block of USD 55k to 190k in the investment; " - "schedule-neutral; fits inside the building programme; the activity goes into the BOI " - "application. Moving both later is one of the scope cuts that would be needed to approach " - "180M THB."), + "the record. **Effect on the plan:** " + pick( + "Plan A adds cassette and CD-R duplication after launch, as a growth step from revenue, " + "starting at tier A or a small tier B. Together they are one estimated block of USD 55k to " + "190k (~THB 4.0M at the midpoint), not in Plan A's price: moving them later is one of its six " + "cost levers. They fit inside the building programme, and the activity can still go into the " + "BOI application from the start (to confirm with the BOI consultant).", + "in Plan B from launch, starting at tier A or a small tier B; cassette and CD-R together are " + "one estimated block of USD 55k to 190k in the investment; schedule-neutral; fits inside the " + "building programme; the activity goes into the BOI application. Plan A, the other version, " + "moves both to after launch as one of its cost levers.")), H2("4.10 CD: two very different routes (investor decision)"), P("'CD manufacturing' can mean two things that differ by two orders of magnitude in capital, and the " "investor is asked to choose."), - T(["", "Option A: CD-R duplication", "Option B: CD replication"], [ + T(["", "Route 1: CD-R duplication", "Route 2: CD replication"], [ ["What it is", "Blank recordable discs are burned and printed by robotic duplicators. The " "result is a CD-R, playable in almost all players, with full-colour on-disc print.", "Discs are injection-moulded from polycarbonate against a nickel stamper (made by glass " @@ -726,14 +931,19 @@ def blocks(): "electroforming skill set and the clean-room discipline of the vinyl galvanics room, but not " "the equipment"], ], widths_mm=[24, 68, 78], font_pt=8.5, - caption="Estimate throughout. Option B figures are order-of-magnitude and would need a dedicated " + caption="Estimate throughout. Route 2 figures are order-of-magnitude and would need a dedicated " "feasibility study."), - P("**Recommendation.** Option A is in the launch plant: it is cheap, schedule-neutral, and serves the " - "plant's customers. Treat Option B as a separate project with its own market study, because CD " + P("**Recommendation.** " + pick( + "Route 1 is the CD route for this plant: it is cheap, schedule-neutral, and serves the plant's " + "customers; Plan A adds it after launch together with the cassette line. ", + "Route 1 is in Plan B from launch: it is cheap, schedule-neutral, and serves the plant's " + "customers. ") + + "Treat Route 2 as a separate project with its own market study, because CD " "replication is a mature, competitive, declining business outside Asia's strongholds and would " "add USD 1.5M to 4.0M and a second building to a plan whose vinyl economics do not depend on it. " - "If the investor wants Option B, the decision must be taken before the BOI application is filed " - "(section 7), and the second building should be designed for it. This plan's totals include " - "Option A only; Option B is shown as a separate line."), + "If the investor wants Route 2, the decision must be taken before the BOI application is filed " + "(section 7), and the second building should be designed for it. " + pick( + "Plan A's price includes neither route; Route 1 is a growth step and Route 2 a separate line.", + "This plan's totals include Route 1 only; Route 2 is shown as a separate line.")), ] return out diff --git a/docs/business-plan/build/content_b.py b/docs/business-plan/build/content_b.py index e01073d..78037ca 100644 --- a/docs/business-plan/build/content_b.py +++ b/docs/business-plan/build/content_b.py @@ -1,6 +1,9 @@ """Part B: what makes it top-notch (traceability, metrology, QC, efficiency); site and building; -regulatory (BOI and licences). Draft 0.2, October 2026.""" +regulatory (BOI and licences). Draft 0.3, October 2026: one text for both versions, Plan A (~180M +THB, the launch plant with six cost levers) and Plan B (~225M THB, five presses, everything in); the +plan-specific passages switch with plan_variant.pick(), called inside blocks().""" from plan_lib import H1, H2, H3, P, B, N, T, KV, IMG, CALL, PB +from plan_variant import pick, is_a, is_b, label, name def blocks(): @@ -13,7 +16,7 @@ def blocks(): "capabilities are what a regional customer cannot buy today and what justifies export-grade " "pricing. None of it is exotic: the instruments exist, the data interfaces exist, and the " "engineering is well understood. What is unusual is putting all of it in one plant from the " - "start rather than bolting it on later. The launch plant makes that possible: with the cutting " + "start rather than bolting it on later. The plan makes that possible: with the cutting " "room and galvanics in-house from the first release, the whole chain from lacquer to box runs " "through our own floor, with no bought-in stamper whose history we cannot see."), @@ -148,16 +151,16 @@ def blocks(): T(["Instrument", "What it measures", "How it is used", "When"], [ ["XRF thickness gauge (Fischer or Bowman class)", "Nickel deposit thickness, non-destructive", "Per serial, read on the outer land zones; replaces the ten-point micrometer. Target total " - "thickness variation 10 to 20 microns", "Launch tier"], - ["Inline machine vision", "Cosmetic defects", "100% of parts, fast", "Launch tier"], + "thickness variation 10 to 20 microns", "At launch"], + ["Inline machine vision", "Cosmetic defects", "100% of parts, fast", "At launch"], ["3D laser confocal microscope (Keyence VK-X class)", "Groove cross-section, wall roughness, " "micro-defects; 20 nm vertical, ~120 nm lateral resolution, non-contact", "Sampled radial " "zones (lead-in, outer, mid, inner) on fathers, mothers and stampers; the full spiral is not " "feasible and not needed. The optical-disc industry verified its nickel stampers with this " - "instrument class", "Full stack; from revenue if the lever is used"], + "instrument class", pick("From revenue", "At launch")], ["Wide-area optical profiler (Keyence VR-6000 class)", "Form, flatness, gross defects; 0.1 " "micron height resolution, ~1 s per field, HDR mode for mirror-bright nickel", - "Fast whole-part mapping", "Full stack; from revenue if the lever is used"], + "Fast whole-part mapping", pick("From revenue", "At launch")], ["Stylus profilometer", "Traceable reference", "Calibrates the optical instruments", "With the optical instruments"], ], widths_mm=[38, 46, 56, 30], font_pt=8.5), @@ -173,21 +176,34 @@ def blocks(): "scripting, but there is no off-the-shelf connector to a factory system. A small watcher at the " "metrology bench stamps each result with the part serial scanned from its back, writes the " "verdict to the part's quality inspection in ERPNext and the raw file to the machine-data store."), - CALL("Metrology: the investor's choice", [ - "**Full stack at launch.** The metrology and QC block is USD 350k to 810k (11.6M to 26.7M THB, " - "estimate, section 8): XRF, laser confocal, wide-area profiler, inline vision on the three " - "presses and the audio station. Every father, mother and stamper is measured before the next " - "plating generation or the press.", - "**Launch tier.** XRF, inline vision and the audio station at launch; the laser confocal and " - "the wide-area profiler bought from revenue. That saves ~10.1M THB at the midpoint with its " - "share of the contingency, one of the four levers that bring the plant inside 216M THB. Until " - "they arrive, groove geometry on the metal is judged indirectly, through the test pressing and " - "the audio station, as most plants do today; thickness and cosmetics are still measured on " - "every part.", - "Either way the data path is the same, so the later instruments plug in without rework. " + CALL(f"Metrology in {name()}: " + pick("the launch tier", "the full stack at launch"), pick([ + "**At launch: XRF, inline vision and the audio station**, USD 170k to 460k (5.6M to 15.2M THB, " + "estimate, section 8). Every father, mother and stamper still gets its nickel thickness " + "measured per serial by XRF and its surface screened by vision, and every record is still " + "inspected optically on the three presses, logged per cycle and sampled by the audio station " + "(section 5.3).", + "**From revenue: the laser confocal and the wide-area profiler**, USD 180k to 350k (estimate). " + "Buying them later takes ~8.8M THB out of the capital round at the midpoint, one of the six " + "levers that bring the plan to ~180M THB. Until they arrive, groove geometry and form on the " + "metal are judged indirectly, through the test pressing and the audio station, as most plants " + "do today.", + "The data path is the same from the first day, so the later instruments plug in without " + "rework. Distributor quotes for the metrology stack are one of the four requests that settle " + "the budget.", + ], [ + "**At launch: the full stack.** The metrology and QC block is USD 350k to 810k (11.6M to 26.7M " + "THB, estimate, section 8): XRF, laser confocal, wide-area profiler, inline vision on the presses " + "and the audio station. Every father, mother and stamper is measured before the next plating " + "generation or the press. The block was priced with inline vision on three presses, so the " + "cameras for the second Duplex system are to quote.", + "**If quotes land high,** the laser confocal and the wide-area profiler (USD 180k to 350k, " + "estimate) are the part that can wait and be bought from revenue: thickness and cosmetics " + "would still be measured on every part, and groove geometry judged through the test pressing " + "and the audio station meanwhile, as most plants do today.", + "Either way the data path is the same, so later instruments plug in without rework. " "Distributor quotes for the metrology stack are one of the four requests that settle the " "budget.", - ]), + ])), H2("5.3 Quality control: three layers for every record, one gate for every material"), P("Full automated audio checking of every record is physically impossible: a 12-inch record plays " @@ -202,7 +218,8 @@ def blocks(): "stamper), stitching and flow lines, warp, off-centre spindle holes, surface debris, wrong or " "off-centre labels. Non-fill and stitching correlate with audible defects, so this is a strong " "proxy for audio quality", "Custom integration of general machine vision (Keyence or Cognex " - "class) on all three presses; no vinyl-specific product exists"], + "class) on all " + pick("three", "five") + " presses; no vinyl-specific " + "product exists"], ["2. Press telemetry, every cycle", "Mould temperatures, pressures, cycle time, extruder values, " "yields and drift alerts from the press PLC", "Process drift before it becomes a defect; the " "record-level context for every other check", "Proven in the industry (Viryl's ADAPT model). " @@ -214,7 +231,8 @@ def blocks(): "from lead-in silence, channel balance; score and pass/fail to the record", "Wrong master cut " "into good-looking grooves, EQ and mastering errors, speed and pitch problems; what no camera " "can see", "Buildable from proven parts (Stamper Discs' Fonograph approach, iZotope-class " - "algorithms); first of its kind as a whole; in the launch tier"], + "algorithms); first of its kind as a whole; " + pick("in the launch tier", + "at launch")], ], widths_mm=[30, 46, 54, 40], font_pt=8.5), P("**Sampling rule for layer 3:** every test pressing and first-off per stamper, plus pulled " "samples densifying as the stamper ages (a stamper lasts roughly 1,000 to 2,000 records; the " @@ -247,10 +265,14 @@ def blocks(): H2("5.4 Efficiency: recover before you generate"), P("The pressing machinery is a modest electrical load: 32 kVA connected for a full Duplex line. The " - "real demand sits in the utilities around it. At launch the three presses need 450 to 540 kg/h of " - "saturated steam at 10 bar / 180 °C and about 390 kW of cooling at a hot-afternoon peak; the " - "utility backbone is built for the five-press fleet (750 to 900 kg/h of steam, up to ~650 kW of " - "cooling). On top comes whole-plant air conditioning in a tropical climate. Newbilt excludes " + "real demand sits in the utilities around it. " + pick( + "At launch the three presses need 450 to 540 kg/h of saturated steam at 10 bar / 180 °C and " + "~391.5 kW of cooling at a hot-afternoon peak; the utility backbone is built for the " + "five-press fleet (750 to 900 kg/h of steam, up to ~650 kW of cooling). ", + "At launch the five presses need 750 to 900 kg/h of saturated steam at 10 bar / 180 °C and " + "~652.5 kW of cooling at a hot-afternoon peak, on a utility backbone with rooms for four " + "boiler and four chiller modules. ") + + "On top comes whole-plant air conditioning in a tropical climate. Newbilt excludes " "steam and cooling from its scope, so these systems are ours to design, and the design rests on " "one observation: the steam's job is to heat the moulds and the cooling water's job is to remove " "that same heat again. Roughly 98% of the press cooling load is heat the steam put into the " @@ -261,9 +283,19 @@ def blocks(): "for the five-press fleet: the boiler hall and the chiller compound with room for four modules " "each, the steam main and condensate return, the cooling mains, the heat-exchanger frame and " "tanks, and hydraulic and compressed-air ring mains with a valved, capped tee at every press " - "position. The machines that make steam and cold water come in identical modules: at launch " - "two 500 kg/h boilers (B-1, B-2) and two 250 kW air-cooled chillers rated at 40 °C ambient " - "(CH-1, CH-2), sequenced lead and lag by one controller. Identical modules mean one set of spares " + "position. The machines that make steam and cold water come in identical modules: " + pick( + "at launch two 500 kg/h boilers (B-1, B-2) for the 450 to 540 kg/h peak and two 250 kW " + "air-cooled chillers rated at 40 °C ambient (CH-1, CH-2) for ~391.5 kW, sequenced lead and " + "lag by one controller. Either boiler alone carries 93 to 111% of the steam demand; one " + "chiller out leaves ~64% of the cooling peak. The boiler bodies come through the Chinese " + "route and the compressor from a Chinese brand's Thai office (below). ", + "at launch two 500 kg/h boilers (B-1, B-2) for the 750 to 900 kg/h peak and three 250 kW " + "air-cooled chillers rated at 40 °C ambient (CH-1 to CH-3) for ~652.5 kW, sequenced lead " + "and lag by one controller; the boilers and the compressor come from Thai suppliers " + "(below). Five presses on two boilers leave no spare: a third module (B-3) is an RFQ option " + "outside the plan price, and without it a boiler fault costs about two presses until it is " + "fixed; one chiller out leaves ~77% of the cooling peak. ") + + "Identical modules mean one set of spares " "and one service routine, N+1 later is one more module rather than a redesign, and the plant " "never runs one oversized boiler at poor part load. Four boilers carry about eight presses with " "one in reserve; four 250 kW chillers carry the five-press fleet with the fourth in reserve, and " @@ -311,14 +343,17 @@ def blocks(): "weekdays) and 2.6037 THB/kWh off-peak, plus the Ft fuel adjustment (+0.1623 THB/kWh for " "September to December 2026; it resets every four months) and reclaimable VAT. Two shifts put " "about two thirds of process energy into peak hours: a blended ~3.81 THB/kWh before the demand " - "charge. For the five-press fleet the backbone is built for, without electric steam, that is " + "charge. " + pick("For the five-press fleet the backbone is built for", "For the five presses") + + ", without electric steam, that is " "roughly 4.5M to 6.8M THB a year before solar, 0.7M to 1.1M of it demand charge (estimates), on " "an 800 to 1,000 kVA connection. Three design consequences:"), B([ "**Biomass heat is far cheaper than electric steam** (below): the demand charge follows the " "boiler's full-power draw, and the peak window covers 13 of the 16 production hours.", - "**The roof gets PV, not solar thermal.** Self-consumed PV is worth ~3.7 THB/kWh; it cannot " - "lower the demand charge, because the peak window runs to 22:00, long after sunset.", + "**The roof gets PV, not solar thermal.** Self-consumed PV is worth ~3.7 THB/kWh" + pick( + " of grid power displaced, less the PPA price the plant pays for it (below)", "") + + "; it cannot lower the demand charge, because the peak window runs to 22:00, long after " + "sunset.", "**The battery is for ride-through, not peak shaving.** Charging off-peak and discharging at " "peak earns ~70k THB a year for the 271 kWh stack, and it can hold demand down by only ~20 kW " "(~30k THB a year; estimates). Its case is riding through grid dips and outages.", @@ -327,8 +362,12 @@ def blocks(): KV([ ["Rooftop PV", "~247 kWp on the 1,523 m² monopitch roof (425 modules of a generic 580 W " "placeholder; no module chosen yet), ~335 to 360 MWh a year, ~25 to 35% of mature " - "two-shift use (1,000 to 1,500 MWh). Saves ~1.2M to 1.3M THB a year and pays back " - "in ~4.5 to 7 years at 25,000 to 35,000 THB/kWp (estimates)"], + "two-shift use (1,000 to 1,500 MWh). " + pick( + "Taken through a solar PPA (below): the plant pays the PPA price for this " + "power instead of buying the array, so its saving is the gap between that " + "price and the ~3.7 THB/kWh of grid power it displaces", + "Saves ~1.2M to 1.3M THB a year and pays back in ~4.5 to 7 years at 25,000 " + "to 35,000 THB/kWp (estimates)")], ["Canopies and the second building", "~40 kWp on the parking canopies (construction RFQ; ~54 " "kWp if fully covered). A phase 2 building's roof adds " "~251 kWp, ~498 kWp across both roofs"], @@ -343,27 +382,39 @@ def blocks(): "burning-season dust"], ["Open checks", "Battery rack voltage against the chosen Deye model's window; Gobel safety " "certifications (not published); EPC warranty on a mixed-vendor DC bus; yield " - "against PVGIS before committing"], - ["Solar PPA (option)", "Instead of buying the PV and battery, an EPC owns and finances them and " - "the plant buys the power: ~12.3M THB less capital at the midpoint with " - "its contingency share, one of the four levers in section 8. The PPA " - "price is not quoted yet, and the BOI solar measure (section 7) rewards " - "the plant's own solar investment, so its tax value probably goes with " - "the array (to confirm with the BOI consultant)"], + "against PVGIS before committing" + pick("; the PPA offer itself, price and " + "terms", "")], + pick(["Solar PPA (this plan)", "An installer owns and finances the PV and the battery, and the " + "plant buys the power at a price still to quote (the calculator carries 3.0 THB/kWh, an " + "estimate, ~0.03M USD a year on the energy line). That keeps the PV EPC (USD 227k to " + "318k) and the battery (USD 42k to 62k) out of the capital round: ~10.7M THB less at the " + "midpoint, one of the six levers in section 8. The BOI solar measure (section 7) rewards " + "the plant's own solar investment, so its tax value very likely goes with the array (to " + "confirm with the BOI consultant). The PPA offer is asked against the specification " + "above"], + ["Owned (this plan)", "The plant buys the array and the battery: rooftop PV EPC USD 227k " + "to 318k (7.5M to 10.5M THB) and the battery USD 42k to 62k (1.4M to 2.0M THB), " + "estimates, section 8. Owning them is what the BOI solar measure rewards (section 7). A " + "solar PPA (an installer owns and finances them, the plant buys the power at a price " + "still to quote) would take ~10.7M THB out of the capital round at the midpoint, but " + "very likely gives up that measure"]), ]), H3("Steam: the open engineering choice"), P("The boilers' fuel is still open; the modular bank works with either. There is no natural gas " "pipeline in Northern Thailand, so gas means a bulk LPG tank on site with hazardous-storage " "separation and licensing, and diesel means a fuel tank with price exposure. The two routes " "without a fossil tank, compared for the same heat (~1,120 to 1,280 MWh a year at about 1.0 " - "million records, the top of the launch plant's range; estimates):"), + "million records, " + pick("the top of the plant's range", "the low end of the five presses' " + "range") + "; estimates):"), T(["", "Electric boiler bank (~98%)", "Biomass boiler bank (~80%)"], [ ["Price of heat", "~3.9 THB/kWh, plus the demand charge", "~0.5 to 0.9 THB/kWh at 1.35 to 2 " "THB/kg delivered (reported market prices, October 2026; no supplier quote yet)"], ["Running cost, mature two shifts", "~5.2M to 6.0M THB a year, including 0.8M to 1.0M of extra " "demand charge for the five-press bank", "~0.6M to 1.2M THB a year of fuel, plus handling " "and ash"], - ["Boiler package, 2 × 500 kg/h", "4.5M to 7M THB (Thai suppliers); the investment's baseline", + ["Boiler package, 2 × 500 kg/h", pick("~2.8M to 5.5M THB through the Chinese route, the " + "plan's price (4.5M to 7M from Thai suppliers)", + "4.5M to 7M THB (Thai suppliers); the plan's price"), "~6M to 10M THB, plus the fuel store"], ["Grid", "Peak ~950 to 1,330 kW: PEA Schedule 4, 1,250 to 1,600 kVA", "Unchanged, ~800 to " "1,000 kVA"], @@ -378,7 +429,9 @@ def blocks(): "land a biomass stack would be a hard sell, which favours electric or LPG there (section 6.1)."), P("**Fuel.** A biomass bank burns roughly 350 to 400 tonnes of air-dry wood a year at about 1.0 " "million records (~540 to 620 t as fresh chips, which is what the store and the monsoon stock are " - "sized for). Lamphun alone produces more than 900,000 t of farm residues a year (Maejo " + "sized for)" + pick("", ", up to ~550 t air-dry at 1.5 million (fuel follows records pressed, " + "not presses)") + + ". Lamphun alone produces more than 900,000 t of farm residues a year (Maejo " "University), so supply is not the constraint; price is. Reported prices follow diesel, so the " "fuel contract gets a diesel clause and sources within ~50 km. The local price-setter is Ratch " "Pathana's biomass buying centre at Pa Sak, Mueang Lamphun, which feeds a 9.6 MW cogeneration " @@ -387,9 +440,19 @@ def blocks(): "that is worth only ~0.1M to 0.25M THB a year, so its value is supply security and the story " "('records pressed with steam from our own trees'), not the fuel bill. Next step: written quotes " "from Pa Sak and two or three chip suppliers, priced by moisture, before the boiler decision."), - P("**Where the boilers come from.** Chinese makers with Thai references (ZOZEN, Sitong, Fangkuai, " - "Taiguo) could supply the two modules for roughly 2.8M to 5.5M THB installed against 4.5M to 7M " - "from Thai suppliers, about 1.6M THB less at the midpoint (estimates from listings, not quotes). " + P("**Where the boilers come from.** " + pick( + "The plan buys the two modules through the Chinese route: boiler bodies from a Chinese maker " + "with Thai references (ZOZEN, Sitong, Fangkuai, Taiguo), installed with the feed tank, pumps, " + "header, controls and piping by a Thai boiler contractor, for roughly 2.8M to 5.5M THB " + "installed against 4.5M to 7M from Thai suppliers, about 1.6M THB less at the midpoint. The " + "compressor is a Chinese brand bought through its Thai office (Kaishan and Denair have one), " + "so service stays local; with it the route saves ~1.9M THB at the midpoint (estimates from " + "listings, not quotes). ", + "The plan buys the two modules and the compressor from Thai suppliers (4.5M to 7M THB " + "installed for the boilers). Chinese makers with Thai references (ZOZEN, Sitong, Fangkuai, " + "Taiguo) could supply the boilers for roughly 2.8M to 5.5M THB installed, about 1.6M THB " + "less at the midpoint, and with a Chinese compressor brand bought through its Thai office " + "~1.9M less (estimates from listings, not quotes): a step if quotes land high. ") + "The specification is a 1.25 MPa design to ASME Section I with the S stamp; most Chinese packaged " "electric units are rated 0.4 to 0.8 MPa and cannot deliver 10 bar. An imported boiler must meet " "TIS, ASME, JIS, EN or an equivalent standard and be verified by a certification body registered " @@ -425,10 +488,12 @@ def blocks(): CALL("Efficiency in one paragraph, for the investor", "Steam and cooling are built once as a " "backbone and filled with identical modules as presses arrive; heat is recovered from the " "flue gas, the condensate and the press returns before more is generated; the roof carries PV " - "worth a quarter to a third of mature electricity use, with a battery for ride-through; no " + "worth a quarter to a third of mature electricity use" + pick(" (through a solar PPA)", "") + + ", with a battery for ride-through; no " "process water is discharged; a fifth of the plastic is reclaimed; and biomass steam, if " "chosen, costs a quarter to a tenth of electric steam. The same choices push the energy line " - "toward its low end, hedge Thai tariff rises, and convert into BOI tax value (section 7). They " + "toward its low end, hedge Thai tariff rises, and convert into BOI tax value" + pick( + " through the Smart and Sustainable Industry measure", "") + " (section 7). They " "also make the plant's sustainability story true rather than claimed, which matters to the " "labels it sells to."), @@ -458,8 +523,8 @@ def blocks(): ["Neighbours", "Agricultural", "Industrial", "A pharmaceutical facility under construction on " "the same land"], ], widths_mm=[28, 44, 44, 54], font_pt=8.5), - P("**Galvanics now raises the bar for every site.** With the electroplating line in the launch " - "plant, a plot has to permit record pressing with a steam boiler **and** electroplating from day " + P("**Galvanics now raises the bar for every site.** With the electroplating line in the plan, a " + "plot has to permit record pressing with a steam boiler **and** electroplating from day " "one, not in a later phase. That favours the industrial estate (licensing through the estate, " "shared effluent treatment) and makes zoning the first check everywhere else."), P("**Payap University** approached the project and is interested in leasing land next to a " @@ -543,25 +608,77 @@ def blocks(): ["Packaging and finished-goods warehouse", "~300 to 500 m²"], ["Utility rooms (boiler, compressor, chiller, electrical)", "~100 to 150 m²"], ["Offices, QC and listening room, archive, IT, entrance", "~150 to 200 m²"], - ["Maintenance workshop and machine bay (crane-served)", "~100 to 150 m²"], - ["Visitor corridor (glazed, ground level)", "~110 to 130 m²"], + ["Maintenance workshop and machine bay (" + pick("crane-ready", "crane-served") + ")", + "~100 to 150 m²"], + [pick("Visitor corridor (glazed, ground level; built later, its strip kept free)", + "Visitor corridor (glazed, ground level)"), "~110 to 130 m²"], ["Circulation, walls, miscellaneous", "~150 to 250 m²"], ["**Total under roof**", "**~1,400 to 2,000 m²**, against 1,500 m² built"], ], widths_mm=[110, 60], caption="Estimates. The boiler and chillers have since moved to the detached utility yard, which " "frees floor the workshop and corridor take; water treatment is proposed in its own " "building next to galvanics; cassette and CD-R duplication (~40 to 80 m² and ~20 to " - "40 m²) are not in the table yet. At the lower half of the table everything fits in " + "40 m²" + pick(", a later step in this plan", "") + ") are not in the table yet. " + pick( + "", "The press rows size one Duplex system and the Classic; the second Duplex " + "system needs its own bay on top (~110 m² at the calculator's floor figure, " + "estimate). ") + + "At the lower half of the table everything fits in " "1,500 m²; at the upper half, finished goods move to a second building."), IMG("production-hall-layout-sketch.png", 170, "Figure 3. Rough layout sketch of the 60 × 25 m hall " "(October 2026): machine door and workshop at the ramp end, then mastering, galvanics, stamper " "prep, material area and lab, the press hall, inspection, QC and packaging along the glazed " - "visitor corridor, with the 5 t crane runway over the production compartment up to the " - "warehouse fire wall. It still draws two Classic positions (the launch plant installs one) and " + "visitor corridor" + pick(" (built later in this plan)", "") + ", with the 5 t crane runway " + "over the production compartment up to the warehouse fire wall. " + pick( + "It still draws two Classic positions (the plan installs one)", + "It still draws one Duplex system and two Classic positions (the plan installs two Duplex " + "systems and one Classic)") + " and " "puts reception and the cutting room under the crane's travel, a conflict the Payap scenario " "model resolves with a separate office building. All positions are estimates."), + P("Figure 4 shows the same plant as the calculator draws it for " + label() + ": the ground floor of a " + "whole site with the press hall cut open, the machines this plan installs and the free positions it " + "keeps for growth."), + IMG(pick("renders/calculator/plan-a-iso-gf.png", "renders/calculator/plan-b-iso-gf.png"), 170, + "Figure 4. The plant at a glance in the plant and business plan calculator, " + pick( + "Plan A preset: Duplex system 1 and the Classic in a press hall laid out for five Duplex bays " + "and four Classic positions, boiler modules B-1/B-2 and chillers CH-1/CH-2 (the free yard " + "positions are marked), the frame crane-ready with the crane rented", + "Plan B preset: Duplex systems 1 and 2 and the Classic in a press hall laid out for five Duplex " + "bays and four Classic positions, boiler modules B-1/B-2 and chillers CH-1 to CH-3 (the free " + "yard positions are marked), the 5 t crane and the cassette room") + + ". Schematic render (docs/fleet-calculator.html, also at cnxvinyl.lol/demos/fleet-calculator/) of a " + "generic site after the Payap scenario model and the utility yard of scale.md, not the Mueang Chi " + "parcel of Figure 2; positions and envelopes are estimates, not to scale where the vendors publish " + "no footprint."), H3("Crane, workshop and visitor corridor"), - B([ + B(pick([ + "**A crane-ready frame, with the crane rented at first.** The frame, the runway and the machine " + "door are built for a 5 t overhead crane (single-girder, ~24 m span, inverter drives, radio " + "remote) over the whole production compartment, roughly 40 to 48 m of the 60 m, stopping at " + "the fire wall to the finished-goods warehouse. For the installations a mobile crane is hired, " + "and the crane itself is bought later if machine moves and maintenance lifts make it worth it. " + "The building is shaped for it from the start: a frame designed for crane loads, no " + "full-height cross walls in the crane zone (rooms there are lidded boxes, with removable " + "hatches where heavy kit goes in), and the cutting room kept outside it, away from the frame's " + "vibration. 5 t covers the heaviest known lift (a Newbilt HRP 12 press, 1,350 kg) with margin " + "until Newbilt states the Classic's weight; 3.2 t is the alternative price.", + "**A machine door** of ~4.5 × 5.0 m at the ramp end, opened a few times a year. Until a crane " + "is bought, the hired crane sets each machine on skates at the door threshold; with the crane, " + "a truck reverses up the ramp into the machine bay and the crane lifts the machine off the bed " + "inside.", + "**A maintenance workshop** of ~100 to 150 m² beside it, where a bought crane would park: a " + "service bay for one press-sized machine, benches, a hydraulic hose crimper, a spares store " + "tracked in ERPNext, and a hot-work corner, held at negative pressure so its dust never " + "reaches the presses. Newbilt service comes from Germany and Pheenix from Sweden; spares on " + "the shelf are the uptime lever.", + "**A glazed visitor corridor, built later.** The plan runs without public tours at first, but " + "the route is designed in: the strip along the car-park wall stays free and the stations " + "follow the process order, from the cutting-room window to packaging. Built, it is ~45 to 55 m " + "long and ~2.4 m clear, with its own filtered air at slight positive pressure and acoustic " + "glazing that brings the 80 to 90 dB(A) near the presses down to roughly 40 to 50 dB(A) " + "(estimates), so a guide talks without a headset and visitors need no PPE; a 1:12 accessible " + "ramp serves the entrance. Until it is built there are no public tours, and the tour route and " + "the Payap programmes start later.", + ], [ "**A 5 t overhead crane** (single-girder, ~24 m span, inverter drives, radio remote) runs over " "the whole production compartment, roughly 40 to 48 m of the 60 m, and stops at the fire wall " "to the finished-goods warehouse. Machines are moved in, out and around without hiring a mobile " @@ -584,13 +701,14 @@ def blocks(): "headset and visitors need no PPE; a 1:12 accessible ramp serves the entrance. Tours for " "artists, labels, investors and schools can run several times a day without stopping " "production.", - ]), + ])), H3("Utility yard and water-treatment building"), T(["Detached utility yard (decided October 2026)", "Size (estimate)"], [ ["Boiler hall, four 500 kg/h module positions (B-1 and B-2 at launch)", "~162 m² (18 × 9 m), " "6.0 m high"], ["Biomass fuel store", "42 m²"], - ["Chiller compound, open and screened, four pads (CH-1 and CH-2 at launch)", "~135 m² (12.5 × " + ["Chiller compound, open and screened, four pads (" + pick("CH-1 and CH-2", "CH-1 to CH-3") + + " at launch)", "~135 m² (12.5 × " "10.8 m)"], ["Cooling pump and heat-exchanger room", "~40 m² (8 × 5 m)"], ["Flue stack", "14 m"], @@ -626,10 +744,16 @@ def blocks(): "plot's narrowing southern end with a two-bay sawtooth roof carrying ~251 kWp and a 20 m yard " "between the two for fire separation and shared loading; coverage stays at 39% of the deed area. " "It is where finished goods move to free production floor, where pressing capacity can double, " - "or where a CD replication line would go if that option is chosen (section 4.9). Where the " - "second Duplex system stands on the Mueang Chi footprint is not drawn yet; the Payap scenario " - "model draws the five-press fleet; its press hall is now planned for Duplex systems (five Duplex " - "bays and four Classic positions), because the plant focuses on special pressings."), + "or where a CD replication line would go if that option is chosen (section 4.10). **The press " + "hall** is planned for Duplex systems, because the plant focuses on special pressings and " + "specials run only on the Duplex: five Duplex bays and four Classic positions (~73/27 by floor, " + "estimate). " + pick( + "This plan installs one Duplex system and one Classic; growth adds Duplex systems first, into " + "bays whose floor, utility positions and ring-main tees are kept from the start. Where the " + "second Duplex system would stand on the Mueang Chi footprint is not drawn yet; ", + "This plan installs two Duplex systems and one Classic at launch; growth adds Duplex systems " + "first. Where the second Duplex system stands on the Mueang Chi footprint is not drawn yet; ") + + "the Payap scenario model draws the five-press fleet."), H3("What the construction RFQ asks"), P("The budget-level construction RFQ, with quantities from the parametric model, asks contractors " "for: the shell rate per m² at the insulated-panel specification (not a bare shed); heavy-duty " @@ -641,21 +765,29 @@ def blocks(): "PV, air conditioning, boilers, chillers and tanks, sprinklers, fit-out and the PEA transformer, " "and asks whether permit drawings for the building permit and the factory licence are included."), H3("What the building costs, and what is not known"), - T(["Block (launch plant)", "USD", "THB", "Basis"], [ + T(["Block", "USD", "THB", "Basis"], [ ["Building ~1,500 m² plus civil and site works", "650k to 1,100k", "21.4M to 36.3M", "estimate at 12,000 to 20,000 THB/m² for Thai pre-engineered steel to the insulated-panel " "specification, plus ~20% site works"], - ["Overhead crane, runway, frame premium, machine door", "97k to 227k", "3.2M to 7.5M", "estimate"], + pick(["Crane-ready frame, runway and machine door; mobile crane rented for the installations", + "39k to 91k", "1.3M to 3.0M", "estimate: 40% of the crane block (USD 97k to 227k); the " + "crane is bought later if needed"], + ["Overhead crane, runway, frame premium, machine door", "97k to 227k", "3.2M to 7.5M", + "estimate"]), ["Maintenance workshop and machine bay fit-out", "30k to 76k", "1.0M to 2.5M", "estimate; a " "workshop lathe and CNC mill not priced"], - ["Visitor corridor and accessible entrance", "67k to 148k", "2.2M to 4.9M", "estimate; " - "building it later is a lever worth ~4.1M THB"], + pick(["Visitor corridor and accessible entrance", "built later", "built later", "USD 67k to " + "148k (2.2M to 4.9M THB) when built, estimate; not in the plan price"], + ["Visitor corridor and accessible entrance", "67k to 148k", "2.2M to 4.9M", "estimate; " + "building it later would take ~3.6M THB out at the midpoint"]), ["Utility yard for four boiler and four chiller modules", "73k to 122k", "2.4M to 4.0M", "estimate at the building rate"], ["Water-treatment building next to galvanics", "52k to 87k", "1.7M to 2.9M", "estimate at the " "building rate"], - ["**Together**", "**~0.97M to 1.76M**", "**~32M to 58M**", "sum of the blocks, before the 15% " - "contingency (section 8)"], + pick(["**Together**", "**~0.84M to 1.48M**", "**~28M to 49M**", "sum of the blocks; the plan " + "carries no contingency (section 8)"], + ["**Together**", "**~0.97M to 1.76M**", "**~32M to 58M**", "sum of the blocks; the plan " + "carries no contingency (section 8)"]), ], widths_mm=[50, 26, 26, 68], font_pt=8.5), P("The single largest unknown is the ground. The Mueang Chi parcel is likely soft former paddy, and " "a piled slab can add several hundred to 1,000+ THB/m² across the building, 4,387 m² of paving " @@ -663,9 +795,13 @@ def blocks(): "before any real number, and the building RFQ with a soil test is one of the four requests that " "settle the budget. Also open: the crane's hook height under the 7.0 m eave; the archive's " "mobile shelving (to quote); the valved branches and feeders for the empty utility positions; " - "and the fire-water volume, which the hydraulic design and the warehouse racking height set. " - "Renting a crane for the installations while the frame stays crane-ready would save ~3.7M THB, " - "but that is a scope cut toward the 180M THB case, not part of the plan."), + "and the fire-water volume, which the hydraulic design and the warehouse racking height set. " + + pick("Renting a crane for the installations while the frame, runway and machine door stay " + "crane-ready takes ~3.2M THB out at the midpoint, one of the six levers; the 5 t crane itself " + "is USD 30k to 76k supplied and installed (estimate) when it is bought.", + "Renting a mobile crane for the installations while the frame, runway and machine door stay " + "crane-ready would take ~3.2M THB out at the midpoint (estimate): a step if quotes land " + "high, not part of the plan.")), H2("6.3 Safety, security and the irreplaceable"), P("Worker safety is a founding priority on equal footing with the environmental commitments. The " @@ -686,7 +822,8 @@ def blocks(): "THB a head a year for insurance, ~2,500 for the check-up plus ~1,500 for risk-factor tests, and " "workwear ~USD 9k a year at ~20 staff."), P("Physical security is zoned: production, galvanics, chemical storage, the metal archive, IT, " - "shipping and the visitor corridor each get badge or biometric access with logs; CCTV at " + "shipping and " + pick("(once built) ", "") + "the visitor corridor each get badge or biometric " + "access with logs; CCTV at " "entrances, perimeter, dock, production, chemicals and archive under a PDPA-compliant retention " "policy. Two things are irreplaceable and get their own protection: **the metal archive** (a " "destroyed father means recutting and re-plating a release; fire-rated room, climate control in " @@ -709,7 +846,9 @@ def blocks(): "pressing is basic plastic consumer-goods manufacturing (incentive Group B): no corporate income " "tax holiday on the core activity, but the full non-tax package and machinery duty exemption. " "The tax value is engineered on top through measures where this project happens to be strong, so " - "the application is pitched on solar, automation and technology content, not on pressing plastic " + "the application is pitched on " + pick("automation, technology content and energy efficiency", + "solar, automation and technology content") + + ", not on pressing plastic " "discs. The research behind this dates from July 2026, BOI revises its measures roughly every " "year, and the exact activity sub-code needs confirmation by a BOI-registered consultant before " "filing."), @@ -718,7 +857,9 @@ def blocks(): "(Germany, Sweden, the UK, Australia, Japan, China). Machinery imported duty-free is also " "exempt from VAT at import (Revenue Department answer on BOI's FAQ, checked October 2026). The " "investment blocks assume promotion: without it, ~5% duty on ~2.3M USD of imported machinery " - "(~0.11M USD) plus ~0.17M USD of import VAT, reclaimed only later (estimates)."], + "(~0.11M USD) plus ~0.17M USD of import VAT, reclaimed only later (estimates for the " + + pick("full equipment list; this plan imports less at first", + "three-press equipment list; the second Duplex system adds to both") + ")."], ["100% foreign ownership and land privileges", "Overrides Foreign Business Act restrictions " "for the promoted activity. The land-ownership privilege is unused under the lease strategy."], ["Visas and work permits via the One Stop Service", "Foreign commissioning engineers and the " @@ -728,7 +869,12 @@ def blocks(): ["Solar and battery measure (Announcement 2/2568, April 2025)", "CIT exemption based on the " "solar investment; PV modules, inverters, battery and battery inverters, and mounting are " "eligible, capped at THB 12M, 30M or 40M of investment per MW depending on investment type. " - "It rewards a plant-owned array, which matters if the solar PPA lever is used (section 5.4)."], + "It rewards a plant-owned array. " + pick( + "This plan takes the PV and the battery through a solar PPA, so the installer owns them " + "and the plant very likely gives up this measure (to confirm with the BOI consultant; " + "section 5.4).", + "This plan buys the ~247 kWp array and the 271 kWh battery, so their cost is the base of " + "the exemption (section 5.4).")], ["Smart and Sustainable Industry measure (Announcement 15/2565, refreshed July 2025)", "Rewards automation, smart machinery and energy efficiency, typically 3 years of CIT exemption " "capped around 50% of the qualifying upgrade spend. The automatic Classic, inline inspection, " @@ -744,7 +890,9 @@ def blocks(): "machinery and raw materials lives, from the first capex invoice."), P("**Process:** file via the e-Investment system and present at an analyst meeting. BOI quotes " "about 40 working days to a decision for projects under THB 200M and 60 to 90 working days for " - "larger tiers; at ~161M to 292M THB the launch plant sits around that line, so the consultant " + "larger tiers; at " + pick("~127M to 226M THB with the ramp-up reserve (~177M at the midpoint)", + "~162M to 286M THB with the ramp-up reserve (~224M at the midpoint)") + + " the plan sits around that line, so the consultant " "confirms which applies. In practice it is roughly 4 to 6 months end to end to the certificate; " "the company is incorporated under it; machinery is imported within a window commonly 30 months " "from issuance; full operation is due by about 36 months. The Northern Economic Corridor " @@ -754,7 +902,7 @@ def blocks(): H2("7.2 Factory licence, galvanics and boilers"), P("BOI promotion does not replace the factory licence (Ror.Ngor. 4), hazardous-substance " "registration for the plating chemistry, wastewater permitting or the boiler rules. **Galvanics " - "is now in the launch plant, so the electroplating line, its chemistry and its zero-discharge " + "is in the plant from launch, so the electroplating line, its chemistry and its zero-discharge " "effluent system are in the first factory licence application**, not a later amendment. The " "earlier plan to keep galvanics out of the first licence to protect the schedule no longer " "applies. Effluent is the most likely regulatory friction point regardless of BOI, and it now " @@ -772,8 +920,9 @@ def blocks(): "engineer; the construction RFQ asks whether contractors include them (shell prices usually do " "not), and stormwater attenuation may be a permit condition.", ]), - P("**Boilers (DIW rules).** The Ministerial Regulation on boilers B.E. 2549 and the matching " - "notification on boiler safety of the same year apply to every module, Thai or imported: a design " + P("**Boilers (DIW rules).** The Ministerial Regulation on boilers B.E. 2549 and the Ministry of " + "Industry notification on boiler safety of the same year apply to every module, Thai or " + "imported: a design " "to TIS or an international standard (ASME, JIS, EN or equivalent) checked and certified by a " "DIW-registered certification body or licensed engineer; for an imported boiler, verification by " "a registered certification body and the manufacturer's data report, design and inspection " @@ -781,11 +930,18 @@ def blocks(): "reported to DIW within 30 days; **a licensed boiler controller on site**; and **inspection at " "least once a year**. The relief for small once-through units does not apply at ~10.5 bar (our " "reading), and the labour-side regulation of 2021 adds licensed-engineer installation and " - "testing and a feedwater standard. A Chinese boiler built to the Chinese GB code would rest on " - "'or equivalent' with no precedent found, hence the ASME specification. DIW has announced a " + "testing and a feedwater standard. " + pick( + "**This plan's two boiler bodies come from a Chinese maker, so they take the imported-boiler " + "route of the notification:** verification by a registered certification body with the full " + "dossier, and an ASME Section I design at 1.25 MPa with the S stamp, because a boiler built " + "to the Chinese GB code would rest on 'or equivalent' with no precedent found. ", + "The plan's modules come from Thai suppliers to the same ASME specification; a Chinese " + "boiler built to the Chinese GB code would rest on 'or equivalent' with no precedent found. ") + + "DIW has announced a " "revision of the boiler, pressure-vessel and refrigeration rules, so they are rechecked before " "the RFQ, and a certification body is engaged before any boiler order."), - P("**Other permits and duties:** the same 2021 labour regulation covers the overhead crane (a " + P("**Other permits and duties:** the same 2021 labour regulation covers the overhead crane" + + pick(" once one is bought", "") + " (a " "crane-industry summary puts cranes above 3 t on an engineer inspection every three months; to " "confirm against the text before the capacity is chosen); hazardous-substance registration and " "locked, inventoried storage for silver nitrate and nickel salts; the occupational health " @@ -797,9 +953,13 @@ def blocks(): "operation) start at the certificate, and the margin on them is consumed by one scenario: " "filing early and then finding the site does not work. Verify the chosen plot's zoning, " "including plating, first.", - "**Scope.** Cassette and CD-R duplication go into the application from the start. CD " - "replication would need new activity codes, which cannot be added casually afterwards, so the " - "investor's decision on CD (section 4.9) is needed before the filing date.", + "**Scope.** " + pick( + "Cassette and CD-R duplication come later in this plan; whether they still go into the " + "first application (their machines then due inside its import window) or into a later " + "amendment is a question for the consultant. ", + "Cassette and CD-R duplication go into the application from the start. ") + + "CD replication would need new activity codes, which cannot be added casually afterwards, so the " + "investor's decision on CD (section 4.10) is needed before the filing date.", "**Sequencing.** The plan's rule is that no machinery purchase order precedes the certificate, " "because duty exemption is not retroactive. But the exemption attaches at importation, not at " "contract signature. If equipment can be ordered with a deposit while the application is in " diff --git a/docs/business-plan/build/content_c.py b/docs/business-plan/build/content_c.py index b5a2dd0..5256d42 100644 --- a/docs/business-plan/build/content_c.py +++ b/docs/business-plan/build/content_c.py @@ -1,168 +1,566 @@ """Part C: investment, revenue and operating model, timeline, phasing, team and ownership, risks, next steps. -Draft 0.2, October 2026: re-based on the launch plant (everything in one capital round, -commissioned in sequence), docs/finance/total-investment.md "Launch plant (October 2026)". +Draft 0.3, October 2026: two versions built from this one file, Plan A (~180M THB, the launch plant with +six cost levers, three presses) and Plan B (~225M THB, the second Duplex system at launch, five presses, +everything in). Both are priced without contingency and with the ramp-up reserve: +docs/finance/total-investment.md "Two plans: A at ~180M THB and B at ~225M THB (October 2026)" and +docs/finance/revenue-model.md "Operating pictures of Plan A and Plan B (October 2026)". +plan_variant.pick() switches the text; it is called inside blocks() only (build_plan.py sets the plan +before it calls blocks()). """ from plan_lib import H1, H2, H3, P, B, N, T, KV, IMG, CALL, PB +from plan_variant import pick, is_a, is_b, label, name + + +# ------------------------------------------------------------ 8.1 blocks +def _block_rows(): + """This plan's blocks: the calculator rows of its preset, grouped (USD and THB, low to high).""" + a = is_a() + rows = [ + ["Phase 0: BOI consultant, legal and lease work, soil test, re-quotes", "40k to 80k", "1.3M to 2.6M", + "Estimate"], + ["Newbilt Duplex system 1 (two HRP 12 presses, EX 50 main and EX 35 colour extruder, trimmer, label " + "oven, shrink wrapper, grinder, label punch)", "350k to 370k", "11.6M to 12.2M", + "Quoted: 2024 offer EUR 200,500 for the Single 2.1 plus the quoted second press and extruder " + "~USD 115k; expired, re-quote"], + ] + if not a: + rows.append(["Newbilt Duplex system 2 (two HRP 12 presses, EX 50 main and EX 35 colour extruder)", + "230k to 300k", "7.6M to 9.9M", "Estimate: two presses at the quoted ~115k per press and " + "extruder set, plus hydraulic unit and EX 35; **no EX 35 price on file**"]) + rows += [ + ["Newbilt Classic, fully automatic press", "290k to 460k", "9.6M to 15.2M", "Placeholder (the old " + "automatic-press band per press); **no Newbilt price on file**"], + ["Pheenix galvanics line (PASU, PPPU, one PDPU, PMPB)", "324k to 445k", "10.7M to 14.7M", + "**OMS's reference plus 20 %**: OMS's 4-cell wet room with the EUR 10k know-how transfer, EUR 234k " + "to 321k (letter of 9 October 2026), × 1.2 = EUR 280.8k to 385.2k; **no Pheenix price on file**"], + ["Galvanics water: zero-discharge (ZLD) evaporator and DI water", "97k to 258k", "3.2M to 8.5M", + "Researched: utilities rows, launch scope"], + ["Water-treatment building next to galvanics (~12 × 10 m, proposed)", "52k to 87k", "1.7M to 2.9M", + "Estimate at the building rate below"], + ["Sibert stamper prep: VSF back-finisher, VSP punch, VSC coiner", "250k", "8.3M", "Sibert's budget " + "confirmation, 5 October 2026; its time, spares, shipping and travel sit in the freight and " + "working-capital lines"], + ["Cutting room: Sillitoe SDMS lathe, spare cutterhead and support, mastering console and chain, " + "monitoring, room build-out", "200k to 350k", "6.6M to 11.6M", "SDMS list price USD 125k (ex tax " + "and shipping); the rest estimate"], + pick(["Metrology and QC, launch tier: XRF, inline vision on the presses, audio station", "170k to 460k", + "5.6M to 15.2M", "Estimate; the laser confocal and the wide-area profiler (USD 180k to 350k) are " + "bought from revenue (lever 2, section 8.2)"], + ["Metrology and QC, full stack: XRF, laser confocal, wide-area profiler, inline vision, audio " + "station", "350k to 810k", "11.6M to 26.7M", "Estimate, phaseable; the launch-plant figure, not " + "re-sized for the two extra presses"]), + ["PVC lab, day-one tier", "55k to 150k", "1.8M to 5.0M", "Estimate"], + pick(["Steam, cooling and compressed air: two 500 kg/h boiler modules (priced electric), cooling " + "backbone for four modules (plate heat exchanger, tanks, pumps, mains), two 250 kW chiller " + "modules (CH-1, CH-2), screw compressor, dryer and receiver", "239k to 416k", "7.9M to 13.7M", + "Researched: utilities rows; boilers and compressor through the Chinese route (lever 6): " + "ASME-stamped 1.25 MPa boiler bodies installed by a Thai contractor, the compressor from a " + "Chinese brand's Thai office"], + ["Steam, cooling and compressed air: two 500 kg/h boiler modules (priced electric), cooling " + "backbone for four modules (plate heat exchanger, tanks, pumps, mains), three 250 kW chiller " + "modules (CH-1 to CH-3), screw compressor, dryer and receiver", "344k to 548k", "11.4M to 18.1M", + "Researched: Thai supplier ranges; the two boiler modules carry the five presses' 750 to 900 " + "kg/h"]), + ["Whole-factory HVAC, clean-room adder for galvanics and the cutting room, softener, loop treatment, " + "racking", "297k to 627k", "9.8M to 20.7M", "Researched: utilities rows"], + ] + if not a: + rows.append(["Rooftop PV (EPC) and the 271 kWh Gobel battery, owned", "269k to 380k", "8.9M to 12.5M", + "Researched: utilities rows; owned, so the BOI solar measure applies"]) + rows += [ + ["Building ~1,500 m² plus civil and site works", "650k to 1,100k", "21.4M to 36.3M", "Estimate at " + "12,000 to 20,000 THB/m² plus ~20 % site works; soil is the main variable"], + pick(["Crane rented for the installations (mobile crane); frame, runway and machine door stay " + "crane-ready", "39k to 91k", "1.3M to 3.0M", "Estimate: 40 % of the crane block (lever 5)"], + ["Overhead crane, runway, frame premium, machine door", "97k to 227k", "3.2M to 7.5M", "Estimate"]), + ["Maintenance workshop and machine bay fit-out", "30k to 76k", "1.0M to 2.5M", "Estimate"], + ] + if not a: + rows.append(["Visitor corridor and accessible entrance", "67k to 148k", "2.2M to 4.9M", "Estimate"]) + rows += [ + ["Utility yard built for four boiler and four chiller modules", "73k to 122k", "2.4M to 4.0M", + "Estimate"], + ["Factory software, ERPNext, artist platform public side", "115k to 310k", "3.8M to 10.2M", + "Estimate: factory software 60k to 170k, ERPNext implementation 15k to 50k, artist platform " + "40k to 90k"], + ] + if not a: + rows.append(["Cassette duplication and CD-R duplication", "55k to 190k", "1.8M to 6.3M", "Estimate, " + "sections 4.8 and 4.9: cassette 40k to 150k, CD-R 15k to 40k"]) + rows += [ + pick(["Freight, installation, commissioning, training (Pheenix, Sibert, Sillitoe, Newbilt beyond its " + "quoted 5 days)", "150k to 300k", "5.0M to 9.9M", "Estimate"], + ["Freight, installation, commissioning, training (Pheenix, Sibert, Sillitoe, Newbilt beyond its " + "quoted 5 days)", "174k to 348k", "5.7M to 11.5M", "Estimate: the launch plant's 150k to 300k " + "plus 24k to 48k for the extra machinery"]), + pick(["Working capital, PVC stock, spares, lease deposit, first-year rent", "137k to 293k", + "4.5M to 9.7M", "Estimate; land is leased, so no land purchase"], + ["Working capital, PVC stock, spares, lease deposit, first-year rent", "201k to 432k", + "6.6M to 14.3M", "Estimate, sized for ~1.25M records a year; land is leased, so no land " + "purchase"]), + ] + if a: + rows.append(["Not bought at launch (levers, section 8.2): rooftop PV and battery (solar PPA), visitor " + "corridor, cassette and CD-R duplication", "none", "none", "The PPA installer owns and " + "finances the array; the rest are growth steps from revenue"]) + rows += [ + pick(["**Subtotal, plan investment**", "**~3.56M to 6.25M**", "**~117.4M to 206.1M**", + "**Midpoint ~161.7M THB (~4.90M USD)**"], + ["**Subtotal, plan investment**", "**~4.61M to 8.07M**", "**~152.2M to 266.3M**", + "**Midpoint ~209.2M THB (~6.34M USD)**"]), + ["Ramp-up reserve: staff hired before first revenue, overheads until volume covers them", + "~0.30M to 0.61M", "10M to 20M", "Estimate; cash the investor puts in, so it is in the plan price"], + pick(["**Plan A price**", "**~3.86M to 6.85M**", "**~127M to 226M**", + "**Midpoint ~177M THB (~5.35M USD): ~180M THB**"], + ["**Plan B price**", "**~4.92M to 8.67M**", "**~162M to 286M**", + "**Midpoint ~224M THB (~6.79M USD): ~225M THB**"]), + ["Contingency: not in the plan price", "", "", pick( + "For information: at 15 %, ~24M THB at the midpoint", + "For information: at 15 %, ~31M THB at the midpoint")], + ] + return rows + + +def _levers_table(): + """Plan A: the six levers from the launch plant with every block, midpoints, no contingency.""" + return T(["Step", "Saves", "Subtotal after it", "What it gives up"], [ + ["Launch plant, every block, no contingency", "", "~193.8M THB (~5.87M USD)", ""], + ["1. Rooftop solar and battery through a solar PPA (the installer owns and finances the array; the " + "plant buys the power)", "~10.7M", "~183.1M", "Owned solar and very likely the BOI solar measure with " + "its tax benefit (our reading, for the BOI consultant); " + "adds the PPA power price to the energy bill, ~0.03M USD a " + "year in the calculator at 3.0 THB/kWh (estimate, to " + "quote)"], + ["2. Metrology launch tier: XRF, inline vision and audio station at launch; laser confocal and " + "wide-area profiler (USD 180k to 350k) bought from revenue", "~8.8M", "~174.4M", "Every stamper and " + "record is still measured (XRF, inline vision on the presses, audio station); the confocal and the " + "profiler come later"], + ["3. Visitor corridor built later", "~3.6M", "~170.8M", "No public tours at first: the tour route and " + "the Payap programmes around it start later"], + ["4. Cassette and CD-R duplication later", "~4.0M", "~166.8M", "No cassette or CD-R at launch; a growth " + "step"], + ["5. Crane rented for the installations (mobile crane)", "~3.2M", "~163.6M", "No overhead crane at " + "first; frame, runway and machine door stay crane-ready, so it can be bought later if needed"], + ["6. Boilers and compressor through the Chinese route", "~1.9M", "**~161.7M (~4.90M USD)**", + "Imported boilers take the Thai route (Ministry of Industry boiler notification B.E. 2549: design " + "and import rules, a certification body registered with the Department of Industrial Works) with an " + "ASME S stamp at 1.25 MPa"], + ["Ramp-up reserve", "", "+10M to 20M", ""], + ["**Plan A**", "", "**~177M THB (~5.35M USD)**", "~127M to 226M from the low to the high end of every " + "block"], + ], widths_mm=[56, 16, 32, 66], font_pt=8.5, + caption="Midpoint values without contingency, estimates; docs/finance/total-investment.md 'Two plans'. " + "The levers keep every machine of the launch plant.") + + +def _additions_table(): + """Plan B: what it adds to the launch plant, midpoints, no contingency.""" + return T(["Block", "USD", "THB, midpoint"], [ + ["Launch plant, every block, no contingency", "4.24M to 7.50M", "~193.8M"], + ["Second Duplex system: two HRP 12, EX 50 and EX 35 (two presses at the quoted ~115k per press and " + "extruder set, plus hydraulic unit and EX 35; no EX 35 price on file)", "230k to 300k", "+8.7M"], + ["Third chiller module, CH-3 (250 kW; the two boiler modules carry 750 to 900 kg/h)", "48k to 78k", + "+2.1M"], + ["Freight and installation for the extra machinery", "24k to 48k", "+1.2M"], + ["Working capital for ~1.25M records a year instead of 0.85M", "64k to 139k", "+3.4M"], + ["**Subtotal**", "**4.61M to 8.07M**", "**~209.2M (~6.34M USD)**"], + ["Ramp-up reserve", "", "+10M to 20M"], + ["**Plan B**", "", "**~224M THB (~6.79M USD)**; ~162M to 286M from the low to the high end"], + ], widths_mm=[100, 30, 40], + caption="Midpoint values without contingency, estimates; docs/finance/total-investment.md 'Two plans'.") + + +def _tranches(): + return T(["Tranche", "Trigger", "Covers", "Approx. share, THB"], [ + ["0", "Now", "Phase 0 work (section 14.1)", "The Phase 0 block, ~1.3M to 2.6M (1 to 2 %)"], + ["1", pick("BOI certificate issued; lease signed; zoning and soil confirmed; pricing validated", + "BOI certificate issued; lease signed; zoning and soil confirmed; pricing and the demand " + "for ~1.25M records a year validated"), + pick("Deposits on every long-lead order: Pheenix galvanics line, Sillitoe lathe, Sibert line, Newbilt " + "Duplex system and Classic; building design and permit; first boiler and chiller modules " + "(boilers and compressor through the Chinese route)", + "Deposits on every long-lead order: Pheenix galvanics line, Sillitoe lathe, Sibert line, both " + "Newbilt Duplex systems and the Classic; building design and permit; first boiler and chiller " + "modules"), + pick("20 to 30 % (~32M to 49M)", "20 to 30 % (~42M to 63M)")], + ["2", "Building permit; vendor build dates confirmed in writing", + pick("Construction, water-treatment building, utility yard, utilities, balance payments as machines " + "are built", + "Construction, water-treatment building, utility yard, utilities including the third chiller " + "module, balance payments as machines are built"), + pick("35 to 45 % (~57M to 73M)", "35 to 45 % (~73M to 94M)")], + ["3", "Building watertight; first machinery shipped", + pick("Fit-out, HVAC and clean zones, ZLD and DI water, the rented crane for the installations, the " + "metrology launch tier, factory software and ERPNext, the launch team", + "Fit-out, HVAC and clean zones, ZLD and DI water, rooftop PV and battery, crane, visitor " + "corridor, the full metrology stack, factory software and ERPNext, cassette and CD-R lines, the " + "launch team"), + pick("15 to 20 % (~24M to 32M)", "15 to 20 % (~31M to 42M)")], + ["4", "Cutting room and galvanics commissioned; first stampers made", "Working capital, PVC stock, " + "spares, first-year rent; the ramp-up reserve (10M to 20M THB, in the plan price) is drawn from here " + "on", pick("8 to 12 % (~13M to 19M), plus the reserve", "8 to 12 % (~17M to 25M), plus the reserve")], + ], widths_mm=[14, 46, 78, 32], font_pt=8.5, + caption=pick("Shares of Plan A's investment before the reserve (~161.7M THB at the midpoint); the THB " + "figures are the shares applied to it (arithmetic, estimates).", + "Shares of Plan B's investment before the reserve (~209.2M THB at the midpoint); the THB " + "figures are the shares applied to it (arithmetic, estimates).")) + + +# ------------------------------------------------------- 9.4 operating picture +def _operating_table(): + if is_a(): + rows = [ + ["Records", "0.58M", "0.74M", "0.90M"], + ["Blended price, 60 % specials", "3.76", "4.49", "5.27"], + ["Direct cost", "2.70", "2.00", "1.35"], + ["Contribution per record", "1.06", "2.49", "3.92"], + ["Pressing contribution", "0.61M", "1.83M", "3.51M"], + ["Title-services contribution", "0.07M", "0.23M", "0.48M"], + ["**Total contribution**", "**0.68M**", "**2.06M**", "**3.99M**"], + ["Cash overheads", "0.45M", "0.33M", "0.20M"], + ["**EBITDA**", "**0.23M**", "**1.73M**", "**3.79M**"], + ["Depreciation", "0.62M", "0.39M", "0.24M"], + ["**Operating profit**", "**-0.39M**", "**1.34M**", "**3.55M**"], + ["Revenue", "2.28M (~75M THB)", "3.65M (~120M THB)", "5.41M (~179M THB)"], + ["Payback on the plan price (EBITDA, mature year)", "~30 yr", "~3.1 yr (2.2 to 4.0 on 3.86M to " + "6.85M)", "~1.0 yr"], + ] + else: + rows = [ + ["Records", "1.0M", "1.25M", "1.5M"], + ["Blended price, 60 % specials", "3.76", "4.49", "5.27"], + ["Direct cost", "2.58", "1.94", "1.30"], + ["Contribution per record", "1.18", "2.55", "3.97"], + ["Pressing contribution", "1.18M", "3.19M", "5.96M"], + ["Title-services contribution", "0.10M", "0.28M", "0.48M"], + ["**Total contribution**", "**1.28M**", "**3.47M**", "**6.44M**"], + ["Cash overheads", "0.45M", "0.33M", "0.20M"], + ["**EBITDA**", "**0.83M**", "**3.14M**", "**6.24M**"], + ["Depreciation", "0.81M", "0.51M", "0.31M"], + ["**Operating profit**", "**0.02M**", "**2.63M**", "**5.93M**"], + ["Revenue", "3.93M (~130M THB)", "6.05M (~200M THB)", "8.60M (~284M THB)"], + ["Payback on the plan price (EBITDA, mature year)", "~10.5 yr", "~2.2 yr (1.6 to 2.8 on 4.92M to " + "8.67M)", "~0.8 yr"], + ] + return T(["USD per year, mature", "Adverse", "Central", "Favourable"], rows, widths_mm=[50, 36, 48, 36], + caption="Estimates, docs/finance/revenue-model.md 'Operating pictures of Plan A and Plan B (October " + "2026)'. Title services at 60 to 70 % contribution after lacquers, styli and nickel. " + "Contribution per record and total contribution are the table's own arithmetic.") + + +def _risk_rows(): + a = is_a() + rows = [ + ["High", "Pricing power in the region is unproven", "The single biggest assumption in the revenue " + "model; a turnaround advantage nobody pays a premium for is a cost, not a moat", "Market " + "validation gate: regional label conversations, the artist platform's calculator as an interest " + "list, a second Thai data point; no large spending before it clears"], + ] + if not a: + rows += [ + ["High", "Demand for ~1.25M records a year", "The central case needs ~1.25M records sold a year, " + "~0.75M of them specials, against 0.74M for the three-press plant; nothing in the market data so " + "far shows that demand", "Market validation (roadmap item 1) before the round is called; the " + "second Duplex system is commissioned last, so its order is the one that can still move back to a " + "growth step"], + ["High", "More capital at risk", "~224M THB in one round, ~27 % more than the three-press Plan A, " + "more of it committed before the market has validated the price and the volume", "Gates and " + "tranches (section 8.3): no order before the BOI certificate and validated pricing and demand"], + ] + rows += [ + ["High", "No contingency in the plan price", pick( + "Quotes landing high are not covered: at 15 % a contingency would be ~24M THB at the midpoint, " + "and the high end of every block comes to ~226M with the reserve", + "Quotes landing high are not covered: at 15 % a contingency would be ~31M THB at the midpoint, " + "and the high end of every block comes to ~286M with the reserve"), + "The requests that settle most of the band come before commitment (section 8.4); tranche release; " + "how overruns are funded (outside the plan price or by scope steps) agreed with the investor up " + "front"], + ["High", "Utilisation and price", pick( + "The cost structure is mostly fixed; the adverse case loses money: it needs ~0.9M records to cover " + "depreciation and the three presses make 0.58M at that rate; at 60 % specials the Duplex rate and " + "the extra cost of specials decide volume and margin", + "The cost structure is mostly fixed; the adverse case only just covers depreciation (~1.0M records " + "needed, 1.0M made), so any shortfall in price or volume turns it into a loss; the extra cost of " + "specials is not in the direct cost yet"), + pick("Central breaks even at ~0.2M records; commission in sequence; the second Duplex waits for " + "demand; treat the adverse column as the honest one", + "Central breaks even at ~0.22M records; commission in sequence; treat the adverse column as the " + "honest one")], + ] + if not a: + rows.append(["Medium", "Ramp length", "The ramp to ~1.25M records is longer than the three-press " + "plant's to 0.74M; the ramp-up reserve is the same 10M to 20M THB estimate", "Break-even at " + "~0.22M records, so a slow ramp costs payback time more than solvency (our reading); a " + "year-by-year cash model for the ramp is a next step (section 9.5)"]) + rows += [ + ["High", "Galvanics and cutting on the critical path", "No paying release until the cutting room " + "and galvanics make good stampers; a slow start there delays every press", "Commission the " + "metal path first and measure it; vendor training; Stamper Discs and SST as contacts for a " + "slipping commissioning, not a plan"], + ["High", "Skills: galvanics process engineer, cutting engineer", "Galvanics is the hardest skill to " + "hire; both roles are now needed at launch", "Recruit or train abroad; BOI work permits; vendor " + "training (Pheenix, Sillitoe, OMS as a reference); Payap programmes as a longer-term pipeline"], + ["High", pick("Prices not on file: the Classic and the Pheenix line", + "Prices not on file: the Classic, the Pheenix line and the second EX 35"), + pick("The Classic band is a placeholder borrowed from another vendor's automatic press; the Pheenix " + "line is priced at OMS's reference plus 20 %, without a Pheenix figure", + "The Classic band is a placeholder borrowed from another vendor's automatic press; the Pheenix " + "line is priced at OMS's reference plus 20 %, without a Pheenix figure; the second Duplex " + "system's EX 35 has no price"), + "Newbilt re-quote and Pheenix quote in phase 0; OMS's dedicated offer as the galvanics benchmark"], + ["High", "Vendor build times unknown", "The press build carries ~40 % of the schedule; 15 to 18 " + "months would push launch to mid-2029; Pheenix, Sillitoe and Sibert lead times also unquoted", + "Required field in every re-quote, now"], + ["High", "Zoning of the chosen plot unverified", "A site reset costs ~6 months; the Payap point " + "already fails zoning; Mueang Chi is unverified", "Verify on the land-use map and with counsel " + "before the BOI filing; industrial estate as " + "fallback"], + ] + if a: + rows.append(["Medium", "Solar PPA and the BOI solar measure", "The PPA very likely gives up the BOI " + "solar measure (owned solar and its tax benefit) and adds a power price, ~0.03M USD a year " + "in the calculator at 3.0 THB/kWh, an estimate to quote", "The BOI consultant's reading " + "and PPA offers next to the purchase quote in phase 0; buying the array, as Plan B does, " + "stays the alternative"]) + rows += [ + ["Medium", "Lease terms and building ownership", "A weak lease makes the building hard to finance " + "and exposes it at expiry", "Registered 30 to 50 year lease with renewal, explicit building " + "ownership and assignment rights; Thai counsel in phase 0"], + ["Medium", "Soil conditions", "Piling could add several hundred to 1,000+ THB/m² across building, " + "paving and fill", "Soil boring test in phase 0 (THB 30k to 50k)"], + ["Medium", "Galvanics permitting", "Effluent and hazardous-substance permitting are the most likely " + "regulatory friction, now in the first factory licence", "Zero-discharge design and the " + "water-treatment building from the " + "start; industrial estate option; " + "lessor's consent on Payap land"], + ["Medium", "Utilities fuel choice open", "Biomass heat costs a quarter to a tenth of electric steam " + "at reported fuel prices; electric steam needs a larger grid connection, biomass a secured fuel " + "supply", "Decide before the boiler request and the grid application; quote electric and fired " + "variants of the same modules"], + ["Medium", "Boiler import compliance (DIW)", pick( + "This plan imports its boiler modules from China: an imported boiler must meet ASME, JIS, EN or " + "equivalent and be verified by a DIW-registered certification body; the modules run above the " + "once-through relief", + "An imported boiler must meet ASME, JIS, EN or equivalent and be verified by a DIW-registered " + "certification body; the modules run above the once-through relief"), + "ASME Section I design with the S stamp and the full dossier; certification body engaged before the " + "order; the same for a Thai-bought boiler"], + ["Medium", "Single press vendor (Newbilt)", pick( + "All three presses, the extruders and the hydraulic aggregates come from one small German " + "manufacturer; build time and order book unknown", + "All five presses, the extruders and the hydraulic aggregates come from one small German " + "manufacturer; build time and order book unknown"), + "Spares and service terms in the re-quote; the Pheenix automatic press stays the comparison if the " + "Classic quote disappoints"], + ["Medium", "Hydraulic ring-main contamination", "One shared oil system: a contamination event " + "reaches every press", "ISO 4406 target, flushing to ISO 23309, particle counts at acceptance " + "and after flushing, non-bypass branch filters, isolation per press, online particle counter, " + "kidney loop; central plant still to be quoted"], + ["Medium", "Currency", "EUR on Newbilt and Pheenix, USD on Sibert and Sillitoe, THB costs, USD/EUR " + "revenue; a 10 % baht move is worth 0.09 to 0.17 USD per record on margin", "Currency and validity " + "in every quote; THB " + "pricing regionally; " + "hedging decision with " + "the investor"], + ["Medium", "Vinyl demand is cyclical", "Global capacity has been added; the model assumes the plant " + "sells what it presses", pick("Mixed fleet suits boutique work that is less cyclical; cassette and " + "CD-R lines diversify once added; growth options wait for demand", + "Mixed fleet suits boutique work that is less cyclical; cassette and " + "CD-R lines diversify; further growth waits for demand")], + ["Medium", "Reject rate in early production", "Early runs, and the first stampers from a new " + "galvanics room, will be worse than the 5 to 10 % allowance while the process settles", "Vendor " + "commissioning, stamper metrology, materials lab from day one, QC layers, conservative launch " + "promises; the ramp-up reserve"], + ["Medium", "Competitive response", "The incumbent may add plating, or a second entrant may appear; " + "the domestic price ceiling may compress on our arrival", "Compete on capability (traceability, " + "QC, climate), export customers, and " + "the collaboration under discussion"], + pick(["Low", "Solar integration under the PPA", "Rack voltage vs inverter window, certifications and " + "warranty move to the installer, but the plant still depends on the array", "Engineering checks " + "of the installer's design in phase 0; large float"], + ["Low", "Solar and battery integration", "Rack voltage vs inverter window; unpublished " + "certifications; mixed-vendor warranty", "Engineering checks and certificate requests in phase " + "0; large float"]), + ["Low", "Cassette supply chain", pick("Blank tape and shells come from few suppliers, once the lines " + "are added", "Blank tape and shells come from few suppliers"), + "Hold stock; qualify two sources"], + ["Low", "CD replication scope creep", "Adds USD 1.5M to 4.0M and a second commissioning programme", + "Decide before BOI filing; treat as a separate project if chosen"], + ] + return rows def blocks(): + a = is_a() return [ # ------------------------------------------------- 8 investment H1("8. Investment"), - P("Everything priced or estimated so far, rolled into one view of the launch plant decided in October " - "2026: one capital round for the whole chain, from the cutting room to the shrink wrapper, " - "commissioned in sequence. Blocks marked 'estimate' have no vendor confirmation; the rest trace to " - "quotes, published prices or researched ranges. Treat all figures as budgetary with a wide margin " - "(plus or minus 30 to 50 % on the estimates) until requests for quotation replace them. Exchange " - "rates: 1 USD = 33 THB, 1 EUR = 1.155 USD, 1 GBP = 1.35 USD."), + P(pick( + "This chapter prices **Plan A (~180M THB)**: the launch plant decided in October 2026, one Newbilt " + "Duplex system and one Classic with the whole chain from the cutting room to the shrink wrapper, " + "in one capital round and commissioned in sequence, brought down with six cost levers that keep " + "every machine. ", + "This chapter prices **Plan B (~225M THB)**: the launch plant decided in October 2026, with the " + "whole chain from the cutting room to the shrink wrapper, plus the second Duplex system at launch: " + "five presses with everything in, in one capital round and commissioned in sequence. ") + + "The plan price carries the ramp-up reserve, because that is cash the investor puts in, and **no " + "contingency**. Blocks marked 'estimate' have no vendor confirmation; the rest trace to quotes, " + "published prices or researched ranges. Treat all figures as budgetary with a wide margin (plus or " + "minus 30 to 50 % on the estimates) until requests for quotation replace them. Exchange rates: " + "1 USD = 33 THB, 1 EUR = 1.155 USD, 1 GBP = 1.35 USD."), P("The September 2026 draft of this plan priced a phased entry (one press, bridge stampers, outsourced " - "cutting) and a five-press full vision. Both are superseded by the launch plant below and are not " - "repeated here; the planning repository keeps them for the record."), + "cutting) and a five-press full vision. Both are superseded, as is the launch-plant budget with a " + "15 % contingency of the previous draft; they are not repeated here, and the planning repository " + "keeps them for the record."), - H2("8.1 The launch plant, all blocks"), - T(["Block", "USD", "THB", "Basis"], [ - ["Phase 0: BOI consultant, legal and lease work, soil test, re-quotes", "40k to 80k", - "1.3M to 2.6M", "Estimate"], - ["Newbilt Duplex system (two HRP 12 presses, EX 50 main and EX 35 colour extruder, trimmer, label " - "oven, shrink wrapper, grinder, label punch)", "350k to 370k", "11.6M to 12.2M", - "Quoted: 2024 offer EUR 200,500 for the Single 2.1 plus the quoted second press and extruder " - "~USD 115k; expired, re-quote"], - ["Newbilt Classic, fully automatic press", "290k to 460k", "9.6M to 15.2M", "Placeholder (the old " - "automatic-press band per press); **no Newbilt price on file**"], - ["Pheenix galvanics line (PASU, PPPU, one PDPU, PMPB)", "320k to 650k", "10.6M to 21.4M", - "Estimate; **no Pheenix price on file**; OMS's reference prices for a 4-cell wet room (EUR 224k " - "to 311k, ~USD 259k to 359k) sit at the low end"], - ["Galvanics water: zero-discharge (ZLD) evaporator and DI water", "97k to 258k", "3.2M to 8.5M", - "Researched: utilities rows, now launch scope"], - ["Water-treatment building next to galvanics (~12 × 10 m, proposed)", "52k to 87k", "1.7M to 2.9M", - "Estimate at the building rate below"], - ["Sibert stamper prep: VSF back-finisher, VSP punch, VSC coiner", "250k", "8.3M", "Sibert's budget " - "confirmation, 5 October 2026; its time, spares, shipping and travel sit in the freight and " - "working-capital lines"], - ["Cutting room: Sillitoe SDMS lathe, spare cutterhead and support, mastering console and chain, " - "monitoring, room build-out", "200k to 350k", "6.6M to 11.6M", "SDMS list price USD 125k (ex tax " - "and shipping); the rest estimate"], - ["Metrology and QC stack (XRF, laser confocal, wide-area profiler, inline vision on three presses, " - "audio station)", "350k to 810k", "11.6M to 26.7M", "Estimate, phaseable"], - ["PVC lab, day-one tier", "55k to 150k", "1.8M to 5.0M", "Estimate"], - ["Utilities, solar, battery, HVAC, clean zones, racking", "863k to 1,477k", "28.5M to 48.7M", - "Researched: Thai supplier ranges, re-sized for three presses (two chiller modules instead of " - "three)"], - ["Building ~1,500 m² plus civil and site works", "650k to 1,100k", "21.4M to 36.3M", "Estimate at " - "12,000 to 20,000 THB/m² plus ~20 % site works; soil is the main variable"], - ["Overhead crane, runway, frame premium, machine door", "97k to 227k", "3.2M to 7.5M", "Estimate"], - ["Maintenance workshop and machine bay fit-out", "30k to 76k", "1.0M to 2.5M", "Estimate"], - ["Visitor corridor and accessible entrance", "67k to 148k", "2.2M to 4.9M", "Estimate"], - ["Utility yard built for four boiler and four chiller modules", "73k to 122k", "2.4M to 4.0M", - "Estimate"], - ["Factory software, ERPNext, artist platform public side", "115k to 310k", "3.8M to 10.2M", - "Estimate: factory software 60k to 170k, ERPNext implementation 15k to 50k, artist platform " - "40k to 90k"], - ["Cassette duplication and CD-R duplication", "55k to 190k", "1.8M to 6.3M", "Estimate, sections " - "4.8 and 4.9"], - ["Freight, installation, commissioning, training (Pheenix, Sibert, Sillitoe, Newbilt beyond its " - "quoted 5 days)", "150k to 300k", "5.0M to 9.9M", "Estimate"], - ["Working capital, PVC stock, spares, lease deposit, first-year rent", "135k to 290k", - "4.5M to 9.6M", "Estimate; land is leased, so no land purchase"], - ["Subtotal", "~4.24M to 7.71M", "~140M to 254M", ""], - ["Contingency 15 %", "~0.64M to 1.16M", "~21M to 38M", ""], - ["**Total, launch plant**", "**~4.9M to 8.9M**", "**~161M to 292M**", "**Midpoint ~6.9M USD, " - "~227M THB**"], - ], widths_mm=[52, 30, 30, 58], font_pt=8.5, - caption="Source: docs/finance/total-investment.md, 'Launch plant (October 2026)'. The second Duplex " - "system and further Classics are growth options with room reserved (hall floor, utility " - "module positions, ring-main tees), not part of this total."), - P("**Not in the total:** a reserve for the ramp-up (staff hired before first revenue, overheads until " - "volume covers them), ~10M to 20M THB, estimate; CD replication (section 4.9); financing costs; " - "currency moves; the mobile shelving for the father and mother archive (to quote); and the central " - "hydraulic plant around the Newbilt aggregates (standby pump set, accumulator station, ring main), " - "not costed yet, for a Thai hydraulic power unit builder to quote. The blocks are vendor prices " - "without Thai duty or import VAT, so they assume BOI promotion: without it, ~5 % duty on ~2.3M USD " - "of imported machinery (~0.11M USD) comes on top, plus ~0.17M USD of import VAT paid at the border " - "and reclaimed later (estimates)."), + H2(pick("8.1 Plan A, all blocks", "8.1 Plan B, all blocks")), + T(["Block", "USD", "THB", "Basis"], _block_rows(), widths_mm=[52, 30, 30, 58], font_pt=8.5, + caption=pick( + "Source: docs/finance/total-investment.md, 'Two plans', and the Plan A preset of the plant and " + "business plan calculator (docs/fleet-calculator.html), whose rows are grouped here; estimates. " + "The second Duplex system and further Classics are growth options with room reserved (hall " + "floor, utility module positions, ring-main tees), not part of this plan.", + "Source: docs/finance/total-investment.md, 'Two plans', and the Plan B preset of the plant and " + "business plan calculator (docs/fleet-calculator.html), whose rows are grouped here; estimates. " + "Further Duplex systems and Classics are growth options: the hall is laid out for five Duplex " + "bays and four Classic positions.")), + P("**Not in the plan price:** a contingency (the blocks are budgetary, so the plan carries no buffer " + "for quotes landing high; at 15 % it would be " + pick("~24M", "~31M") + " THB at the midpoint); CD " + "replication (section 4.10); financing costs; currency moves; the mobile shelving for the father and " + "mother archive (to quote); and the central hydraulic plant around the Newbilt aggregates (standby " + "pump set, accumulator station, ring main), not costed yet, for a Thai hydraulic power unit builder " + "to quote. The blocks are vendor prices without Thai duty or import VAT, so they assume BOI " + "promotion: without it, ~5 % duty on ~2.3M USD of imported machinery (~0.11M USD, the launch " + "plant's estimate) comes on top, plus ~0.17M USD of import VAT paid at the border and reclaimed " + "later (estimates)" + pick( + ". Plan A imports its boiler modules and buys less metrology at launch; the estimate is not " + "re-sized for either.", + ". Plan B's second Duplex system adds ~0.23M to 0.30M USD of imported machinery to that.")), - H2("8.2 The investor's question: 180M THB, maybe 20 % more"), + H2("8.2 Two versions of this plan"), P("The lead investor asked in October 2026 whether the plant can be built for **180M THB (~5.45M USD), " - "possibly up to 20 % more (216M THB, ~6.55M USD)**. Against the launch-plant total:"), - T(["Case", "Launch plant", "Against 180M", "Against 216M"], [ - ["Low end of every block", "~161M THB", "Fits, ~19M to spare", "Fits"], - ["Midpoint", "~227M THB", "~47M over", "~11M over"], - ["High end of every block", "~292M THB", "~112M over", "~76M over"], - ], widths_mm=[50, 40, 40, 40]), - P("At the midpoint, four levers bring the plant inside 216M without dropping any of the machines " - "decided above (midpoint values with their share of the contingency, estimates):"), - T(["Lever", "Saves", "Launch plant after it"], [ - ["Rooftop solar and battery through a solar PPA (the installer owns and finances the array, the " - "plant buys the power) instead of buying them", "~12.3M THB", "~214M THB"], - ["Metrology launch tier (XRF, inline vision, audio station); the laser confocal and the wide-area " - "profiler bought from revenue", "~10.1M THB", "~204M THB"], - ["Pheenix galvanics priced near OMS's reference for a 4-cell wet room (EUR 224k to 311k)", - "~6.7M THB", "~198M THB"], - ["Visitor corridor built later; the plant runs without public tours at first", "~4.1M THB", - "~193M THB"], - ], widths_mm=[110, 26, 34]), - CALL("Reading this honestly", [ - "**216M THB is a realistic target for the full equipment list; 180M THB holds only if the open " - "quotes land low.** With the four levers and the ramp-up reserve of ~10M to 20M THB on top, the " - "midpoint comes to ~203M to 213M THB, inside 216M.", - "**180M is a low-quote outcome, not a plan.** Reaching it at the midpoint needs scope cuts on top " - "of the levers: cassette and CD-R later (~4.6M THB) and a rented crane for the installations while " - "the frame stays crane-ready (~3.7M THB) give ~185M before the reserve, still above 180M.", - "**Chinese suppliers do not change the answer.** Boilers, compressed air and hydraulics were " - "checked in October 2026: about 2M THB at the midpoint (~2.5M with contingency), ~1 % of the " - "target. Worth taking for the two boiler modules (ASME-stamped 1.25 MPa design; an imported " - "boiler must be verified by a certification body registered with the Thai Department of " - "Industrial Works) and for the compressor (Kaishan and Denair have Thai offices). The Newbilt " - "hydraulic aggregates stay Newbilt's. Chinese chillers and HVAC, larger blocks, are not checked " - "yet.", + "possibly up to 20 % more**. The answer is two versions of this plan, built from the same documents, " + "both priced without contingency and with the ramp-up reserve: **Plan A** keeps every machine of " + "the launch plant and brings it to ~180M THB with six cost levers; **Plan B** adds the second " + "Duplex system at launch, five presses with everything in, at ~225M THB (Plan A plus 25 %). This " + "document is " + label() + ". How the two differ (estimates):"), + T(["Midpoints, estimates", "Plan A" + pick(" (this plan)", ""), "Plan B" + pick("", " (this plan)")], [ + ["Plan price: ramp-up reserve in, no contingency", "~177M THB (~5.35M USD): ~180M", + "~224M THB (~6.79M USD): ~225M"], + ["Low to high end of every block", "~127M to 226M THB", "~162M to 286M THB"], + ["Presses", "3: Duplex system 1 (two HRP 12) and one Classic", + "5: two Duplex systems (four HRP 12) and one Classic"], + ["Records a year at 60 % specials", "~0.58 to 0.90M, central 0.74M (Duplex-limited)", + "~1.0 to 1.5M, central 1.25M"], + ["Revenue, central", "3.65M USD (~120M THB)", "6.05M USD (~200M THB)"], + ["EBITDA, central", "1.73M USD", "3.14M USD"], + ["Operating profit, adverse case", "-0.39M USD: loses money", "0.02M USD: just covers depreciation"], + ["Payback on the plan price, central (EBITDA, mature year)", "~3.1 yr (2.2 to 4.0)", + "~2.2 yr (1.6 to 2.8)"], + ["What it gives up or takes on", "Six levers: solar through a PPA (very likely without the BOI " + "solar measure), confocal and profiler from revenue, no tours at first, cassette and CD-R later, a " + "rented crane, Chinese boilers and compressor; the second Duplex waits for revenue", "No levers; " + "needs ~1.25M records sold a year, ~0.75M of them specials, which the market data does not show " + "yet; a longer ramp on the same reserve; ~27 % more capital"], + ], widths_mm=[46, 62, 62], font_pt=8.5, + caption="Estimates: docs/finance/total-investment.md 'Two plans' and docs/finance/revenue-model.md " + "'Operating pictures of Plan A and Plan B'. Section 9 has this plan's operating picture."), + *( + [P("**Plan A: six levers, every machine kept.** From the launch plant with every block, no " + "contingency, midpoint values:"), + _levers_table(), + P("Plan B takes none of these levers and adds the second Duplex system, a third chiller module, " + "their freight and installation and the working capital for ~1.25M records: ~209.2M THB before " + "the reserve, ~224M with it.")] + if a else + [P("**Plan B: the launch plant plus the second Duplex system, no levers.** Midpoint values:"), + _additions_table(), + P("Plan B takes none of Plan A's six levers (~32M THB at the midpoint together): it keeps owned " + "solar and battery, and with them the BOI solar measure, the full metrology stack, the visitor " + "corridor from the start, the bought crane, cassette and CD-R, and Thai-supplied utilities.")] + ), + CALL("What decides between Plan A and Plan B", [ + "**Demand first.** Plan B needs ~1.25 million records sold a year in its central case, about 70 % " + "more than Plan A's 0.74 million, three fifths of them special editions. Market validation " + "(section 14.1, item 1) is the evidence for that, and it is not in yet.", + "**The quotes.** The Newbilt re-quote for the Classic and the EX 35 (in Plan B also the second " + "Duplex system), the Pheenix quote against the OMS reference, the building quote with the soil " + "test, and, for Plan A, the solar PPA offer.", + "**Neither price carries a contingency.** Quotes landing high are funded outside the plan price or " + "by scope steps (section 8.4).", + pick("**The second Duplex stays a growth step.** Its floor, utility module positions and ring-main " + "tees are reserved, so adding it from revenue is a step, not a rebuild.", + "**The second Duplex is commissioned last.** If validation does not show the demand, it is " + "the part of Plan B that can still return to a growth step, leaving the three-press launch " + "plant."), ]), - P("**What decides it.** The Classic and the Pheenix galvanics line have no price on file, and the " - "building depends on the soil. Four requests settle most of the band: the Newbilt re-quote for the " - "Duplex and the Classic, a Pheenix quote for the galvanics line, the building request for quotation " - "with a soil test, and distributor quotes for the metrology stack. Until they are in, the plan " - "quotes **~216M THB as the target** with the levers above, and 180M as the low-quote case."), + P("Figure 5 is the budget check of the plant and business plan calculator with the " + label() + + " preset, contingency kept out of the total as in this plan."), + IMG(pick("renders/calculator/plan-a-budget.png", "renders/calculator/plan-b-budget.png"), 160, + "Figure 5. Budget card of the plant and business plan calculator, " + pick( + "Plan A preset: 161.7M THB at the midpoint without contingency, 171.7M to 181.7M with the " + "ramp-up reserve of 10M to 20M, inside 180M at the midpoint", + "Plan B preset: 209.2M THB at the midpoint without contingency, 219.2M to 229.2M with the " + "ramp-up reserve of 10M to 20M, inside 225M at the midpoint") + + ". Bars: the investment at the low end, the midpoint and the high end of every block, the reserve " + "hatched, against 180M and 225M THB. Calculator figures (docs/fleet-calculator.html), estimates."), H2("8.3 Tranches"), - P("The launch plant is one capital round, but it is not one payment. Capital is released against " - "milestones, so each tranche is spent only once the previous gate has cleared. Because cutting and " - "galvanics are commissioned first and have their own build times, their orders sit in the first " - "long-lead tranche next to the presses. The shares below are estimates for planning the calls on " - "capital, not a payment schedule agreed with any vendor."), - T(["Tranche", "Trigger", "Covers", "Approx. share"], [ - ["0", "Now", "Phase 0 work (section 14.1)", "1 to 2 %"], - ["1", "BOI certificate issued; lease signed; zoning and soil confirmed; pricing validated", - "Deposits on every long-lead order: Pheenix galvanics line, Sillitoe lathe, Sibert line, Newbilt " - "Duplex and Classic; building design and permit; first boiler and chiller modules", "20 to 30 %"], - ["2", "Building permit; vendor build dates confirmed in writing", "Construction, water-treatment " - "building, utility yard, utilities, balance payments as machines are built", "35 to 45 %"], - ["3", "Building watertight; first machinery shipped", "Fit-out, HVAC and clean zones, ZLD and DI " - "water, crane, metrology, factory software and ERPNext, cassette and CD-R lines, the launch team", - "15 to 20 %"], - ["4", "Cutting room and galvanics commissioned; first stampers made", "Working capital, PVC stock, " - "spares, first-year rent; the ramp-up reserve (outside the total) is drawn from here on", - "8 to 12 %"], - ], widths_mm=[16, 54, 74, 26]), + P("The plan is one capital round, but it is not one payment. Capital is released against milestones, " + "so each tranche is spent only once the previous gate has cleared. Because cutting and galvanics are " + "commissioned first and have their own build times, their orders sit in the first long-lead tranche " + "next to the presses. The shares below are estimates for planning the calls on capital, not a " + "payment schedule agreed with any vendor."), + _tranches(), + *([] if a else [P("The second Duplex system is commissioned last (section 11.1). Its order sits with " + "the other long-lead items in tranche 1, and it is the one order that could still be " + "moved to a growth step if the demand case weakens before the round is called.")]), H2("8.4 What moves the number"), B([ + "**No contingency in the price.** " + pick( + "Plan A's ~177M THB is the midpoint of every block with the ramp-up reserve and no buffer: at " + "15 % a contingency would add ~24M THB, and the high end of every block comes to ~226M. ", + "Plan B's ~224M THB is the midpoint of every block with the ramp-up reserve and no buffer: at " + "15 % a contingency would add ~31M THB, and the high end of every block comes to ~286M. ") + + "Quotes landing above the midpoint are funded outside the plan price or by scope steps; how they are " + "funded is a decision for the investor before commitment (section 14.2).", + "**The quotes that decide it.** The Classic has no Newbilt price (its band is a placeholder " + "borrowed from another vendor's automatic press); the Pheenix line is priced at OMS's reference " + "plus 20 %, without a Pheenix figure; " + pick( + "the EX 35 is priced only as the expired 2024 quote's second-extruder option; the building " + "depends on the soil; and the solar PPA lever depends on an offer. The Newbilt re-quote, the " + "Pheenix quote, the building request with a soil test, the metrology distributor quotes and " + "the PPA offers settle most of the band.", + "the second Duplex system's EX 35 has no price on file (the first is priced as the expired " + "2024 quote's second-extruder option); and the building depends on the soil. The Newbilt " + "re-quote, the Pheenix quote, the building request with a soil test and the metrology " + "distributor quotes settle most of the band."), "**BOI promotion.** The machinery duty and import VAT exemption applies across most of the " - "equipment blocks (~0.11M USD of duty and ~0.17M USD of import VAT cash flow, estimates), and the " - "automation and solar spend converts into corporate income tax exemption headroom. The application " - "precedes every purchase order. One interaction to check with the BOI consultant: the solar measure " - "is based on the plant's own solar investment, so the solar PPA lever would likely give that " - "headroom up (our reading).", + "equipment blocks (~0.11M USD of duty and ~0.17M USD of import VAT cash flow on the launch plant, " + "estimates), and the automation and solar spend converts into corporate income tax exemption " + "headroom. The application precedes every purchase order. " + pick( + "The solar measure is based on the plant's own solar investment, so Plan A's solar PPA would " + "likely give that headroom up (our reading, a question for the BOI consultant).", + "Plan B owns its solar array, so it keeps the solar measure."), "**The ground.** Soft paddy soil under the building, paving and fill platform is the single largest " "cost variable in the building package, and the cheapest to resolve: a soil boring test costs " "THB 30k to 50k.", - "**The two missing machine prices.** The Classic and the Pheenix line carry two of the widest " - "machine bands in the table and have no vendor price at all. The Classic band is a placeholder " - "borrowed from another vendor's automatic press.", - "**Chinese suppliers: ~1 %.** Checked for boilers, compressed air and hydraulics, worth about 2M " - "THB (section 8.2). Chillers and HVAC are the larger blocks and have not been checked yet; that is " - "the next Chinese lever to test.", - "**Solar PPA.** The largest single lever (~12.3M THB at the midpoint) moves the array off the " - "capital budget and adds a power price to the energy line instead.", + pick("**Chinese suppliers: taken where they pay.** Plan A buys the boiler modules and the " + "compressor through the Chinese route (~1.9M THB at the midpoint, about 1 % of the price); the " + "Newbilt hydraulic aggregates stay Newbilt's. Chillers and HVAC, the larger blocks, are not " + "checked yet; that is the next Chinese lever to test.", + "**Chinese suppliers: ~1 %.** Plan B prices Thai-supplied utilities. The Chinese route for the " + "boiler modules and the compressor would take ~1.9M THB off at the midpoint (Plan A takes " + "it); chillers and HVAC, the larger blocks, are not checked yet."), + pick("**Solar PPA.** The largest single lever (~10.7M THB at the midpoint) moves the array off the " + "capital budget and adds a power price to the energy line instead (~0.03M USD a year in the " + "calculator at 3.0 THB/kWh, an estimate to quote).", + "**Solar bought, not leased.** Plan B owns the array and the battery (8.9M to 12.5M THB). A " + "solar PPA would take ~10.7M THB off the price at the midpoint and add a power price to the " + "energy line instead, very likely without the BOI solar measure."), "**Every band narrows only with quotes.** The supplier map in the planning repository lists who to " "ask, and the re-quotes are phase 0 work (section 14).", ]), @@ -170,27 +568,34 @@ def blocks(): H2("8.5 Currency exposure"), P("Revenue will be mostly USD and EUR from export customers; the cost base is mostly THB; the equipment " "is priced in several currencies. Newbilt quotes in EUR, and the Pheenix line is expected in EUR " - "(European vendor, no quote yet; the currency is a stated field in the request). Sibert's budget and " - "Sillitoe's list price are in USD (Sibert is a UK company, Sillitoe Australian). None of it is " - "hedged, and the orders will not be placed for roughly a year. In the September draft a 10 % move " - "in EUR/THB was worth USD 25k to 35k on the Duplex line alone; with the Classic and the galvanics " - "line also in EUR, the three EUR lines come to ~0.96M to 1.48M USD, so the same move is worth " - "roughly USD 0.1M to 0.15M (estimate)."), + "(European vendor, no quote yet; the currency is a stated field in the request; the plan prices it " + "at OMS's EUR reference plus 20 %, EUR 280.8k to 385.2k). Sibert's budget and Sillitoe's list price " + "are in USD (Sibert is a UK company, Sillitoe Australian). None of it is hedged, and the orders will " + "not be placed for roughly a year. In the September draft a 10 % move in EUR/THB was worth USD 25k " + "to 35k on the Duplex line alone; " + pick( + "with the Classic and the galvanics line also in EUR, the three EUR lines come to ~0.96M to " + "1.28M USD, so the same move is worth roughly USD 0.10M to 0.13M (estimate).", + "with the second Duplex system, the Classic and the galvanics line also in EUR, the four EUR " + "lines come to ~1.19M to 1.58M USD, so the same move is worth roughly USD 0.12M to 0.16M " + "(estimate).")), P("Operationally, roughly two-thirds of direct cost (labour, energy, local cartons, maintenance) is " "THB, so a 10 % baht appreciation takes **0.09 to 0.17 USD off the gross margin per record** without " - "any operational change, enough to push the adverse case further under water. Three mitigations " - "are planned: every re-quote states its currency and validity period; decide early whether to " - "quote regional customers in THB; and decide, once the BOI timeline is known, whether to hedge the " - "EUR orders. The hedging decision belongs to the investor."), + "any operational change, " + pick("enough to push the adverse case further under water. ", + "enough to push the adverse case, which only just covers " + "depreciation, under water. ") + + "Three mitigations are planned: every re-quote states its currency and validity period; decide early " + "whether to quote regional customers in THB; and decide, once the BOI timeline is known, whether to " + "hedge the EUR orders. The hedging decision belongs to the investor."), # ------------------------------------- 9 revenue and operating model H1("9. Revenue and operating model"), - P("A first-pass economic model of the launch plant in a mature year. Most numbers are estimates from " - "industry pricing norms and the project's own cost research; the point is the shape of the economics " - "and which levers matter, not precision. The price assumption is deliberately held at the " - "conservative Western export level even though the one set of Thai market data (section 3.3) says " - "domestic prices are several times higher: re-basing the whole model on one supplier's price list " - "in a market with one supplier would be worse than leaving it low."), + P("A first-pass economic model of " + pick("Plan A's three presses", "Plan B's five presses") + " in a " + "mature year. Most numbers are estimates from industry pricing norms and the project's own cost " + "research; the point is the shape of the economics and which levers matter, not precision. The price " + "assumption is deliberately held at the conservative Western export level even though the one set " + "of Thai market data (section 3.3) says domestic prices are several times higher: re-basing the " + "whole model on one supplier's price list in a market with one supplier would be worse than leaving " + "it low."), H2("9.1 Pricing assumptions"), B([ @@ -216,32 +621,54 @@ def blocks(): "**Per-title services: USD 580 to 1,730 per title** (THB 19k to 57k) for mastering, cutting, " "stampers and test pressings. The middle of the range is the **artist-demo per-title fee of 37,836 " "THB**: mastering 10,000, lacquer 5,336, cutting 4,000, plating 14,000, press set-up 3,000 and " - "tests 1,500. The launch plant models 200 to 400 titles a year; mastering is labour-bound, and the " - "plan staffs one to two engineers, which caps this line.", - "**Cassettes and CD-Rs** are add-on lines, not in the operating picture. The September draft " - "illustrated them at 20k to 60k cassettes a year at USD 2.50 to 4.00 and 10k to 40k CD-Rs at USD " - "1.50 to 3.00; estimates with no market data behind them yet.", + "tests 1,500. " + pick("Plan A models 200 to 400 titles a year", "Plan B models 300 to 400 titles " + "a year (375 central)") + + "; mastering is labour-bound, and the plan staffs one to two engineers, which caps this line.", + pick("**Cassettes and CD-Rs** come later in Plan A (a growth step, lever 4) and are not in the " + "operating picture. The September draft illustrated them at 20k to 60k cassettes a year at " + "USD 2.50 to 4.00 and 10k to 40k CD-Rs at USD 1.50 to 3.00; estimates with no market data " + "behind them yet.", + "**Cassettes and CD-Rs** are add-on lines in the plant from launch, not in the operating " + "picture. The September draft illustrated them at 20k to 60k cassettes a year at USD 2.50 to " + "4.00 and 10k to 40k CD-Rs at USD 1.50 to 3.00; estimates with no market data behind them " + "yet."), "**Dropshipping fees** per parcel and **stamper supply to other plants** are on top and not " "modelled.", ]), - H2("9.2 Capacity and revenue of the launch plant"), - P("Three presses make **~0.58 to 0.90 million records a year on two shifts at 60 % specials** " - "(estimate). Specials run only on the Duplex system (the Classic has one built-in extruder), so its " - "two semi-automatic presses at 60 to 80 records an hour each set the pace, and the Classic (~128 an " - "hour, 28 s cycle, vendor flyer) presses the standard 40 % at about two thirds load; at 60 to 70 % " - "effectiveness, 16 hours a day and 300 days a year. At ~20 % specials the same presses made 0.71 to " - "0.97 million. The press fleet calculator, at the team's planning rates (3 records a minute per " - "Duplex system, 2 per Classic, 65 % effectiveness), stays balanced at ~0.94 million. The central " - "case takes the middle, 0.74 million."), - T(["USD per year", "Adverse", "Central", "Favourable"], [ + H2(pick("9.2 Capacity and revenue of Plan A", "9.2 Capacity and revenue of Plan B")), + P(pick( + "Three presses make **~0.58 to 0.90 million records a year on two shifts at 60 % specials** " + "(estimate). Specials run only on the Duplex system (the Classic has one built-in extruder), so its " + "two semi-automatic presses at 60 to 80 records an hour each set the pace, and the Classic (~128 an " + "hour, 28 s cycle, vendor flyer) presses the standard 40 % at about two thirds load; at 60 to 70 % " + "effectiveness, 16 hours a day and 300 days a year. At ~20 % specials the same presses made 0.71 to " + "0.97 million. The plant and business plan calculator, at the team's planning rates (3 records a " + "minute per Duplex system, 2 per Classic, 65 % effectiveness), stays balanced at ~0.94 million. " + "The central case takes the middle, 0.74 million.", + "Five presses make **~1.0 to 1.5 million records a year on two shifts at 60 % specials** " + "(estimate). Specials run only on the Duplex systems (the Classic has one built-in extruder), but " + "with two of them the plant is not Duplex-limited: the four semi-automatic presses, 240 to 320 " + "records an hour together, carry the specials, and the Classic (~128 an hour, 28 s cycle, vendor " + "flyer) the rest; at 60 to 70 % effectiveness, 16 hours a day and 300 days a year that is ~1.06 to " + "1.5 million. The plant and business plan calculator, at the team's planning rates (3 records a " + "minute per Duplex system, 2 per Classic, 65 % effectiveness), gives ~1.5 million. The central " + "case takes 1.25 million.")), + T(["USD per year", "Adverse", "Central", "Favourable"], pick([ ["Records", "0.58M", "0.74M", "0.90M"], ["Blended price, 60 % specials", "3.76", "4.49", "5.27"], ["Pressing revenue", "~2.17M", "~3.31M", "~4.72M"], ["Titles × per-title fee", "200 × 580", "300 × 1,155", "400 × 1,730"], ["Title-services revenue", "~0.12M", "~0.35M", "~0.69M"], ["**Revenue**", "**2.28M (~75M THB)**", "**3.65M (~120M THB)**", "**5.41M (~179M THB)**"], - ], widths_mm=[50, 40, 40, 40], + ], [ + ["Records", "1.0M", "1.25M", "1.5M"], + ["Blended price, 60 % specials", "3.76", "4.49", "5.27"], + ["Pressing revenue", "~3.76M", "~5.61M", "~7.91M"], + ["Titles × per-title fee", "300 × 580", "375 × 1,155", "400 × 1,730"], + ["Title-services revenue", "~0.17M", "~0.43M", "~0.69M"], + ["**Revenue**", "**3.93M (~130M THB)**", "**6.05M (~200M THB)**", "**8.60M (~284M THB)**"], + ]), widths_mm=[50, 40, 40, 40], caption="Estimate. Pressing and title revenue are records × price and titles × fee; the totals are " "those of docs/finance/revenue-model.md. A pure-volume plant runs at the low per-title " "end; a boutique-heavy mix pushes titles up and volume down."), @@ -256,23 +683,34 @@ def blocks(): "largely pass-through"], ["Shrink wrap", "0.02 to 0.03", "0.8 to 1.1", "Film"], ["Energy", "0.12 to 0.23", "3.8 to 7.6", "~1.5 to 2 kWh blended per record at grid/solar mix"], - ["Production labour, launch plant", "**0.13 to 0.28**", "4.2 to 9.3", "13 to 19 direct staff, " - "3.7M to 5.4M THB a year, over 0.58 to 0.90M records (0.08 to 0.16 on the five-press fleet)"], + pick(["Production labour, Plan A", "**0.13 to 0.28**", "4.2 to 9.3", "13 to 19 direct staff, " + "3.7M to 5.4M THB a year, over 0.58 to 0.90M records (0.08 to 0.16 on five presses)"], + ["Production labour, Plan B", "**0.08 to 0.16**", "2.6 to 5.4", "13 to 19 direct staff, " + "3.7M to 5.4M THB a year, over 1.0 to 1.5M records (0.13 to 0.28 on three presses)"]), ["Stamper amortisation", "0.03 to 0.12", "1.0 to 4.0", "In-house three-generation set at ~USD 60 " "to 150 marginal over 1,000 to 2,000 " "pressings"], ["Maintenance, spares, consumables", "0.12 to 0.23", "3.8 to 7.6", "Estimate"], ["Reject allowance", "0.12 to 0.17", "3.8 to 5.7", "5 to 10 % reject rate carried by good units"], - ["**Total direct cost, launch plant**", "**~1.35 to 2.70**", "**~45 to 89**", "Central 2.00; no " - "extra cost for specials yet"], + pick(["**Total direct cost, Plan A**", "**~1.35 to 2.70**", "**~45 to 89**", "Central 2.00; no " + "extra cost for specials yet"], + ["**Total direct cost, Plan B**", "**~1.30 to 2.58**", "**~43 to 85**", "Central 1.94; no " + "extra cost for specials yet"]), ], widths_mm=[42, 26, 26, 76], font_pt=8.5, caption="Estimates, docs/finance/revenue-model.md. THB at 33 per USD."), - P("**Why labour per record is higher than in the September draft.** Two shifts need the full press, " - "finishing, galvanics, QC and maintenance crews whether the hall holds three presses or five, so " - "the direct payroll stays at 3.7M to 5.4M THB a year (113k to 163k USD) while the volume falls from " - "1.0 to 1.5 million records to 0.58 to 0.90 million. Labour per record rises to **0.13 / 0.19 / " - "0.28 USD** (favourable / central / adverse), and the direct cost to 1.35 / 2.00 / 2.70 USD. The " - "build-up, at northern Thai rates loaded ×1.3 for social security, overtime, bonus and PPE:"), + P(pick( + "**Why labour per record is higher than in the September draft.** Two shifts need the full press, " + "finishing, galvanics, QC and maintenance crews whether the hall holds three presses or five, so " + "the direct payroll stays at 3.7M to 5.4M THB a year (113k to 163k USD) while the volume falls from " + "1.0 to 1.5 million records to 0.58 to 0.90 million. Labour per record rises to **0.13 / 0.19 / " + "0.28 USD** (favourable / central / adverse), and the direct cost to 1.35 / 2.00 / 2.70 USD. The " + "build-up, at northern Thai rates loaded ×1.3 for social security, overtime, bonus and PPE:", + "**Five presses spread the same crews.** Two shifts need the full press, finishing, galvanics, QC " + "and maintenance crews whether the hall holds three presses or five, so the direct payroll stays at " + "3.7M to 5.4M THB a year (113k to 163k USD), and Plan B spreads it over 1.0 to 1.5 million records: " + "**0.08 / 0.11 / 0.16 USD** a record (favourable / central / adverse), against 0.13 / 0.19 / 0.28 " + "on three presses, and a direct cost of 1.30 / 1.94 / 2.58 USD. The build-up, at northern Thai " + "rates loaded ×1.3 for social security, overtime, bonus and PPE:")), T(["Role", "Heads", "THB/month each, loaded"], [ ["Press and finishing operators", "8 to 12", "~19,500"], ["Galvanics", "2 to 3", "~32,500"], @@ -285,84 +723,134 @@ def blocks(): "health insurance with a yearly check-up (~0.35M THB a year for ~20 staff) and unified workwear " "(~0.3M THB a year) come on top of the ×1.3 and are not yet in the per-record figure."), - H2("9.4 Operating picture of the launch plant"), + H2(pick("9.4 Operating picture of Plan A", "9.4 Operating picture of Plan B")), P("Built from the components above. Three scenarios, each internally consistent: adverse pairs low " "volume with the low price, the high cost, the high capital and the high overheads; favourable does " "the opposite; central takes midpoints. Cash overheads (admin, sales, insurance, facility running, " "IT, professional fees, marketing, the land lease) are estimated at USD 0.20M to 0.45M a year and " - "paired high-to-adverse. Depreciation is 8.9M USD over 10 years (adverse), the 216M THB target " - "(~6.55M USD) over 12.5 years (central), and 4.9M USD over 15 years (favourable)."), - T(["USD per year, mature", "Adverse", "Central", "Favourable"], [ - ["Records", "0.58M", "0.74M", "0.90M"], - ["Blended price, 60 % specials", "3.76", "4.49", "5.27"], - ["Direct cost", "2.70", "2.00", "1.35"], - ["Contribution per record", "1.06", "2.49", "3.92"], - ["Pressing contribution", "0.61M", "1.83M", "3.51M"], - ["Title-services contribution", "0.07M", "0.23M", "0.48M"], - ["**Total contribution**", "**0.68M**", "**2.06M**", "**3.99M**"], - ["Cash overheads", "0.45M", "0.33M", "0.20M"], - ["**EBITDA**", "**0.23M**", "**1.73M**", "**3.79M**"], - ["Depreciation", "0.89M", "0.52M", "0.33M"], - ["**Operating profit**", "**-0.66M**", "**1.21M**", "**3.46M**"], - ["Revenue", "2.28M (~75M THB)", "3.65M (~120M THB)", "5.41M (~179M THB)"], - ["Payback (EBITDA, mature year)", "never", "~3.8 yr (2.8 to 5.1 on 4.9M to 8.9M)", "~1.3 yr"], - ], widths_mm=[50, 36, 48, 36], - caption="Estimates, docs/finance/revenue-model.md 'Operating picture of the launch plant (October " - "2026)'. Title services at 60 to 70 % contribution after lacquers, styli and nickel."), - CALL("Reading this table honestly", [ - "**The central case works on 216M THB.** EBITDA ~1.7M USD (~57M THB) and operating profit ~1.2M " - "USD (~40M THB) a year once the plant runs at volume. It breaks even on operating profit at about " - "**0.25 million records a year, about a third of its output**. Against the earlier ~20 % specials " - "share (0.84M records, EBITDA 1.63M) more specials earn a higher price on fewer records.", - "**The adverse case cannot cover depreciation at any volume three presses make.** It would need " - "~1.1 million records. It stacks the low price, the high cost, the high capital and the high " - "overheads at once. At the central cost and volume, the price that covers depreciation is only " - "~2.7 to 3.0 USD (~90 to 98 THB) a record, below the low price assumed: price realisation and " - "utilisation decide solvency, not upside.", + "paired high-to-adverse. Depreciation is on this plan's blocks: " + pick( + "the high end (6.25M USD) over 10 years (adverse), the midpoint (4.90M USD) over 12.5 years " + "(central) and the low end (3.56M USD) over 15 years (favourable). Payback is counted on the " + "whole plan price including the ramp-up reserve (3.86M / 5.35M / 6.85M USD from the low to the " + "high end).", + "the high end (8.07M USD) over 10 years (adverse), the midpoint (6.34M USD) over 12.5 years " + "(central) and the low end (4.61M USD) over 15 years (favourable). Payback is counted on the " + "whole plan price including the ramp-up reserve (4.92M / 6.79M / 8.67M USD from the low to the " + "high end).")), + _operating_table(), + CALL("Reading this table honestly", pick([ + "**The central case works on ~177M THB.** EBITDA ~1.7M USD (~57M THB) and operating profit ~1.3M " + "USD (~44M THB) a year once the plant runs at volume. It breaks even on operating profit at about " + "**0.2 million records a year, about a quarter of its central output**. Against the earlier ~20 % " + "specials share (0.84M records, EBITDA 1.63M) more specials earn a higher price on fewer records.", + "**The adverse case loses money.** It would need ~0.9 million records to cover depreciation, and " + "the three presses make 0.58 million at that rate. It stacks the low price, the high cost, the high " + "capital and the high overheads at once. At the central cost and volume the price that covers " + "depreciation is ~2.7 USD (~88 THB) a record (arithmetic on the table), below the low price " + "assumed: price realisation and utilisation decide solvency, not upside.", "**The central margin is too good to trust yet.** A central EBITDA margin of ~47 % is far above " "the 15 to 25 % pressing plants earn. The direct cost table counts only per-record consumables and " "direct payroll and leaves out indirect labour (supervision, planning, warehouse), freight, scrap " - "above the reject allowance and sales commissions. **Treat the adverse column as the honest one " - "until those lines exist.**", - "**This is a sensitivity, not a forecast.** The plant and business plan calculator, with its own " - "cost build-up (it adds electric steam heat and the cutting engineer, which this table leaves " - "out) and the team's faster Duplex planning rate, at which the launch plant is not Duplex-limited, " - "gives at 850k records and 60 % specials: revenue 4.14M, EBITDA 2.07M, operating profit 1.52M " - "USD, payback 3.3 years on a mature year; with a ramp of 35, 70 and 90 % in the first three " - "years, cash payback in year ~4.8 and ~18 % IRR over ten years, pre-tax and pre-financing " - "(estimates). " - "Not modelled here: cassette and CD-R lines, stamper supply to " - "other plants, dropshipping fees, and the ramp year. BOI tax exemptions shield part of early-year " - "profits where there are any.", - ]), + "above the reject allowance, sales commissions and the extra cost of specials. **Treat the adverse " + "column as the honest one until those lines exist.** The plan price carries no contingency either.", + "**This is a sensitivity, not a forecast.** The plant and business plan calculator's Plan A preset, " + "with its own cost build-up (it adds electric steam heat, the cutting engineer and the PPA power " + "price, ~0.03M USD a year, which this table leaves out) and the team's faster Duplex planning rate, " + "at which the three presses are not Duplex-limited, gives at 850k records and 60 % specials: " + "revenue ~4.14M, EBITDA 2.04M USD, payback 2.4 years on the 161.7M THB investment in a mature " + "year; with a ramp of 35, 70 and 90 % in the first three years and the reserve in year 0, cash " + "payback in year ~3.9, ~25 % IRR and an NPV of ~4.9M USD over ten years, pre-tax and " + "pre-financing (estimates). Not modelled here: cassette and CD-R lines (later in Plan A), stamper " + "supply to other plants, dropshipping fees, and the ramp year. BOI tax exemptions shield part of " + "early-year profits where there are any.", + ], [ + "**Demand comes first.** Plan B earns this only if the records sell: its central case needs ~1.25 " + "million records a year, ~0.75 million of them special editions, against 0.74 million for the " + "three-press Plan A. Nothing in the market data so far shows that demand (roadmap item 1, market " + "validation).", + "**The central case works on ~224M THB.** EBITDA ~3.1M USD (~104M THB) and operating profit ~2.6M " + "USD (~87M THB) a year once the plant runs at volume; it breaks even on operating profit at about " + "**0.22 million records a year, under a fifth of its central output**. Its central EBITDA is ~1.8 " + "times Plan A's for ~27 % more money. On the earlier ~20 % specials share the five-press table " + "showed EBITDA 2.59M at the same 1.25M records: five presses are not Duplex-limited, so more " + "specials raise the price on the same volume.", + "**The adverse case only just covers depreciation** (~1.0 million records needed, 1.0 million " + "made): more presses spread the same crews, overheads and title services over more records. It " + "stacks the low price, the high cost, the high capital and the high overheads at once. At the " + "central cost and volume the price that covers depreciation is ~2.4 USD (~79 THB) a record " + "(arithmetic on the table), below the low price assumed.", + "**The central margin is too good to trust yet.** A central EBITDA margin of ~52 % is far above " + "the 15 to 25 % pressing plants earn. The direct cost table counts only per-record consumables and " + "direct payroll and leaves out indirect labour (supervision, planning, warehouse), freight, scrap " + "above the reject allowance, sales commissions and the extra cost of specials. **Treat the adverse " + "column as the honest one until those lines exist.** The plan price carries no contingency either.", + "**This is a sensitivity, not a forecast.** The plant and business plan calculator's Plan B preset, " + "with its own cost build-up (it adds electric steam heat and the cutting engineer, which this " + "table leaves out), gives at 1.25M records and 60 % specials: revenue ~6.09M, EBITDA 3.25M USD, " + "payback 2.0 years on the 209.2M THB investment in a mature year; with a ramp of 35, 70 and 90 % in " + "the first three years and the reserve in year 0, cash payback in year ~3.3, ~32 % IRR and an NPV " + "of ~9.7M USD over ten years, pre-tax and pre-financing (estimates). Not modelled here: cassette " + "and CD-R lines, stamper supply to other plants, dropshipping fees, and the ramp year. BOI tax " + "exemptions shield part of early-year profits where there are any.", + ])), + IMG(pick("renders/calculator/plan-a-cash.png", "renders/calculator/plan-b-cash.png"), 160, + "Figure 6. Ten years of cash in the plant and business plan calculator, " + pick( + "Plan A preset: cash payback in year ~3.9, IRR ~25 %, NPV ~4.9M USD at 10 %", + "Plan B preset: cash payback in year ~3.3, IRR ~32 %, NPV ~9.7M USD at 10 %") + + ". Year 0 is the midpoint investment plus the ramp-up reserve; years 1 to 3 sell 35, 70 and 90 % of " + "the mature year's output. Pre-tax, pre-financing, no BOI tax holiday, no terminal value. The " + "calculator's own cost build-up and faster Duplex planning rate, not the table above " + "(docs/fleet-calculator.html); a sketch, not a forecast, estimates."), H2("9.5 The ramp"), - P("The table above is a mature year. The launch plant does not start there. It is commissioned in " - "sequence: first the cutting room and galvanics (the presses need their stampers), then the Duplex " - "system, then the Classic. Early production runs slower and rejects more than any of these figures " - "while the process settles, and the crews of a two-shift plant are on the payroll before the " - "volume is. The **ramp-up reserve of ~10M to 20M THB** (estimate, outside the investment total) is " - "there to carry staff hired before first revenue and overheads until volume covers them. Fan-funded " - "campaigns on the artist platform open only after the first releases have shipped and lead times " - "are measured."), + P(pick( + "The table above is a mature year. Plan A does not start there. It is commissioned in sequence: " + "first the cutting room and galvanics (the presses need their stampers), then the Duplex system, " + "then the Classic. Early production runs slower and rejects more than any of these figures while " + "the process settles, and the crews of a two-shift plant are on the payroll before the volume is. " + "The **ramp-up reserve of ~10M to 20M THB** (estimate, inside the plan price) is there to carry " + "staff hired before first revenue and overheads until volume covers them. Fan-funded campaigns on " + "the artist platform open only after the first releases have shipped and lead times are measured.", + "The table above is a mature year. Plan B does not start there. It is commissioned in sequence: " + "first the cutting room and galvanics (the presses need their stampers), then Duplex system 1, " + "the Classic, and Duplex system 2 last. Early production runs slower and rejects more than any of " + "these figures while the process settles, and the crews of a two-shift plant are on the payroll " + "before the volume is. **Plan B's ramp is longer**: it has to sell ~1.25 million records a year, " + "not 0.74 million, before it reaches the table above. The **ramp-up reserve is the same ~10M to " + "20M THB** estimate as for Plan A (inside the plan price); it carries staff hired before first " + "revenue and overheads until volume covers them, and with break-even at ~0.22 million records a " + "slower ramp costs payback time more than solvency (our reading). Fan-funded campaigns on the " + "artist platform open only after the first releases have shipped and lead times are measured.")), P("**A year-by-year cash model for the ramp is a next step, not a claim this plan makes.** It belongs " "to the financing discussion and needs the vendor build times and the commissioning calendar " - "(section 10) first."), - P("**The growth option.** A second Duplex system (two more semi-automatic presses) lifts the plant to " - "~1.0 to 1.5 million records a year, roughly **+0.3 to 0.5 million records**, for **~USD 230k to " - "300k** for the press system (estimate: two presses at the quoted ~115k per press and extruder set, " - "plus hydraulic unit and EX 35, no EX 35 price on file); its utility modules and installation come " - "on top. The hall, the module positions in the boiler hall and chiller compound, and the ring-main " - "tees are reserved for it, so it is a revenue-funded step, not a rebuild."), + "(section 10) first" + pick( + ". The calculator's 35, 70 and 90 % ramp in section 9.4 is a planning assumption, not that model.", + ". The calculator's 35, 70 and 90 % ramp in section 9.4 is a planning assumption, the same for " + "both plans, so it does not show Plan B's longer ramp.")), + P(pick( + "**The growth option.** A second Duplex system (two more semi-automatic presses) lifts the plant to " + "~1.0 to 1.5 million records a year at 60 % specials, roughly **+0.4 to 0.6 million records**, for " + "**~USD 230k to 300k** for the press system (estimate: two presses at the quoted ~115k per press " + "and extruder set, plus hydraulic unit and EX 35, no EX 35 price on file). With its chiller module " + "(CH-3, USD 48k to 78k), freight and installation (24k to 48k) and the working capital for the " + "extra records it comes to ~15.4M THB at the midpoint, as Plan B prices it. The hall, the module " + "positions in the boiler hall and chiller compound, and the ring-main tees are reserved for it, so " + "it is a revenue-funded step, not a rebuild.", + "**Growth beyond five presses.** The hall is laid out for five Duplex bays and four Classic " + "positions, and growth adds Duplex systems first, then Classics, from revenue. The boiler hall and " + "chiller compound are built for four modules each: Plan B fills two boiler and three chiller " + "positions, so a further press stage starts with the next module (scale and utility phasing in the " + "planning repository).")), # ----------------------------------------------- 10 timeline H1("10. Timeline: today to first paying release"), P("Every duration is an estimate. The calendar in the planning repository was drawn in August 2026 and " - "has not yet been re-drawn for the launch plant; nothing in phase 0 has started, so it shifts day " - "for day with the BOI consultant engagement. On that calendar, **first paying release lands around " - "Q4 2028 to mid-2029, roughly 27 to 33 months from the start of phase 0.** This plan quotes that " - "as the working figure, not as a re-based date (the executive summary marks it open), and flags " - "the new risk to it: the launch plant puts the metal path on the critical path."), + "has not yet been re-drawn for the launch plant" + pick("", " or for Plan B's second Duplex system") + + "; nothing in phase 0 has started, so it shifts day for day with the BOI consultant engagement. On " + "that calendar, **first paying release lands around Q4 2028 to mid-2029, roughly 27 to 33 months " + "from the start of phase 0.** This plan quotes that as the working figure, not as a re-based date " + "(the executive summary marks it open), and flags the new risk to it: the launch plant puts the " + "metal path on the critical path."), CALL("The critical path", [ "**BOI certificate → long-lead orders → vendor builds → sea freight → commissioning of the cutting " "room and galvanics → first stampers → press commissioning → test pressings → first paying " @@ -380,6 +868,10 @@ def blocks(): "and the Sibert machines have no lead time on file. Build time and order-book position are " "required fields in every re-quote; it is one line in each email and the highest-value missing " "fact in the project.", + *([] if a else [ + "**Plan B's second Duplex system is commissioned last**, after the Classic, so it is not on the " + "path to the first paying release. It lengthens commissioning and the ramp to full volume; its " + "build time, on top of the first system's at the same vendor, is not quoted yet."]), ]), T(["#", "Step", "Duration", "Source"], [ ["1", "Engage BOI consultant, prepare application", "4 to 5 months", "Estimate"], @@ -406,9 +898,14 @@ def blocks(): "~4 months", "Galvanics effluent and hazardous-substance registration are now in the first " "licence scope: the most likely regulatory friction point; ZLD design in the application from " "the start"], - ["Solar and battery (purchase or PPA)", "Fit-out, ~Q2 2028", "Large", "Not a risk; battery lead " - "time is 50 to 60 days"], - ["Cassette and CD-R lines", "Fit-out, ~Q2 2028", "Large", "Not a risk; short lead times"], + pick(["Solar through the PPA (the installer builds and owns the array)", "Fit-out, ~Q2 2028", + "Large", "Not a risk; the PPA offer is phase 0 work; battery lead time is 50 to 60 days"], + ["Solar and battery (purchase)", "Fit-out, ~Q2 2028", "Large", "Not a risk; battery lead time " + "is 50 to 60 days"]), + pick(["Cassette and CD-R lines", "Later (growth step)", "Not on the launch calendar", "Not a risk; " + "short lead " + "times"], + ["Cassette and CD-R lines", "Fit-out, ~Q2 2028", "Large", "Not a risk; short lead times"]), ["Hiring: galvanics process engineer and cutting engineer", "Before the metal path commissions", "**None: now on the critical path**", "Galvanics is the hardest skill to hire; both people must " "be hired and trained (at the vendors) before step 6a"], @@ -418,9 +915,11 @@ def blocks(): P("**BOI windows are comfortable** on the August calendar: machinery clears customs ~Q3 2028 against a " "30-month import window ending ~Q4 2029 (~15 months of margin), and first production ~Q4 2028 " "against a ~36-month full-operation deadline (~18 months). The launch plant puts four vendors' " - "machines, not one, inside the import window. The margin is consumed by exactly one scenario: " - "filing early to start the clock and then discovering the site does not work. Verify zoning before " - "filing."), + "machines, not one, inside the import window" + pick( + ", and Plan A adds the Chinese boiler modules. ", + ", and Plan B's second Duplex system has to clear customs inside it too. ") + + "The margin is consumed by exactly one scenario: filing early to start the clock and then discovering " + "the site does not work. Verify zoning before filing."), P("**The one lever worth six to nine months** is the BOI sequencing question in section 7: the duty " "exemption attaches at importation, not at contract signature, so if an order and deposit can be " "placed while the application is in review, the press build overlaps the BOI process. It is a " @@ -437,30 +936,45 @@ def blocks(): "phased entry, in which galvanics, cutting and the automatic press followed from revenue. The " "gates have not moved: no machinery order before the BOI certificate, no large spending before the " "market validates the price, no coppice planning before the land-title check. What changed is " - "that the round, once released, buys the full launch plant, and only growth stays revenue-gated."), + "that the round, once released, buys " + pick( + "Plan A's plant, the launch plant with its six levers, and only growth and the items the levers " + "move later stay revenue-gated.", + "Plan B's five presses with everything in, and only further growth stays revenue-gated.")), T(["Phase", "Content", "Gate"], [ - ["0. Validate and clear the gates (now)", "Market validation with regional labels and distributors; " - "BOI consultant, activity code, application; lease terms, zoning, soil test; 60 rai title check; " - "re-quotes and quotes from every launch vendor (section 14.1)", "Runs in parallel; gates " - "everything"], + ["0. Validate and clear the gates (now)", "Market validation with regional labels and distributors" + + pick("", ", including the demand for ~1.25M records a year") + "; BOI consultant, activity code, " + "application; lease terms, zoning, soil test; 60 rai title check; re-quotes and quotes from every " + "launch vendor (section 14.1)", "Runs in parallel; gates everything"], ["1. Quotes and site (during the BOI window)", "Firm quotes with build times; site selection " "between the Mueang Chi lease, other Payap land and the industrial estate; resolve the 35 % vs " "45 % humidity floor", "BOI filed"], ["2. Commit", "Incorporate under the certificate; sign the lease; order every long-lead item: " - "Pheenix galvanics line, Sillitoe lathe, Sibert line, Newbilt Duplex and Classic, first two " - "boiler and chiller modules", "BOI certificate and validated pricing"], - ["3. Build and commission (~6 to 12 months after commitment)", "Construction, water-treatment " - "building, utilities, HVAC, clean zones, solar, security, crane; machinery installation and " - "vendor commissioning; traceability and ERPNext live before the machines; hire and train", + "Pheenix galvanics line, Sillitoe lathe, Sibert line, " + pick( + "Newbilt Duplex and Classic, first two boiler and chiller modules (boilers through the Chinese " + "route)", + "both Newbilt Duplex systems and the Classic, the boiler modules and the first chiller " + "modules"), pick("BOI certificate and validated pricing", + "BOI certificate, validated pricing and demand")], + ["3. Build and commission (~6 to 12 months after commitment)", pick( + "Construction, water-treatment building, utilities, HVAC, clean zones, security, the " + "crane-ready frame (a mobile crane for the installations); the solar array built by the PPA " + "installer; machinery installation and vendor commissioning; traceability and ERPNext live " + "before the machines; hire and train", + "Construction, water-treatment building, utilities, HVAC, clean zones, solar and battery, " + "security, crane, visitor corridor; machinery installation and vendor commissioning; " + "traceability and ERPNext live before the machines; hire and train"), "Building permit, vendor build dates confirmed"], ["4. Launch (the whole chain in-house)", "Commission in sequence (table below); test pressings, QC " "baselines, reject shakedown; first paying releases; per-lot PVC gate live; qualify Thai " "compound", "Commissioning complete"], - ["5. Expand (revenue-gated)", "Second Duplex system; further Classics; the metrology parts bought " - "from revenue if that lever is used; the visitor corridor if built later; the biomass boiler if " - "steam starts electric; the phase 2 building; CD replication if chosen", "Revenue and, for CD " - "replication, a separate " - "decision"], + ["5. Expand (revenue-gated)", pick( + "Second Duplex system; further Classics; the laser confocal and wide-area profiler; the visitor " + "corridor and public tours; cassette and CD-R duplication; an owned crane if needed; the " + "biomass boiler if steam starts electric; the phase 2 building; CD replication if chosen", + "Further Duplex systems first, then Classics (the hall is laid out for five Duplex bays and " + "four Classic positions); the biomass boiler if steam starts electric; the phase 2 building; " + "CD replication if chosen"), + "Revenue and, for CD replication, a separate decision"], ], widths_mm=[42, 96, 32], font_pt=8.5), H2("11.1 Commissioning sequence"), T(["Step", "What is commissioned", "Why in this order"], [ @@ -468,13 +982,18 @@ def blocks(): "Sibert stamper-prep line", "The presses need their stampers; no bridge stampers are planned. " "First lacquers, fathers, mothers and stampers, and the metal archive " "from the first title"], - ["2", "Newbilt Duplex system (two HRP 12, EX 50 and EX 35), with the steam and cooling plant " - "(boiler modules B-1, B-2; chiller modules CH-1, CH-2)", "The semi-automatic presses suit the " - "colour, splatter and boutique runs " - "that carry the premiums, and they " - "teach the crews the process"], + ["2", pick("Newbilt Duplex system (two HRP 12, EX 50 and EX 35), with the steam and cooling plant " + "(boiler modules B-1, B-2; chiller modules CH-1, CH-2)", + "Newbilt Duplex system 1 (two HRP 12, EX 50 and EX 35), with the steam and cooling plant " + "(boiler modules B-1, B-2; chiller modules CH-1, CH-2)"), + "The semi-automatic presses suit the colour, splatter and boutique runs that carry the premiums, " + "and they teach the crews the process"], ["3", "Newbilt Classic, fully automatic", "Volume runs once the metal path and the press process " "are stable"], + *([] if a else [ + ["4", "Newbilt Duplex system 2 (two HRP 12, EX 50 and EX 35), with chiller module CH-3; steam " + "from B-1 and B-2", "The crews know the process from system 1; it carries the specials " + "volume that the central case needs"]]), ], widths_mm=[12, 78, 80]), P("If commissioning of the metal path slips, Stamper Discs (stampers) and SST in Frankfurt (lacquer " "cutting, already Poy Records' cutter) stay contacts for overflow and for a slipping commissioning, " @@ -504,14 +1023,29 @@ def blocks(): "the start, and on Payap land the lessor's consent as well."], ["**The cutting room is a smaller decision than it was.** The Sillitoe SDMS lists at USD 125k with " "automation in the box, and the Payap programmes in mastering and lathe cutting need a working " - "room.", "**More capital up front.** ~161M to 292M THB in one round, against ~57M to 95M THB for " - "the superseded phased entry; more of it is committed before the market has validated " - "the price."], + "room.", pick("**More capital up front.** ~127M to 226M THB in one round (~177M at the " + "midpoint), against ~57M to 95M THB for the superseded phased entry; more of it is " + "committed before the market has validated the price.", + "**More capital up front.** ~162M to 286M THB in one round (~224M at the midpoint), " + "against ~57M to 95M THB for the superseded phased entry; more of it is committed " + "before the market has validated the price.")], + pick(["**Six levers, no machine dropped.** The levers bring the whole chain to ~180M THB, and the " + "second Duplex waits for demand and revenue on a reserved floor.", + "**What the levers give up.** Owned solar and very likely the BOI solar measure, public tours " + "at first, cassette and CD-R at launch, a bought crane; the boilers are imported from China " + "under the Thai boiler rules. The adverse case still loses money."], + ["**Five presses at launch.** The same crews, overheads and title services spread over ~1.25 " + "million records: central EBITDA ~1.8 times the three-press plant's for ~27 % more money, " + "and the adverse case covers its depreciation.", + "**Demand is unproven.** The central case needs ~1.25 million records sold a year, ~0.75 " + "million of them specials; nothing in the market data shows that yet, and the ramp to it is " + "longer."]), ], widths_mm=[85, 85], font_pt=8.5), P("**How the plan answers the risks:** commission the metal path first and measure it before the " "presses depend on it; hire the galvanics and cutting engineers early and train them at the " "vendors; design zero discharge from the start; and release the round in tranches (section 8.3), " - "so that nothing is ordered before the BOI certificate and validated pricing."), + "so that nothing is ordered before the BOI certificate and validated pricing" + pick( + ".", " and demand; the second Duplex system is commissioned last.")), # --------------------------------------- 12 team, ownership, governance H1("12. Team, ownership and governance"), @@ -538,12 +1072,14 @@ def blocks(): "(GBP 10k to 20k packages); vendor commissioning and training (Newbilt, Pheenix, Sibert, " "Sillitoe); property insurer."], ], widths_mm=[48, 122]), - P("Headcount: the launch plant runs the whole chain on two shifts, so it needs most of the mature crew " - "from the start: a direct production payroll of 13 to 19 (8 to 12 press and finishing operators, 2 " - "to 3 galvanics, 1 to 2 QC, 2 maintenance), 1 to 2 mastering and cutting engineers, and 3 to 5 in " - "admin, sales and logistics. The revenue model plans on about 20 people at the start (estimate), " - "plus 1 to 2 for the cassette and CD-R lines. A process engineer from abroad can be employed on a " - "BOI work permit (section 7)."), + P("Headcount: the plant runs the whole chain on two shifts, so it needs most of the mature crew from " + "the start: a direct production payroll of 13 to 19 (8 to 12 press and finishing operators, 2 to 3 " + "galvanics, 1 to 2 QC, 2 maintenance), 1 to 2 mastering and cutting engineers, and 3 to 5 in admin, " + "sales and logistics. The revenue model plans on about 20 people at the start (estimate), " + pick( + "and the cassette and CD-R lines add 1 to 2 when they come.", + "plus 1 to 2 for the cassette and CD-R lines; it built that direct crew for the five-press " + "fleet.") + + " A process engineer from abroad can be employed on a BOI work permit (section 7)."), H2("12.2 Ownership and structure"), P("Amounts and percentages are not yet agreed and are deliberately left open here. The intended " "structure is:"), @@ -556,11 +1092,13 @@ def blocks(): "capital in packaging) or both, is to be discussed; its strategic value is a packaging partner " "whose incentives are aligned with the plant's schedule and quality, within the same province.", "**Debt-to-equity no higher than 3:1**, maintained for the life of the BOI privileges, which sets " - "the floor on equity in the financing mix: at least a quarter of the funding, ~54M THB on the " - "216M target (arithmetic, before financing costs).", + "the floor on equity in the financing mix: at least a quarter of the funding, " + pick( + "~44M THB of Plan A's ~177M", "~56M THB of Plan B's ~224M") + + " (arithmetic, before financing costs).", "**A shareholders' agreement** covering board composition, reserved matters (capital calls and " - "tranche releases, the growth options such as a second Duplex, CD replication), pre-emption and " - "transfer, information rights, and the founders' roles and remuneration.", + "tranche releases, the growth options such as " + pick("a second Duplex", "further Duplex systems") + + ", CD replication), pre-emption and transfer, information rights, and the founders' roles and " + "remuneration.", "**Related-party discipline.** Ploy Printing will be both a shareholder and the plant's main " "packaging supplier. The supply agreement is priced at arm's length, benchmarked periodically " "against other printers, with quality and lead-time terms written down, and Ploy Printing abstains " @@ -574,92 +1112,11 @@ def blocks(): H1("13. Risks and open questions"), P("Every plan has risks; the point of listing them is to say which are being retired, by what, and " "when. The first column is the plan's own honest severity. The September draft's bridge-stamper " - "risk is gone with the bridge stampers; the launch plant brings its own in its place."), - T(["Severity", "Risk", "What it would do", "Mitigation and status"], [ - ["High", "Pricing power in the region is unproven", "The single biggest assumption in the revenue " - "model; a turnaround advantage nobody pays a premium for is a cost, not a moat", "Market " - "validation gate: regional label conversations, the artist platform's calculator as an interest " - "list, a second Thai data point; no large spending before it clears"], - ["High", "Utilisation and price", "The cost structure is mostly fixed; the adverse case loses " - "money even at the full volume of three presses (it needs ~1.1M records to cover depreciation); " - "at 60 % specials the Duplex rate and the extra cost of specials decide volume and margin", - "Central breaks even at ~0.25M records; commission in sequence; growth options wait for demand; " - "treat the adverse column as the honest one"], - ["High", "Galvanics and cutting on the critical path", "No paying release until the cutting room " - "and galvanics make good stampers; a slow start there delays every press", "Commission the " - "metal path first and measure it; vendor training; Stamper Discs and SST as contacts for a " - "slipping commissioning, not a plan"], - ["High", "Skills: galvanics process engineer, cutting engineer", "Galvanics is the hardest skill to " - "hire; both roles are now needed at launch", "Recruit or train abroad; BOI work permits; vendor " - "training (Pheenix, Sillitoe, OMS as a reference); Payap programmes as a longer-term pipeline"], - ["High", "Missing prices: Classic and Pheenix line", "Two of the largest machine lines have no " - "vendor price; the Classic band is a placeholder", "Newbilt re-quote and Pheenix quote in phase " - "0; OMS's reference prices as the galvanics " - "benchmark"], - ["High", "Budget fit against 216M THB", "Midpoint ~227M is ~11M over; the high end is ~292M", - "Four levers bring the midpoint to ~203M to 213M with the reserve; four requests settle most of " - "the band; tranche release"], - ["High", "Vendor build times unknown", "The press build carries ~40 % of the schedule; 15 to 18 " - "months would push launch to mid-2029; Pheenix, Sillitoe and Sibert lead times also unquoted", - "Required field in every re-quote, now"], - ["High", "Zoning of the chosen plot unverified", "A site reset costs ~6 months; the Payap point " - "already fails zoning; Mueang Chi is unverified", "Verify on the land-use map and with counsel " - "before the BOI filing; industrial estate as " - "fallback"], - ["Medium", "Lease terms and building ownership", "A weak lease makes the building hard to finance " - "and exposes it at expiry", "Registered 30 to 50 year lease with renewal, explicit building " - "ownership and assignment rights; Thai counsel in phase 0"], - ["Medium", "Soil conditions", "Piling could add several hundred to 1,000+ THB/m² across building, " - "paving and fill", "Soil boring test in phase 0 (THB 30k to 50k)"], - ["Medium", "Galvanics permitting", "Effluent and hazardous-substance permitting are the most likely " - "regulatory friction, now in the first factory licence", "Zero-discharge design and the " - "water-treatment building from the " - "start; industrial estate option; " - "lessor's consent on Payap land"], - ["Medium", "Utilities fuel choice open", "Biomass heat costs a quarter to a tenth of electric steam " - "at reported fuel prices; electric steam needs a larger grid connection, biomass a secured fuel " - "supply", "Decide before the boiler request and the grid application; quote electric and fired " - "variants of the same modules"], - ["Medium", "Boiler import compliance (DIW)", "An imported boiler must meet ASME, JIS, EN or " - "equivalent and be verified by a DIW-registered certification body; the modules run above the " - "once-through relief", "ASME Section I design with the S stamp and the full dossier; " - "certification body engaged before the order; the same for a Thai-bought " - "boiler"], - ["Medium", "Single press vendor (Newbilt)", "All three presses, the extruders and the hydraulic " - "aggregates come from one small German manufacturer; build time and order book unknown", "Spares " - "and service terms in the re-quote; the Pheenix automatic press stays the comparison if the " - "Classic quote disappoints"], - ["Medium", "Hydraulic ring-main contamination", "One shared oil system: a contamination event " - "reaches every press", "ISO 4406 target, flushing to ISO 23309, particle counts at acceptance " - "and after flushing, non-bypass branch filters, isolation per press, online particle counter, " - "kidney loop; central plant still to be quoted"], - ["Medium", "Currency", "EUR on Newbilt and Pheenix, USD on Sibert and Sillitoe, THB costs, USD/EUR " - "revenue; a 10 % baht move is worth 0.09 to 0.17 USD per record on margin", "Currency and " - "validity in every " - "quote; THB pricing " - "regionally; hedging " - "decision with the " - "investor"], - ["Medium", "Vinyl demand is cyclical", "Global capacity has been added; the model assumes the plant " - "sells what it presses", "Mixed fleet suits boutique work that is less cyclical; cassette and " - "CD-R lines diversify; growth options wait for demand"], - ["Medium", "Reject rate in early production", "Early runs, and the first stampers from a new " - "galvanics room, will be worse than the 5 to 10 % allowance while the process settles", "Vendor " - "commissioning, stamper metrology, materials lab from day one, QC layers, conservative launch " - "promises; the ramp-up reserve"], - ["Medium", "Competitive response", "The incumbent may add plating, or a second entrant may appear; " - "the domestic price ceiling may compress on our arrival", "Compete on capability (traceability, " - "QC, climate), export customers, and " - "the collaboration under discussion"], - ["Low", "Solar and battery integration", "Rack voltage vs inverter window; unpublished " - "certifications; mixed-vendor warranty", "Engineering checks and certificate requests in phase " - "0, or a PPA that moves it to the installer; large float"], - ["Low", "Cassette supply chain", "Blank tape and shells come from few suppliers", "Hold stock; " - "qualify two " - "sources"], - ["Low", "CD replication scope creep", "Adds USD 1.5M to 4.0M and a second commissioning programme", - "Decide before BOI filing; treat as a separate project if chosen"], - ], widths_mm=[16, 40, 52, 62], font_pt=8), + "risk is gone with the bridge stampers; the launch plant brings its own in its place" + pick( + ", and Plan A's levers and its price without contingency add theirs.", + ", and Plan B's five presses and its price without contingency add theirs.")), + T(["Severity", "Risk", "What it would do", "Mitigation and status"], _risk_rows(), + widths_mm=[16, 40, 52, 62], font_pt=8), P("**Open questions with owners** are in the next section. Two standing caveats on the evidence base: " "the Thai market data is one buyer, one plant and one afternoon, and the underlying invoices and " "tour notes should be archived with this plan before it goes in front of a bank; and the industry " @@ -670,40 +1127,57 @@ def blocks(): H1("14. Next steps and the ask"), H2("14.1 Phase 0: the next three to six months"), T(["#", "Action", "Owner", "Cost", "Retires"], [ - ["1", "Market validation with regional labels and distributors: the 3.50 to 4.60 USD blended " - "price, run sizes, and whether faster turnaround earns a premium; publish the artist platform's " - "calculator early with indicative prices and an interest list", "Simona, Alexander", "Travel", - "Pricing risk"], + ["1", "Market validation with regional labels and distributors: the 3.76 to 5.27 USD blended " + "price at 60 % specials, run sizes, and whether faster turnaround earns a premium" + pick( + "", "; and whether demand reaches ~1.25 million records a year, three fifths of them " + "specials") + "; publish the artist platform's calculator early with indicative prices " + "and an interest list", "Simona, Alexander", "Travel", pick("Pricing risk", "Pricing and demand " + "risk")], ["2", "Engage a BOI-registered consultant: activity sub-code; the order-before-certificate question " - "first; galvanics, cassette and CD-R in the application; CD replication decision; whether a solar " - "PPA affects the solar measure; Payap R&D", "Simona", "USD 5k to 15k", "Sequencing, scope"], + "first; galvanics, cassette and CD-R in the application; CD replication decision; " + pick( + "how the solar PPA affects the solar measure; ", "") + "Payap R&D", "Simona", "USD 5k to 15k", + "Sequencing, scope"], ["3", "Thai counsel: lease heads of terms (term, renewal, building ownership, assignment) and zoning " "of the chosen plot for pressing, a steam boiler and electroplating; company and shareholder " "structure including Ploy Printing", "Simona, counsel", "USD 5k to 15k", "Zoning, lease, " "ownership"], ["4", "Soil boring test on the chosen plot", "Alexander", "THB 30k to 50k", "Ground risk"], - ["5", "Newbilt re-quote: Duplex (EX 50 and EX 35) and Classic, with build time, order-book " - "position, PLC data access, central hydraulic supply and written hydraulic requirements, currency " - "and validity", "Alexander", "Free", "Classic price, schedule"], + ["5", "Newbilt re-quote: " + pick("Duplex (EX 50 and EX 35)", "two Duplex systems (EX 50 and EX 35 " + "each)") + + " and Classic, with build time, order-book position, PLC data access, central hydraulic supply " + "and written hydraulic requirements, currency and validity", "Alexander", "Free", + "Classic and EX 35 price, schedule"], ["6", "Pheenix quote for the galvanics line (PASU, PPPU, PDPU, PMPB) with lead time and training; " "OMS dedicated offer as the reference; ZLD and DI water vendor", "Alexander", "Free", - "Largest unpriced block"], + "Galvanics priced on a reference only"], ["7", "Sillitoe quote and build time (SDMS, spare cutterhead, support terms, DMM question)", "Alexander", "Free", "Cutting room, schedule"], ["8", "Sibert itemised quotation and order terms against the USD 250k budget: lead time, " "installation time, spares, shipping, travel", "Alexander", "Free", "Stamper prep, schedule"], ["9", "Building request for quotation to two or three Thai pre-engineered building contractors, " "with the soil result", "Alexander", "Free", "Building estimate"], - ["10", "Utility requests: Thai suppliers; Chinese boiler makers (ZOZEN, Sitong, Fangkuai, Taiguo; " - "1.25 MPa, ASME S stamp, electric and fired variants); compressors from Kaishan and Denair's Thai " - "offices; chillers and HVAC, Chinese makers included; the 35 % vs 45 % humidity floor; a Thai " - "hydraulic builder for the central plant", "Alexander", "Free", "Utilities band, fuel choice"], - ["11", "Metrology distributor quotes (XRF, confocal, profiler, inline vision, audio station)", - "Alexander", "Free", "Metrology band"], - ["12", "Solar PPA offers next to the purchase quote; battery and inverter engineering checks", - "Alexander", "Free", "Solar lever"], - ["13", "Cassette and CD-R equipment quotes from two vendors each; tape and shell supply", - "Alexander", "Free", "New-scope estimates"], + ["10", pick( + "Utility requests: Chinese boiler makers for the plan's boiler modules (ZOZEN, Sitong, Fangkuai, " + "Taiguo; 1.25 MPa, ASME S stamp, electric and fired variants) with a Thai installer; compressors " + "from Kaishan and Denair's Thai offices; Thai suppliers for the rest; chillers and HVAC, Chinese " + "makers included; the 35 % vs 45 % humidity floor; a Thai hydraulic builder for the central " + "plant", + "Utility requests: Thai suppliers; Chinese boiler makers (ZOZEN, Sitong, Fangkuai, Taiguo; " + "1.25 MPa, ASME S stamp, electric and fired variants) and compressors from Kaishan and Denair's " + "Thai offices for comparison; chillers and HVAC, Chinese makers included; the 35 % vs 45 % " + "humidity floor; a Thai hydraulic builder for the central plant"), + "Alexander", "Free", "Utilities band, fuel choice"], + ["11", pick("Metrology distributor quotes (XRF, inline vision, audio station; confocal and profiler " + "for later)", "Metrology distributor quotes (XRF, confocal, profiler, inline vision, " + "audio station)"), "Alexander", "Free", "Metrology band"], + ["12", pick("Solar PPA offers (the plan's lever) next to a purchase quote; the installer's battery " + "and inverter design checked", "Solar and battery purchase quotes, with a PPA offer for " + "comparison; battery and inverter engineering " + "checks"), "Alexander", "Free", + pick("Solar lever, PPA price", "Solar block")], + ["13", pick("Cassette and CD-R equipment quotes from two vendors each, for the growth step; tape and " + "shell supply", "Cassette and CD-R equipment quotes from two vendors each; tape and " + "shell supply"), "Alexander", "Free", "New-scope estimates"], ["14", "Search for the galvanics process engineer and the cutting engineer; next meeting with Payap " "on the programmes", "Simona, Alexander", "None yet", "Skills risk"], ["15", "60 rai title check for the coppice plan", "Simona", "Small", "Biomass path"], @@ -713,30 +1187,53 @@ def blocks(): ], widths_mm=[8, 84, 26, 24, 28], font_pt=8), H2("14.2 What the investor is asked for"), KV([ - ["Now", "Approval of Phase 0 spending of ~USD 40k to 80k (~1.3M to 2.6M THB, part of the launch-plant " - "total), so the quotes, the soil test, the BOI consultant and counsel can start."], - ["On the gates clearing", "A commitment in principle to the launch plant at a **target of ~216M " - "THB**, released in the tranches of section 8.3, with the financing mix " - "set to hold debt-to-equity at or below 3:1. Told plainly: at the " - "midpoint, 216M holds with the four levers and the ramp-up reserve " - "inside it; 180M holds only if the open quotes land low, because even " - "the levers plus scope cuts (cassette and CD-R later, a rented crane) " - "leave ~185M before the reserve. Until the four requests are back, the " - "honest range is ~161M to 292M THB."], - ["Decisions", "The equity and debt mix; CD replication, yes or no, before the BOI application is " - "finalised; the steam fuel (electric or biomass); which levers to take (solar PPA, " - "metrology launch tier, visitor corridor later); the shareholder structure with Ploy " - "Printing and the founders; hedging of the EUR orders."], - ["Later", "Revenue-funded growth: the second Duplex system (~USD 230k to 300k for the presses, " - "estimate), further Classics, the rest of the metrology stack, the biomass boiler if " - "steam starts electric, and the phase 2 building."], + ["Now", "Approval of Phase 0 spending of ~USD 40k to 80k (~1.3M to 2.6M THB, part of the plan " + "price), so the quotes, the soil test, the BOI consultant and counsel can start."], + ["On the gates clearing", pick( + "A commitment in principle to **Plan A at ~180M THB** (~177M at the midpoint, the ramp-up " + "reserve of 10M to 20M included, no contingency), released in the tranches of section 8.3, " + "with the financing mix set to hold debt-to-equity at or below 3:1 (equity of at least ~44M " + "THB). Told plainly: the price carries no contingency (at 15 % it would be ~24M THB more at " + "the midpoint), and from the low to the high end of every block the plan comes to ~127M to " + "226M THB. The Newbilt re-quote, the Pheenix quote, the building quote with the soil test, " + "the metrology quotes and the solar PPA offer decide where in that range it lands.", + "A commitment in principle to **Plan B at ~225M THB** (~224M at the midpoint, the ramp-up " + "reserve of 10M to 20M included, no contingency), released in the tranches of section 8.3, " + "with the financing mix set to hold debt-to-equity at or below 3:1 (equity of at least ~56M " + "THB). Told plainly: the price carries no contingency (at 15 % it would be ~31M THB more at " + "the midpoint), and from the low to the high end of every block the plan comes to ~162M to " + "286M THB. Market validation of the demand for ~1.25 million records a year comes first; " + "then the Newbilt re-quote (two Duplex systems with the EX 35, the Classic), the Pheenix " + "quote, the building quote with the soil test and the metrology quotes decide where in that " + "range it lands.")], + ["Decisions", pick( + "The equity and debt mix, and how quotes landing above the plan price are funded; the six " + "levers, the solar PPA first (it very likely gives up the BOI solar measure); CD replication, " + "yes or no, before the BOI application is finalised; the steam fuel (electric or biomass); " + "the shareholder structure with Ploy Printing and the founders; hedging of the EUR orders.", + "The equity and debt mix, and how quotes landing above the plan price are funded; five " + "presses at launch against the market validation (the second Duplex system is commissioned " + "last and can still return to a growth step); CD replication, yes or no, before the BOI " + "application is finalised; the steam fuel (electric or biomass); the shareholder structure " + "with Ploy Printing and the founders; hedging of the EUR orders.")], + ["Later", pick( + "Revenue-funded growth: the second Duplex system (~USD 230k to 300k for the press system; " + "~15.4M THB at the midpoint with its chiller module, freight and working capital, as Plan B " + "prices it), the laser confocal and wide-area profiler (USD 180k to 350k), the visitor " + "corridor, cassette and CD-R, an owned crane if needed, further Classics, the biomass boiler " + "if steam starts electric, and the phase 2 building.", + "Revenue-funded growth: further Duplex systems first, then Classics, in the hall laid out for " + "five Duplex bays and four Classic positions; the biomass boiler if steam starts electric; " + "and the phase 2 building.")], ], widths_mm=[38, 132]), P("The next version of this plan should carry: the Newbilt, Pheenix, Sillitoe and Sibert quotes with " "their build times in place of the placeholder and estimated blocks; the building quote with the " - "soil result; the negotiated lease; a buyer-side price data point; the investor's CD and fuel " - "decisions; a calendar re-drawn for the launch plant with the metal-path commissioning in it; a " - "year-by-year cash model for the ramp; and the shareholder terms. Each of those is a phase 0 " - "output."), + "soil result; " + pick("the solar PPA offer and the BOI consultant's reading of the solar measure; ", + "market evidence for the 1.25 million records a year; ") + + "the negotiated lease; a buyer-side price data point; the investor's CD and fuel decisions; how " + "overruns are funded, since the price carries no contingency; a calendar re-drawn for the launch " + "plant with the metal-path commissioning in it; a year-by-year cash model for the ramp; and the " + "shareholder terms. Each of those is a phase 0 output."), # --------------------------------------------------- 15 appendix H1("15. Appendix: sources and planning documents"), @@ -751,23 +1248,27 @@ def blocks(): ["scale.md", "Project sizing on one page: capacity per fleet, building zones, electrical, solar, " "steam and cooling, utility phasing, people"], ["finance/total-investment.md", "The launch-plant roll-up (October 2026) with the basis of every " - "block, the investor's 180M THB question and the levers; the " - "superseded full vision and phased entry"], + "block; 'Two plans': Plan A at ~180M and Plan B at ~225M THB, " + "the six levers, Plan B's additions and what is not in either " + "price; the superseded investor answer, full vision and phased " + "entry"], ["finance/revenue-model.md", "Pricing, the Thai market data and factory tour, the Record Industry " - "benchmark, direct cost, the launch-plant operating picture"], + "benchmark, direct cost, the launch-plant operating picture and the " + "operating pictures of Plan A and Plan B"], ["finance/utilities-investment.csv", "Thai supplier candidates and budgetary ranges for steam, " "cooling, air, water, HVAC, solar and battery"], ["finance/phase1-construction-rfq.md", "Contractor price request with quantities from the " "parametric model"], - ["fleet-calculator.html", "Press fleet calculator: target output and specials share to the " - "Duplex/Classic mix, people, utilities and the operating picture"], + ["fleet-calculator.html", "Plant and business plan calculator: target output and specials share to " + "the Duplex/Classic mix, people, utilities, investment and the operating " + "picture, with the Plan A and Plan B presets"], ["equipment/pressing-line.md and equipment/newbilt/", "Press fleet strategy, hydraulic ring mains; " "Newbilt offer, site requirements, service " "rates, 2026 product flyers"], ["equipment/galvanics.md (with pheenix-alpha/, sibert/, oms/)", "Pheenix electroforming line, " "Sibert stamper prep, OMS reference " - "prices, cycle times, the metal " - "archive"], + "prices (the Pheenix price basis), " + "cycle times, the metal archive"], ["suppliers/vendor-landscape.md, equipment-suppliers.md", "Per-vendor narrative (lathes, cutting " "services) and the full needs list with " "contacts"], diff --git a/docs/business-plan/build/export_pdf.py b/docs/business-plan/build/export_pdf.py index b9c8d7a..b0fc99d 100644 --- a/docs/business-plan/build/export_pdf.py +++ b/docs/business-plan/build/export_pdf.py @@ -1,5 +1,5 @@ -"""Export CNX-Vinyl-Business-Plan.docx to PDF with LibreOffice, filling in the table of contents. +"""Export CNX-Vinyl-Business-Plan-A.docx and -B.docx to PDF with LibreOffice, filling in the table of contents. Run with LibreOffice's own Python (it ships the uno module): "C:/Program Files/LibreOffice/program/python.exe" export_pdf.py @@ -8,8 +8,8 @@ A plain `soffice --convert-to pdf` leaves the Word TOC field unfilled. import uno, sys, time, subprocess, os from pathlib import Path HERE = Path(__file__).resolve().parent -DOCX = HERE.parent / "CNX-Vinyl-Business-Plan.docx" -PDF = HERE.parent / "CNX-Vinyl-Business-Plan.pdf" +DOCXS = [HERE.parent / f"CNX-Vinyl-Business-Plan-{p}.docx" for p in ("A", "B")] +DOCXS = [d for d in DOCXS if d.exists()] from com.sun.star.beans import PropertyValue def pv(n, v): p = PropertyValue(); p.Name = n; p.Value = v; return p @@ -24,20 +24,22 @@ for i in range(60): time.sleep(0.5) smgr = ctx.ServiceManager desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx) -src = uno.systemPathToFileUrl(str(DOCX)) -doc = desktop.loadComponentFromURL(src, "_blank", 0, (pv("Hidden", True),)) -idx = doc.getDocumentIndexes() -print("indexes", idx.getCount()) -for i in range(idx.getCount()): - idx.getByIndex(i).update() -doc.refresh() -# update fields (page numbers) -doc.getTextFields().refresh() -for i in range(idx.getCount()): - idx.getByIndex(i).update() -out = uno.systemPathToFileUrl(str(PDF)) -doc.storeToURL(out, (pv("FilterName", "writer_pdf_Export"),)) -doc.close(True) +for DOCX in DOCXS: + PDF = DOCX.with_suffix(".pdf") + src = uno.systemPathToFileUrl(str(DOCX)) + doc = desktop.loadComponentFromURL(src, "_blank", 0, (pv("Hidden", True),)) + idx = doc.getDocumentIndexes() + print(DOCX.name, "indexes", idx.getCount()) + for i in range(idx.getCount()): + idx.getByIndex(i).update() + doc.refresh() + # update fields (page numbers) + doc.getTextFields().refresh() + for i in range(idx.getCount()): + idx.getByIndex(i).update() + out = uno.systemPathToFileUrl(str(PDF)) + doc.storeToURL(out, (pv("FilterName", "writer_pdf_Export"),)) + doc.close(True) try: desktop.terminate() except Exception: diff --git a/docs/business-plan/build/plan_variant.py b/docs/business-plan/build/plan_variant.py new file mode 100644 index 0000000..ff9267f --- /dev/null +++ b/docs/business-plan/build/plan_variant.py @@ -0,0 +1,36 @@ +"""Which version of the business plan is being built (October 2026). + +Plan A, ~180M THB: the launch plant (1 Duplex system + 1 Classic, every machine) with six cost levers. +Plan B, ~225M THB: five presses (the second Duplex system at launch), everything in. +Both are priced without contingency and with the ramp-up reserve +(docs/finance/total-investment.md, "Two plans"). + +build_plan.py sets PLAN before it calls the content modules' blocks(); call pick() and the +helpers inside blocks(), never at import time. +""" +PLAN = "A" + +NAME = {"A": "Plan A", "B": "Plan B"} +PRICE = {"A": "~180M THB", "B": "~225M THB"} + + +def is_a() -> bool: + return PLAN == "A" + + +def is_b() -> bool: + return PLAN == "B" + + +def pick(a, b): + """The Plan A or the Plan B variant of a value, text or list of blocks.""" + return a if PLAN == "A" else b + + +def name() -> str: + return NAME[PLAN] + + +def label() -> str: + """e.g. 'Plan A (~180M THB)'.""" + return f"{NAME[PLAN]} ({PRICE[PLAN]})" diff --git a/docs/fleet-calculator.html b/docs/fleet-calculator.html index 2933f0b..7175deb 100644 --- a/docs/fleet-calculator.html +++ b/docs/fleet-calculator.html @@ -3743,14 +3743,15 @@ function renderBudget(e) { `
against ${M(B1)}: ${gap(tot, B1)} · against ${M(B2)}: ${gap(tot, B2)}
`; }).join(""); const mid = V[1], mt = mid.cap + mid.res, rLo = cx.res.lo * fx, rHi = cx.res.hi * fx; + const tgt = mt <= B1 ? B1 : B2; // the tightest budget the midpoint fits (Plan A: 180M, Plan B: 225M) $("budK").innerHTML = kpi(M(mid.cap) + " THB", `investment at the midpoint, ${cx.ctgIn ? "contingency included" : "without contingency"}`) + kpi(`${M(mid.cap + rLo)} to ${M(mid.cap + rHi)}`, `THB with the ramp-up reserve (${M(rLo)} to ${M(rHi)})`) + - kpi(mt <= B2 ? M(B2 - mt) : "+" + M(mt - B2), `${mt <= B2 ? "to spare under" : "over"} ${M(B2)} THB at the midpoint${inB ? ", reserve included" : ""}`); - const verdict = mt <= B2 ? `Mid fits ${M(B2)} with ${M(B2 - mt)} to spare` : `Mid is ${M(mt - B2)} over ${M(B2)}`; + kpi(mt <= tgt ? M(tgt - mt) : "+" + M(mt - B2), `${mt <= tgt ? "to spare under" : "over"} ${M(tgt)} THB at the midpoint${inB ? ", reserve included" : ""}`); + const verdict = mt <= tgt ? `Mid fits ${M(tgt)} with ${M(tgt - mt)} to spare` : `Mid is ${M(mt - B2)} over ${M(B2)}`; const detail = inB ? `the investment ${M(mid.cap)} plus the ramp-up reserve, ${M(mid.cap + rLo)} to ${M(mid.cap + rHi)} THB with the reserve at ${M(rLo)} to ${M(rHi)}` : `the investment ${M(mid.cap)} THB without the reserve; with it, ${M(mid.cap + rLo)} to ${M(mid.cap + rHi)}`; - const vs180 = mt <= B1 ? `it fits ${M(B1)} too, with ${M(B1 - mt)} to spare` : `against ${M(B1)} it is ${M(mt - B1)} over`; + const vs180 = mt <= B1 ? `against ${M(B2)} it has ${M(B2 - mt)} to spare` : `against ${M(B1)} it is ${M(mt - B1)} over`; $("budV").innerHTML = `
${verdict}: ${detail}; ${vs180}. ` + `The low end is ${M(V[0].cap + V[0].res)}, the high end ${M(V[2].cap + V[2].res)} THB.
`; } diff --git a/docs/renders/calculator/plan-a-budget.png b/docs/renders/calculator/plan-a-budget.png new file mode 100644 index 0000000..2f85001 Binary files /dev/null and b/docs/renders/calculator/plan-a-budget.png differ diff --git a/docs/renders/calculator/plan-a-cash.png b/docs/renders/calculator/plan-a-cash.png new file mode 100644 index 0000000..e12c91a Binary files /dev/null and b/docs/renders/calculator/plan-a-cash.png differ diff --git a/docs/renders/calculator/plan-a-iso-gf.png b/docs/renders/calculator/plan-a-iso-gf.png new file mode 100644 index 0000000..424b81c Binary files /dev/null and b/docs/renders/calculator/plan-a-iso-gf.png differ diff --git a/docs/renders/calculator/plan-b-budget.png b/docs/renders/calculator/plan-b-budget.png new file mode 100644 index 0000000..5c900e1 Binary files /dev/null and b/docs/renders/calculator/plan-b-budget.png differ diff --git a/docs/renders/calculator/plan-b-cash.png b/docs/renders/calculator/plan-b-cash.png new file mode 100644 index 0000000..df69c12 Binary files /dev/null and b/docs/renders/calculator/plan-b-cash.png differ diff --git a/docs/renders/calculator/plan-b-iso-gf.png b/docs/renders/calculator/plan-b-iso-gf.png new file mode 100644 index 0000000..f651255 Binary files /dev/null and b/docs/renders/calculator/plan-b-iso-gf.png differ diff --git a/docs/roadmap.md b/docs/roadmap.md index 0035083..f5460bf 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -8,8 +8,11 @@ Rough durations are estimates. These three run in parallel and gate everything downstream: -1. **Market validation**: test the 3.50 to 4.60 USD blended pressing price - and regional demand with Asian labels and distributors, starting at +1. **Market validation**: test the blended pressing price (3.76 to 5.27 + USD at the planned 60 % specials; 3.50 to 4.60 at a standard-heavy mix) + and regional demand, which decides between Plan A (~0.74M records a year) + and Plan B (~1.25M) in [total investment](finance/total-investment.md#two-plans-a-at-180m-thb-and-b-at-225m-thb-october-2026), + with Asian labels and distributors, starting at Making Vinyl in Haarlem (Alexander and Simona). This is the biggest assumption in the [revenue model](finance/revenue-model.md); the financing case waits on it. **Partially started**: a first buy-side