Skip to content
Docs

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.json entry. Pass-1 horticultural facts are editorial compilations marked draft-unreviewed until 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.json and are reviewed before indexing.
  • Never merge cultivars because trade names look alike.

Authoring and build (pass 1)

  • Authored data lives in src/ (plants-*.mjs by form, regions.mjs, materials.mjs, schedule-rules.mjs, sources.mjs, shared colours in palette.mjs). Plant records use a short-key shorthand documented at the top of src/plants-trees.mjs; lib/catalog.mjs expands it into the schema above.
  • Derived, never hand-typed: id (slug of accepted name + cultivar, rank words and × dropped, unless an explicit id is given), genus, yearsToMaturity default (by form and growth rate), installSizes (typical nursery sizes per form, clamped to 90 % of the minimum mature size), defaultInstallSize, symbol2d/crown defaults, representation.openplanProxy (contract mapping, thresholds on the mature midpoints), provenance (one ol-editorial entry plus one per policy list) and quality.
  • 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 unreviewed policy entry (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.
  • appliesTo in schedule rules: every non-empty list must match (forms AND leaf AND any one of tags). Windows with alternate: true are either/or choices to the first window.
  • policy.jurisdiction uses US-XX; clients match it against US- + each region state (and the region id).
  • node catalog/check.mjs validates the published data/*.json and fails if they are stale relative to src/.