Skip to content
HomePagesHomePages template kit
Menu

Pick a scenario for a fixture

Source a fixture's slots from real property data, by the fill-by-source rule.

Fill a section’s fixtures.ts from the kit’s golden scenarios instead of inventing values, so preview stays honest and every fixture is grounded in a real, self-consistent property.

Import scenarios from the fixtures entry — never the root barrel; dev-only sample data must never reach a published renderer bundle’s import graph — and pick the one whose breadth matches the state you’re building:

import { scenarios } from "@homepages/template-kit/fixtures";
const luxury = scenarios.luxuryMultiUnit; // 12 units, 3 contacts, both logos, video + 3D tour
const sparse = scenarios.sparseSingleFamily; // 1 unit, 1 contact, no logos, no media
const rent = scenarios.forRentCondo; // 1 unit, 2 contacts, both logos, video only

base almost always builds on luxuryMultiUnit — it’s the breadth ceiling, so a layout that survives it survives everything smaller. Reach for sparseSingleFamily or forRentCondo for a states entry designed to look different against a thinner property.

Scenario units listing_intent property_type contacts pois photos contact logos media
luxuryMultiUnit 12 for_sale multi_family 3 24 12 both logos video + 3D tour
sparseSingleFamily 1 for_sale single_family 1 4 3 (reused from forRentCondo) none (null) none (null)
forRentCondo 1 for_rent condo_townhome 2 8 8 both logos video only

Don’t invent a value. Every slot in schema.ts already declares how it’s filled in production — fixtures.ts mirrors that:

Slot’s fill-spec source How the fixture fills it
a fact (fact.<container>.<field>) read it off the scenario — s.facts.address.display, primaryContact(s).fields.phone
derived() a helper — propertyMetrics(s), poisByCategory(s), contactCards(s)
ai a short sample fill grounded in the scenario’s facts — a headline about this property, never lorem ipsum or invented facts

A fixture that gets this wrong is worse than a missing one: a slot bound fact.unit.beds whose fixture value doesn’t match s.facts.units[0].beds teaches nothing about the layout it’s supposed to preview.

import {
contactCards,
poisByCategory,
primaryContact,
propertyMetrics,
scenarios,
} from "@homepages/template-kit/fixtures";
const s = scenarios.luxuryMultiUnit;
Helper Returns
primaryContact(s) The scenario’s primary contact (ContactFixture, position 0 by construction) — throws if the scenario has none
contactCards(s) Every attached contact, in order (ContactFixture[])
poisByCategory(s) The scenario’s POIs bucketed by category (Record<PoiFixture["category"], PoiFixture[]>)
propertyMetrics(s) beds/baths/sqft/price off the lowest-position unit, bedsMin/bedsMax/bathsMin/bathsMax/sqftMax/priceStart across all units, and addressLine1/addressLine2

propertyMetrics returns kit fact vocabulary — addressLine1/addressLine2, not a template’s own slot names, so the kit never learns what a section calls its slots. Map it to your slots at the call site:

const m = propertyMetrics(s);
// ...in base.slots:
address_street: m.addressLine1,
address_locality: m.addressLine2,

Fields the helpers don’t cover are readable straight off the scenario: s.photos, s.pois, s.amenities, s.contacts, s.media, and s.facts (the raw PropertyFacts). A contact’s org name and logos (logo_light_id/logo_dark_id) live on ContactFixture["fields"], not on a sibling “brand” object — read them off primaryContact(s).fields or s.contacts.

Every media reference in a scenario is an asset id, the same thing a saved page holds — s.photos[n].id, primaryContact(s).fields.headshot_id / .logo_light_id / .logo_dark_id, s.media.video_id, and a floor plan ref’s id. Put the id in the fixture and stop there: the url, the alt fallback, and the responsive ladder are attached for you when the fixture loads. Never state a url in a fixture. (s.media.tour_3d_url is the one exception — a 3D tour is a third-party embed with no asset behind it.)

A states entry designed to look different against a sparser property sources from a different scenario, not from overridden literals — see Preview a section’s structural edge cases for the full pattern.

None — this is a pure content edit. No CLI command beyond the author loop below.

Verify with the author loop.