Overview
Fireshield Tools is a Cloudflare Pages platform hosting two structural steel fire protection utilities. Both tools share a common section database and calculation engine โ built once, used everywhere.
๐ฅ FireCalc Live
Intumescent paint schedule generator. Upload a member list (Excel) โ get DFT, WFT, surface area, and paint weight per member โ download a formatted Excel schedule.
Products: Fireshield SQ476 (waterborne) and 920KS (epoxy)
๐ SteelVision v0.1
PDF structural drawing reader. Upload a drawing โ extract section callouts via regex โ match against the shared section database.
Status: Text extraction working; spatial association (linking callouts to geometry) is next.
Deployment
| Environment | Domain | Pages Project | D1 Database |
|---|---|---|---|
| Production | fireshield.consult.poh.nz | fireshield | fireshield-db |
| Dev | fireshield-dev.consult.poh.nz | fireshield-dev | fireshield-db-dev |
Both domains are behind Cloudflare Access (OTP). The pages.dev URL is public and used for API access.
Architecture
Key Design Decisions
- esbuild bundles everything at build time. Section JSONs (278 sections, 7 types) and product DFT tables are embedded into each worker. No runtime database calls for lookups โ fast and offline-capable for the MCP server.
- Shared library, multiple consumers.
lib/section-lookup.jsandlib/calculator.jsare imported by the Cloudflare Pages Function, the SteelVision client app, and the MCP server โ all via esbuild bundling. - D1 for mutable state only. The Cloudflare D1 SQLite database stores fuzzy match approvals (
section_aliases) and completed project schedules (projects,members). Static data never touches D1. - Section database on R2. The canonical section JSONs in
data/sections/are synced to a Cloudflare R2 bucket (steel-sections) so external projects can pull the same data without depending on this repo.
Section Matching Pipeline
- Exact match โ normalise input, check 278 sections + stored aliases (100% confidence)
- Custom alias โ check D1
section_aliasesfor user-approved mappings - Fuzzy match โ parse components, score candidates by dimensional proximity; auto-accept โฅ 80%
- Unmatched โ surface candidate suggestions in the UI for manual selection and approval
Shared Section Database
278 sections across 7 types: UB, UC, PFC, SHS, CHS, RHS, EA โ sourced from NZ/AU engineering references.
| Type | Description | Sides logic |
|---|---|---|
UB / UC | Universal Beams / Columns | 3 = beam (bottom flange sheltered), 4 = column |
PFC | Parallel Flange Channel | 3 sides standard |
SHS / RHS / CHS | Hollow sections | 4 sides always |
EA | Equal Angles | 3 sides standard |
WI / WB | Welded I / Box (computed) | Hp/A derived from DxBxtfxtw geometry |
R2 sync: python scripts/sync_sections.py push|pull|status
Excel Parser โ Input Formats
The FireCalc parser (public/firecalc/app.js โ findHeaders()) auto-detects the header row within the first 10 rows and maps columns by pattern matching. Two formats are tested and supported:
VIP format Standard
Row 1 is the header row. One data row per member.
| Column | Maps to |
|---|---|
Steel Section | Profile |
Length Meters | Length |
QTY | Quantity |
Fire Rating | Duration |
TCRIT | Critical temp |
Side | Sides (3/4) |
Zone | Zone (per row) |
Use | Use (Beam/Columnโฆ) |
Zone filter fully populated. All test client files use this format.
FireCalc output schedule Round-trip
Rows 1โ9: project metadata. Row 10: header. Zone group headers ("Zone: S01-010โฆ") are inter-row separators, not columns.
| Column | Maps to |
|---|---|
Section Designation | Profile |
Length (m) | Length |
Qty | Quantity |
Duration (min) | Duration |
Tcrit (ยฐC) | Critical temp |
Sides | Sides |
Use | Use |
โ Zone column will be blank โ zone info lives in group header rows, not per-column.
Parser Guard Rules
These prevent summary/metadata rows from being parsed as section data:
- Numeric profile cells skipped โ Summary by Zone tables have total lengths (e.g.
319.2) in the profile column as numeric Excel cells. Atypeof === 'number'check catches these before string conversion. - Header-like text skipped โ Cells starting with
Total,Summary,Notes,Steel,Section,Profile,Designation, orSizeare rejected as section designations. Arearemoved from zone patterns โ "Area (mยฒ)" is surface area, not a zone/location column. OnlyZone,Location, andLevelmatch the zone column.
Test Files
| File | Format | Members | Result |
|---|---|---|---|
Intumescent Coating - Building 1-UC-VIP.xlsx | VIP | 747 | 728 exact + 19 welded computed. 1 DFT out-of-range (WI 450x400x50x20, SF=36.2, 30min). Full zones. |
Test 1-920KS-PFP-Schedule.xlsx | FireCalc output | 747 | 728 exact + 19 welded computed. No unmatched. Zones blank (group-header format). |
CHCH East School-updated-VIP.xlsx | VIP | 66 | All exact. Most fail DFT range with SQ476; 39/66 succeed with 920KS. |
Three Parks Wanaka-VIP-1001 and 920KS.xlsx | VIP (2 sheets) | โ | 7 unique profiles incl. EA, PFC, SHS, UC. All exact. |
4157361-Christchurch East School-SQ476-920-VIP-rv2.xlsx | VIP (complex) | 373 | Handles "UB 310UB40.4" and "SHS 100x100x9" prefix formats. |
MCP Server
The MCP (Model Context Protocol) server exposes the FireCalc calculation engine as tools that an AI assistant can call directly โ no browser, no Excel. It runs as a local stdio process and is pre-configured for Claude Code via .mcp.json.
/mcp in Claude Code to confirm it's active, then just ask naturally โ "What's the DFT for a 310UB40.4 at 60 min?" and Claude will call the tools automatically.
~/.config/Claude/claude_desktop_config.json under mcpServers with "command": "node" and "args": ["/path/to/fire/dist/mcp-server.mjs"].
Available Tools
lookup_section
Find a steel section by profile string. Returns designation, section type, Hp/A (3-sided and 4-sided), cross-sectional area, and mass per metre. Fuzzy matching handles common variations and typos.
{ "profile": "310UB40.4" }
โ { "designation": "310UB40.4", "type": "UB", "hp_3sided_mm": 189, "hp_4sided_mm": 243, "area_mm2": 5170, ... }
calculate_member
Calculate DFT, WFT, surface area, and paint weight for one member. Returns certified intumescent coating thickness from bilinear interpolation of the product's DFT tables.
{ "profile": "310UB40.4", "product": "SQ476", "sides": 3, "fire_rating": 60, "length": 6 }
โ { "dft_mm": 1.245, "wft_mm": 1.245, "surface_area_m2": 7.21, "weight_kg": 10.75, ... }
compare_products
Side-by-side SQ476 vs 920KS comparison for a member. Returns DFT, WFT, coats, weight, and the delta โ which product is thinner and by how much.
{ "profile": "310UB40.4", "sides": 3, "fire_rating": 60, "length": 6 }
โ { "SQ476": { "dft_mm": 1.245, ... }, "920KS": { "dft_mm": 0.89, ... }, "delta": { "lower_dft": "920KS", ... } }
list_sections
Browse the section database. Omit type for a summary count per type; specify a type (UB, UC, SHS, etc.) to list all sections of that type with their Hp/A and area values.
{ "type": "UB" }
โ [ { "designation": "150UB14.0", "hp_3sided_mm": 328, ... }, ... ] // 50 sections
What the MCP Server Can Answer Today
- "What's the DFT for a 500UB92 at 90 minutes with SQ476, 3-sided?"
- "Which of 920KS or SQ476 gives a thinner coating on a 250UC89.5 column at 60 min?"
- "List all SHS sections available in the database."
- "Can you find the section closest to 'SHS100x5'?" (fuzzy match)
- "For a 6m 310UB32 beam at 30 min, how much paint weight does 920KS add vs SQ476?"
HTTP API (ChatGPT / Other LLMs)
The same four operations are available over HTTP at https://fireshield.pages.dev/api/calc โ no authentication required. This is the endpoint used for ChatGPT GPT Actions.
# GET
curl 'https://fireshield.pages.dev/api/calc?action=lookup_section&profile=310UB40.4'
# POST
curl -X POST https://fireshield.pages.dev/api/calc \
-H 'Content-Type: application/json' \
-d '{"action":"compare_products","profile":"310UB40.4","sides":3,"fire_rating":60}'
OpenAPI spec (for ChatGPT Action import): https://fireshield.pages.dev/firecalc/openapi.json
Future MCP Ideas
The MCP server currently covers single-member lookups and calculations. Here's what could be added as the platform grows:
๐ Batch schedule calculation
Accept a JSON array of members and return a full schedule โ same pipeline as the browser tool but callable by an AI agent. Useful for Claude to generate a complete PFP schedule from a member list in conversation.
๐ Product optimiser
Given a member list, run all available products and return coverage stats โ which product coats the most members, which combination gives full coverage, what's the total paint weight for each option. The foundation for AI-assisted product selection.
๐ SteelVision integration
Add a read_drawing tool that accepts a PDF path or base64 blob, runs the section callout extraction pipeline, and returns matched sections. An AI agent could then chain this with calculate_member to go from drawing โ full schedule in one conversation.
๐ Project history tools
Add get_project, list_projects tools that query the D1 database. An AI could retrieve a past schedule, compare it to a new one, or flag members whose DFT would change if the product was switched.
๐งฎ Design check tool
Accept Tcrit, section factor, product, and fire rating โ return whether DFT is in range, what the limiting factor is, and what alternative products or fire ratings would bring it into range. Useful for the "nothing works for this member" scenario.
๐ค Agentic schedule generation
Chain the tools end-to-end: an AI agent reads a structural drawing (SteelVision), identifies all members, matches them to sections (lookup_section), runs DFT calculations (calculate_member), handles edge cases conversationally, then outputs a formatted schedule. The MCP tools are designed with this pipeline in mind.