| ★ ▲ | Address ▲ | Zone ▲ | Lot ▲ | Price ▲ | Lot Size ▲ | Lot W ▲ | Exit $/SF ▲ | Sell Value ▲ | Land Cost ▲ | Profit ▲ | ROC ▲ | Slope ▲ | Days Listed ▲ | New ▲ | Link |
|---|
The sliders below are the SFR pro forma. Every parcel reprices live as you drag — pins re-color, the deal card refreshes, Market Data aggregates re-tally. Move the ROC chip to widen or narrow the visible pool.
Default filter posture on load: Status = Active · ROC ≥ 20% · Lot ≥ 5K SF · Lot W ≥ 40 ft · Lot D ≥ 100 ft · Acquisition ≤ $2M · Exit ≥ $1,200/SF · Land basis ≤ $500/SF · Slope ≤ 20%. Click Reset all in the header chip bar to return to this posture.
PIN COLORS (Return on Cost)
DEAL STATUS DOTS
OTHER MARKERS
Switch to the Assumptions tab above to tune the SFR pro forma — every parcel reprices live as you drag. The map opens on viable deals only (ROC ≥ 0% at asking price); use the ROC filter to widen.
We identify single-family-zoned LA County parcels — teardown or vacant — where the spread between land cost and a new-construction $/SF exit is large enough to pencil. We acquire, build one modern modular SFR per lot, and sell it. Baseline economics: $500/SF all-in ($425 hard + $75 soft, configurable) against a $1,000/SF+ target exit. Build-to-sell only. One home per lot for v1.
This app covers LA County only (City + all incorporated cities). All listings, comps, and zoning data are LA-specific. Vacant Land + Single Family Residential are both admitted to the acquisition layer; vacant lots are the preferred build-to-sell target and run the pro forma off defaultHomeSf with demoCost = 0.
VHFHSZ: Very High Fire Hazard Severity Zone is an informational flag only in the SFR app, NOT a knockout. The Jan-2025 Palisades burn footprint is a priority target — post-fire vacant lots are surfaced via the burn-zone overlay (toggle in the filter bar) and the 🔥 badge on deal cards. Insurance + WUI code surcharge belong in the per-deal pro forma, not the eligibility gate.
Listing status: Captured at scrape time and refreshed on every rebuild. Redfin's STATUS field maps to a user-facing label: Active → “Active” (no pill), Contingent → “In Contract” (amber pill), Pre On-Market → “Coming Soon” (gray pill). Filter via the Listing Status segmented control under Filters; pill renders on the deal card header for non-Active deals.
Zoning coverage: 4-endpoint cascade (City of LA / Santa Monica / Malibu / LA County DRP) confirms zone for ~80% of slice parcels. Parcels in uncovered cities (Beverly Hills, WeHo, Culver City, Inglewood, Pasadena, Glendale, Burbank, Long Beach) fall back to the Redfin property-type mapping with a zoningUnconfirmed flag on the card.
Every parcel runs through the SFR pro forma (see src/models/proforma.js):
The acquisition decision always turns on “max land price.” The model exposes both forms:
maxLand = netSales − buildCost − financingCost − (netSales × targetGrossReturnPct)maxLand = ((sellValue − sellingCosts) − allInBuildPsf×homeSf×(1 + roc×holdMonths÷12)) / (1 + roc×holdMonths÷12)Deal signal = maxLand vs. asking. The gap is the opportunity.
Land $X + Build $Y ($/SF × homeSf) + Demo $Z + Financing $F = $T all-in → Sell $S − Txn cost $C → $P profit. Demo is broken out of Build so the equation foots to Total cost. Financing now includes the loan origination fee (P1-6 fix: computeCostStack rolls loanAmount × loanFeePct into financingCost so totalCost foots).far_rules.json v2.1 (89 jurisdictions, 282-entry neighborhood map) — the JSON is the single source of truth; src/data/zoning-rules.js is a thin loader. Resolution chain:
l.city.toLowerCase() → neighborhoodMap (e.g. “Woodland Hills” → los-angeles-city; “Topanga” → los-angeles-county-unincorporated) → jurisdictions[key] → merge zones[normalizeZone(l.zone)] over jurisdiction.default. Any miss falls to advisoryDefault {method:'verify', far:0.50}. Post-resolution demotion: LA-City listings whose zone has an H suffix OR carry the listing coastal flag demote method to verify (advisory, never clamps). Non-LA coastalCDP:true jurisdictions (Redondo, Manhattan Beach, Malibu, …) keep their method but never clamp.
{sqft, branch, provenance, clamp}):
far × lotSfeffFarOverride × lotSf for per-floor-cap cities (e.g. Santa Monica — 30% ground + 20% second floor → eff. FAR 0.50). Otherwise coverage × lotSf × stories (stories from JSON; fallback floor(maxHeightFt/10)).(lw − 2·sideFt) × (depth − frontFt − rearFt) × floors. depth uses surveyed l.ld when present, else lotSf / lw. floors = stories || floor(maxHeightFt/10). Width missing or footprint ≤ 0 → falls to fallback. Used for jurisdictions with sourced setbacks + height but no codified FAR (LA County unincorp, Title 22 §22.20).0.50 × lotSf. Used when jurisdiction is unmapped, method demoted to verify, or envelope branch is unrenderable.provenance:'computed' + no flags → normal mono numeral; CLAMP badge iff clamp:true.'computed' + zoningUnconfirmed → advisory tier “~{n} SF · zone unconfirmed”, no CLAMP badge.'est-dims' (sourced rule, but lotShape==='est' — synthetic 2.5:1 dims, envelope branch only) → advisory “~{n} SF · est. dims”.'fallback' → verify-gray “~{n} SF · ~0.50 assumed”. Never styled like a computed number.effFarOverride cities.
method === 'far' && confidence === 'high' && !l.zoningUnconfirmed && !demoted && !coastalCDP. In practice only LA-City non-H non-coastal confirmed-zone listings clamp. Everything else is advisory: 75 long-tail cities are honest verify stubs (advisory 0.50, low confidence), LA County unincorp is envelope-advisory (footprint computable but never clamps), Santa Monica / Long Beach / Burbank are coverage-advisory, Malibu / Manhattan Beach / Redondo are coastal-advisory. Header “Zoning” button opens the right drawer with the full per-jurisdiction table (method, ratio basis, setbacks, height, confidence, clamp eligibility, source) populated at runtime from the JSON.
.dcp3-tv line-height (smaller-font values use .dcp3-tv-sm, same line-height). Land $/SF = asking ÷ lot SF (broker frame). Missing data renders as “—”. Home SF is a plain static tile by default; only in edit mode does it flip to the reddish editable input (bounds 400–12,000).SENSITIVITY_DELTA_PSF ($100) below the base exit $/SF. Each row re-runs calculateProForma (P1-5 fix: resolved as window.calculateProForma || window.Models?.ProForma?.calculateProForma so the lookup never fails on load order). Viable badge green when ROC ≥ 0._editInput('homeSf', ...) which routes to _onEditInput, writes _editMode.values.homeSf, and persists to _overrideHomeSf on Done. Drives both build cost (hard+soft $/SF × homeSf) AND sale (homeSf × exitPsf); re-renders tiles, math line, Zoning strip cap pill, all sensitivity rows, and the expanded ledger from the single-source pro forma.sfr_overrides_<AIN>). An “Edited” badge appears on cards with saved overrides. Internally they write _overrideHardPsf / _overrideSoftPsf / _overrideHomeSf — the same keys resolveDealInputs consumes, so card edits actually apply.Page-load defaults: ROC ≥ 0%, Lot Width ≥ 50 ft, Lot Depth — any, Exit $/SF ≥ $1200, Slope ≤ 20%, Asking ≤ $2M, Land Basis ≤ $500/SF, Zoning = R1 + LAND + R2/R3 vacant.
l.ld.fetch_slopes.py; drag the slider to widen. Lots with slope ≥15% show a cost-uplift warning.l.isVacantLand. Persists across page reloads. Vacant lots carry $0 demo cost; teardowns add demo cost from the Assumptions slider.l.status from Redfin (Active, Contingent → “In Contract”, Pre On-Market → “Coming Soon”). Captured at scrape time; refreshed on every rebuild. Persists across page reloads.newSinceLast=true by the snapshot diff (i.e. absent from the prior pipeline run). Persists per browser. See New & Changed Listings for the underlying detection.l.burnZone = "Palisades". Displayed as 🔥 BURN-ZONE TARGET. Surfaced, never suppressed.l.coastal = true for parcels inside the CA Coastal Commission boundary. Displayed as 🌊 Coastal Zone — CDP required on the deal card. Informational only — never excludes. The Coastal Development Permit (CDP) adds 3–6+ months to entitlement. Toggle the coastal zone overlay in the filter panel to visualize the CCC boundary on the map._editMode.values.homeSf live, drives the FAR cap pill + pro forma, and persists to _overrideHomeSf on Done. Overrides the global Home Size slider for that one deal.Rescaled to the realized SFR exit-$/SF distribution observed in the SM+Palisades slice (~$840 P5 → $3,540 P95). The band discriminates inside the $1.5K–$2.5K/SF meat of the market.
Listing data is a dated snapshot from the most recent pipeline run. Individual listings may have gone under contract, been withdrawn, or had price changes since the snapshot was taken. Always verify a listing is still active on Redfin before acting. Use the Redfin ↗ link in the card footer to confirm live status.
A footnote at the bottom of each deal card shows “Listing data as of [date]”. The text turns amber when the snapshot is more than 3 days old.
Every pipeline run compares today’s Redfin pull against a committed rolling snapshot (data/listings_snapshot.json, keyed by Redfin URL) and stamps three fields on each listing:
firstSeen — ISO date the listing was first observed by the pipeline. Carries forward on every run.newSinceLast — true when the listing key was absent from the previous snapshot. Surfaces in the card header as a green “New” badge and is filterable via the New since last refresh toggle in Filters.statusChanged — {from, to} when Redfin status moved between runs (e.g. Active → Contingent). Surfaces as an amber “→ In Contract” micro-tag in the badges row.priceChanged — signed integer dollar delta vs. the prior snapshot. Negative values surface as a green “Price ↓ $X” micro-tag; positive as a red “Price ↑ $X”.listings.js naturally and are written to data/new_gone_<YYYY-MM-DD>.json for the (future) Build B2 email pass.First-run guard: on the very first pipeline run after this feature ships there is no prior snapshot — the run establishes the baseline and newSinceLast=false for every listing. Real diffs start on run 2. Legacy listings missing these fields render as if all three were unset (no badges, no filter hits).
Colored dots in the header bar show when each dataset was last refreshed:
Datasets tracked: Listings, Comps, Parcels.
Invite-only access. Contact matt@lucidresi.com.
Exit $/SF is the estimated sale price per square foot for a completed new-construction single-family home on this parcel. The comp universe is restricted to detached single-family residences only (no condos, no townhomes, no multi-family) and to sales within the last 24 months. Comps are classified into three condition tiers, and the exit price prefers the truest comp pool (T1-New) and falls back gracefully when that pool is thin.
prefer T1-New regression → T1-Reno regression → T1-New median → T1-Reno median → T2 regression × (1 + uplift) → T2 median × (1 + uplift)
uplift = 10% (canonical new-construction premium; T2-fallback paths only — exits reprice at next data refresh)
No floor. No ceiling. The model output is the number. Each cluster reports its exitSrc (which tier the price came from) so confidence can be judged at a glance.
Comps are spatially clustered (0.005° ≈ 0.35 mi grid cells) and bucketed into one of three tiers:
A cluster needs at least 3 comps in a tier to fit a weighted size-regression. Below that, the tier median is used. T1-Reno requires no premium — recently renovated SFR finishes are comparable to new construction in $/SF terms; the gap shows up only in T2.
The Sale $/SF grid layer and comp popup colors use a 14-bucket cold-to-hot gradient:
Within each cluster and each tier (with ≥3 comps), the pipeline fits a recency-weighted linear regression of price = intercept + slope × sqft across comp sale price and square footage, then predicts the price at the 3,500 SF target home size. Output is converted back to $/SF for display. Comps outside 1,200–6,000 SF are excluded from the curve fit; comps with extreme slopes (<$200 or >$1,500/SF) are rejected as bad fits.
The 3,500 SF anchor matches our default new-build SFR home size. Larger or smaller targets are interpolated from the same curve via the KEY-panel home-size override.
The model requires at least 5 comps. If fewer qualify, the search radius expands (up to 3.0 miles) and lower product tiers are added until 5 are found. Confidence is scored 0–100 based on comp count and method quality:
The pipeline rejects regression slopes outside [$200, $1,500]/SF as bad curve fits, and excludes comps whose $/SF falls outside this same band. Comps outside 1,200–6,000 SF are excluded from the size-curve fit. Trimming is performed at the curve-fit stage, not as a post-hoc IQR pass.
When a cluster lacks enough T1-New or T1-Reno prints to anchor an exit, the model falls back to the T2 (older / unrenovated) pool with a +10% condition uplift (the canonical new-construction premium). This adjusts for the empirical gap between an existing-condition resale and what a new SFR build in the same submarket trades for. Exits reprice at the next data refresh.
The uplift is applied only when exitSrc is existing+uplift, existing-median+uplift, or blended+uplift. T1 paths (T1-New and T1-Reno) carry no premium. T1-Reno prints (recently renovated) are treated as comparable to new construction in finish level.
Each cluster exposes the path the exit number was derived from, so confidence can be judged at a glance:
new — Strongest: ≥3 T1-New comps in the cluster supported a size-regression fitreno — Strong: ≥3 T1-Reno comps anchored the regression (recent renovation ≈ new finish)new-median / reno-median — Moderate: ≥3 T1 prints exist but the regression did not pass sanity checks; tier median usedexisting+uplift / existing-median+uplift — Limited: no T1 prints in the cluster; T2 baseline used with +10% condition uplift (canonical new-construction premium)blended+uplift — Weakest: insufficient comps in any tier; blended cluster median used with +5% uplift (half the canonical premium). Treat exit with caution.Hiding comps filters the comp table for inspection; exit $/SF stays at the pipeline value (full re-pricing on the remaining pool is a future enhancement). Excluded comps remain visible at reduced opacity and are flagged (EXCLUDED: TRUE) in CSV exports.
Exclusions are per-deal and per-session — they reset on page reload. To override exit $/SF, use edit mode on the deal card.
Eligible parcels are single-family-zoned and buildable. In-scope zones: A, RA, RE, RS, R1, RU, RZ, RW1, and LAND (vacant residential).
R2 / R3 vacant land is also admitted when isVacantLand === true — these are buildable single-SFR lots within a multi-family zone. Improved or teardown R2/R3 (existing multi-family buildings) remains excluded due to RSO / tenant risk. In the current dataset this adds ~73 R2 and ~52 R3 vacant lots to the eligible pool.
Two automatic disqualifiers — no override:
Full buildable envelope per jurisdiction. maxBuildable by method:
FAR × lot · coverage × lot × stories · footprint(setbacks) × floors.
Only FAR + high-confidence hard-clamps Home SF; coverage & envelope are advisory.
LA-City Hillside (H-suffix) / Coastal lots demote to verify. Unsourced setback/height fields render verify, never a guess.
| Jurisdiction | Method | Ratio basis | Setbacks F/S/R | Max Ht | Conf. | Clamp | Source |
|---|
FAR × lot
coverage × lot × stories
footprint(W−2·side)(D−front−rear) × floors
Clamp ⇢ FAR + high only
LA County build-to-sell single-family
Your account is signed in, but it doesn't have access to this app.
Access to SFR Acquisition is by invitation only. Contact your admin at matt@lucidresi.com to request access.
Choose a password for your account