Draw it, buffer it, import it, or adopt a live fire perimeter, warning polygon or evacuation zone — and get structures in the ICS 209 Block 30 "Threatened" classes, people as a labelled estimate, and the named lifeline assets inside. Every count carries its method and its age, and every zone edit writes a line to a change log.
During an event, someone in the county emergency-management office has to put a defensible "threatened" figure in front of the Planning Section. The question is always the same: for this zone — drawn, buffered, imported or a live footprint — how many people, buildings and lifeline assets are inside it, and which ones?
The ICS 209 asks for exactly that: Block 30B, "the number of structures potentially threatened by the incident within the next 72 hours, based on currently available information" — and, in the same instructions, "note … if numbers entered are estimates or are confirmed." The app answers in that shape and says which it is.
The 209 asks for the number; nobody publishes it. The free tool the buyer already opens counts facilities one layer at a time and no buildings at all; the licensed stack summarises a polygon for credits and prints no estimate label.
Probed live, 2026-10-21. Read beside the incident's own 209 — never instead of it.
Over Paradise, every USA Structures footprint was imaged 2014-07-25 → 2018-09-10. The CAMP fire (alarm 2018-11-08) covers 99.9 % of the zone, and 9,074 of 9,075 footprints sit inside it. A test on the fire's year alone returns 0 and misses it. The real test is the alarm date against the newest imagery date.
OCC_CLS = Residential includes temporary lodging, nursing homes and dormitories, and in Paradise 2,241 of 9,075 footprints (25 %) are residences of unknown type. So the 209 crosswalk runs on PRIM_OCC, and "type not published" gets its own row. It is never split between single and multiple.
The footprint layer's building-population field is populated on 0 footprints in all five reference zones. So people come from FEMA NRI tract populations: areal-weighted, uniform density assumed, rounded to two significant digits (the 40 CFR 68.30 convention), and always labelled estimated.
So every number prints its imagery range, its class rule and its method. Without the burn-scar line, the app would report nine thousand threatened structures in a town most of which burned eight years ago.
| What exists | The zone | What it counts | Verdict |
|---|---|---|---|
| FEMA RAPT | draw a point, line or polygon with a buffer; a shapefile; current weather warnings. A fire perimeter as the zone: not stated | facilities "one infrastructure layer at a time"; a separate tract Population Counter; no structure count | Free, and already open. We sit beside it |
| Esri Emergency Management Operations | "draw the impacted area" | one infographic incl. USA Structures; population as a sum of block points; no estimate label stated; GeoEnrichment credits per run | The stack the buyer may own. This app runs beside it |
| FEMA Hazus 7.2 | a study region, on ArcGIS Pro desktop | damage, dollars, casualties, from building stock aggregated by tract or block | A loss estimator. A different question |
| PDC DisasterAWARE · Kontur Disaster Ninja · Everbridge · Samdesk | the vendor's own hazard model, any AOI (Kontur), or the vendor's incidents | exposure from their own grid, or your own assets only | Triage and alerting. The zone or the inventory is fixed elsewhere |
| Impact Zone | draw · buffer · import · adopt a live footprint | a Block 30 "Threatened" table, people (estimated, with the method) and named lifeline assets, each with its vintage and its change since the last edit | The gap |
No product read combines an arbitrary zone, a live footprint as the zone, and people, structures and named facilities in one summary. Only RAPT says "estimated", and no page read says how a partly-covered tract is weighted.
A light drafting table. The zone card is the select. The exposure ledger is the summary. The change log is the tray that accumulates, and the impact summary is the export. The output document is the product.
The counts follow the zone, never the map. Pan, zoom, context layers and the legend change nothing in the ledger. Only a zone edit recounts, and every recount appends one line with its time, the edit, Δ structures by class, Δ people (est.), and the assets that came in and went out.
Named assets: 8 of 8 inside. Paradise Fire Department Stations 81 and 82, and six public schools, one of them primarily virtual. The exception banner puts the schools first and isolates them in one click. People come from 10 NRI tracts, all only partly inside, with uniform density assumed and the method printed under the figure.
The log is never edited and never deleted, except by Clear log, which writes its own line. It is capped at 200 lines, and the cap is stated. The whole log prints in the impact summary, so "within the next 72 hours, based on currently available information" has a record of what it was based on.
So the structures card prints "⚠ … imaged before the CAMP fire … some may no longer stand." Damaged and destroyed counts come from field inspection, not from this app.
The adopted TIMBER perimeter is 14 parts, 10,496 vertices, 409,417 characters. A GET over ~2,048 characters returns an HTML error page, which a naive client reads as "no data". Every geometry query goes by POST, and the browser suite asserts it on every request.
The state field holds the full name. Filter on STATE_FIPS='06' and you get 10,931,401 California footprints. A statewide group-by failed after 56 s in the probe, so every structures query carries the zone geometry.
OBJECTID · ObjectId (HCAI) · GRASP_ID (CDC SVI) · FID (Cal OES SVI) · objectid (NWS) · and none declared at all (Geoportal). The id is read from each layer's metadata. It is never assumed.
60 active rows, 13 newest per incident and source, 7 incidents, and name case differs (Timber / TIMBER). The adopt rule keys on the upper-cased name plus source, and prints the perimeter's own date. A distinct-values query folds case and hides the duplicate.
An ungrouped statistic over an empty zone returns one row of nulls, not an empty list. Read as data, it is a zero with a null date. The app reads it as none, and an empty zone is a designed screen: "Nothing from the bound layers is inside this zone."
68 California tracts are suppressed as -999, not null. Painted naively, they become the least vulnerable. They are counted as "not ranked, not shown as low". SVI's population also differs from NRI's for the same tract, so the estimate never mixes them.
The spine: FEMA USA Structures footprints (CC BY 4.0) · FEMA National Risk Index tracts, December 2025 (1.20.0) · CDC/ATSDR SVI 2022 · HCAI open acute-care hospitals (454 rows) · CAL FIRE facilities (1,566 active) · CDE public schools 2025-26 · Caltrans state highways · CAL FIRE FIRIS and WFIGS perimeters · NWS watches and warnings · published evacuation zones · CAL FIRE historic perimeters. Flood is the Cal OES 2022-08 extract, labelled a substitute, because FEMA's NFHL refused 12 of 12 connections. Nothing is generated or seeded: every point is a published record or the operator's own import.
The "hide" filter used for the legend and the lifeline chips was silently rejected by MapLibre as a legacy filter. So Schools did not drop hospitals from the map, while the table, the chip and the DOM all said it had. It is fixed, and now pinned offline.
The core and the whole zone are each counted on the server, and the ring is the difference. A footprint on the boundary is never counted twice. The browser suite asserts this on live data for the adopted, drawn and imported zones.
0 API keys. A zero-dependency server.mjs. Turf 7.2.0 vendored with its sha256 recorded. The map controls vendored, with the drift check OK. All 33 keyless basemaps, and no request to a deny-listed host.
Stated honestly: the last full green browser run predates a final copy-and-layout pass (the feed bar, two labels, the Block 31 line, the legend title). The re-run was stopped by the host for low memory at 155 assertions, with 5 failures traced to one harness click landing on the draw panel. That framing is fixed, but not yet re-verified. The screenshots on these slides show the post-pass layout (the two-column feed bar). Do not read the build as fully green until node drive.mjs passes again.
Every one of these is written into the delivered application's own README. A tool that hides its edges costs you the project it cannot finish.
To point it at you, we need the live footprints you already adopt (perimeters, warning polygons, evacuation zones), a structures layer with occupancy, a tract population, and your own sites as a CSV or GeoJSON import. The same reading then counts your county's zone, not Paradise.
It drops in beside what you already run. FEMA RAPT stays open. Esri's Emergency Management Operations stays licensed. The impact summary (PDF), the exposed-assets CSV and the zone GeoJSON are built for your own systems to ingest. Every count carries the shape the 209 asks for: threatened, estimated, dated, and what changed.