Plant catalog format
The schema of the shared regional plant database every OpenLandscape3D client bundles. Source of truth: catalog/README.md in the website repository.
The shared regional plant database for every OpenLandscape3D client. Facts, recommendations and visual representations are stored separately (Drive plan 06): a plant can be a valid taxon without being suitable for a site; suitability is computed by the apps from these facts plus site inputs.
Consumers: openlandscape3d-cloud (npm run catalog copies catalog/data/*.json into src/lib/catalog/)
and openlandscape3d-ios (scripts/sync-catalog.sh copies them into OpenLandscape3D/Resources/Catalog/).
The interchange contract is openlandscape3d-ios/docs/EXPORT_FORMAT.md.
Files
| File | What |
|---|---|
data/plants.json |
{ "catalogVersion": "ol-plants@0.1", "generatedAt", "plants": Plant[] } |
data/regions.json |
{ "regions": Region[] } — the three U.S. pilot regions |
data/materials.json |
{ "materials": Material[] } — surfaces, fences, edging |
data/schedule-rules.json |
{ "rules": ScheduleRule[] } |
data/sources.json |
{ "sources": Source[] } — every source cited by provenance |
Plant
| Field | Type | Notes |
|---|---|---|
id |
string | Stable kebab-case slug of the accepted name, e.g. acer-rubrum, echinacea-purpurea. Cultivars: hydrangea-paniculata-limelight. Never reused. |
aliases |
string[] | Old ids / synonyms slugs that resolve to this record |
scientificName |
string | Accepted name without authorship, e.g. Acer rubrum |
authorship |
string | null | e.g. L. |
cultivar |
string | null | e.g. 'Limelight' (no quotes in the value: Limelight) |
family, genus |
string | |
commonNames |
{ name, lang, preferred }[] |
at least one preferred English name |
synonyms |
string[] | scientific synonyms |
form |
enum | tree · conifer · palm · shrub · perennial · grass · groundcover · vine · succulent |
leaf |
enum | deciduous · evergreen · semi-evergreen · herbaceous (perennials/grasses that die back) |
mature |
{ heightM: [min,max], spreadM: [min,max] } |
typical landscape size, metres |
growthRate |
enum | slow · medium · fast |
yearsToMaturity |
number | |
sun |
enum[] | subset of full, part, shade |
moisture |
enum[] | subset of dry, medium, wet |
soil |
enum[] | subset of sand, loam, clay |
ph |
[min,max] | null |
|
hardiness |
{ system: "USDA", min, max } |
integer zones |
bloom |
{ months: int[], color: "#rrggbb", colorName } | null |
months 1–12; null for non-showy |
foliageColor |
#rrggbb |
summer foliage, used by renderers |
fallColor |
#rrggbb | null |
|
nativeRegionIds |
string[] | pilot region ids where the species is native |
nativeRange |
string | short text, e.g. "Eastern North America" |
waterUse |
enum | low · medium · high |
maintenance |
enum | low · medium · high |
deerResistance |
enum | low · medium · high |
wildlife |
enum[] | subset of pollinators, birds, butterflies, hummingbirds, host-plant |
tags |
string[] | e.g. privacy, rain-garden, drought-tolerant, salt-tolerant, slope, edible, fragrant, winter-interest |
spacingM |
number | recommended on-centre spacing for groups/hedges |
defaultInstallSize |
string | one of the contract's installSize codes |
installSizes |
{ code, heightM, spreadM }[] |
typical nursery sizes and the size at planting |
policy |
{ jurisdiction, status, sourceId, effective }[] |
jurisdiction = region id or US-XX; status ∈ invasive, noxious, prohibited, regulated, watch |
summary |
string | Original 1–3 sentence design summary (never copied from nurseries) |
designNotes |
string[] | short original tips |
representation |
{ openplanProxy, symbol2d, crown } |
openplanProxy = OpenPlan3D catalog id per the contract mapping; symbol2d ∈ canopy, conifer, shrub, clump, spiky, mat; crown ∈ round, oval, columnar, vase, pyramidal, spreading, weeping, mound, upright, fountain, rosette, fan |
externalIds |
{ usdaSymbol?, gbifKey?, powoId? } |
only values verified against the source; otherwise omit |
provenance |
{ fields: string[] | "*", sourceId, retrieved, method, reviewStatus, confidence }[] |
reviewStatus ∈ draft-unreviewed, reviewed; confidence ∈ low, medium, high |
quality |
{ score: 0–100, indexable: boolean } |
computed by build.mjs: required fields + provenance + summary |
Region
{ id, name, country: "US", states: ["NY", …], hardinessZones: ["5a", … ], defaultZone, frost: { lastSpring: "MM-DD", firstFall: "MM-DD" }, climate, precipitationMm, summary, designGuidance: string[], ecoregions: string[] }
Pilot ids: us-northeast, us-southeast, us-southwest.
Material
{ id, kind: "surface"|"fence"|"edging"|"wall", appliesTo: [area or line kinds], name, color: "#rrggbb", unit: "m2"|"m"|"m3", priceUsd: { low, high }, notes } — prices are planning ranges, not quotes.
ScheduleRule
{ "id": "plant-container-shrub", "task": "transplant" , "label": "Plant container shrubs",
"appliesTo": { "forms": ["shrub"], "leaf": [], "tags": [] }, // empty = any
"windows": [ { "anchor": "lastSpring", "startDays": 0, "endDays": 45 },
{ "anchor": "firstFall", "startDays": -45, "endDays": -14, "alternate": true } ],
"recurrence": "once" | "yearly" | "weekly-first-season" | "monthly-growing-season",
"constraints": "Avoid frozen or saturated soil.",
"sourceId": "ol-editorial", "confidence": "medium" }
Task vocabulary (task): site-prep, soil-test, order, sow, transplant, divide, mulch,
establishment-watering, irrigation-adjust, winterize, prune, deadhead, cut-back, stake,
scout, fertilize, protect, inspect.
Rules
- Every fact cites a
sources.jsonentry. Pass-1 horticultural facts are editorial compilations markeddraft-unrevieweduntil a regional reviewer signs off; the website shows that state. - No nursery copy or photos. Summaries are original.
- Invasive/noxious statements cite the jurisdiction's list in
sources.jsonand are reviewed before indexing. - Never merge cultivars because trade names look alike.
Authoring and build (pass 1)
- Authored data lives in
src/(plants-*.mjsby form,regions.mjs,materials.mjs,schedule-rules.mjs,sources.mjs, shared colours inpalette.mjs). Plant records use a short-key shorthand documented at the top ofsrc/plants-trees.mjs;lib/catalog.mjsexpands it into the schema above. - Derived, never hand-typed:
id(slug of accepted name + cultivar, rank words and×dropped, unless an explicitidis given),genus,yearsToMaturitydefault (by form and growth rate),installSizes(typical nursery sizes per form, clamped to 90 % of the minimum mature size),defaultInstallSize,symbol2d/crowndefaults,representation.openplanProxy(contract mapping, thresholds on the mature midpoints),provenance(oneol-editorialentry plus one per policy list) andquality. quality.score= 60 × share of required fields present + 15 (provenance) + 10 (summary 60–400 chars) + 5 (design notes) + 5 (any external id) + 5 (all provenance reviewed).indexable= score ≥ 75 and no unreviewedpolicyentry (invasive statements are reviewed before indexing).- Perennial bloom colours must land in the same OpenPlan3D flower bucket under the web hue thresholds, the iOS hue thresholds and the iOS colour-name words; ambiguous colours and null perennial blooms are build errors.
appliesToin schedule rules: every non-empty list must match (forms AND leaf AND any one of tags). Windows withalternate: trueare either/or choices to the first window.policy.jurisdictionusesUS-XX; clients match it againstUS-+ each region state (and the region id).node catalog/check.mjsvalidates the publisheddata/*.jsonand fails if they are stale relative tosrc/.