const fs = require('fs'); let content = fs.readFileSync('src/components/landing/Sections.tsx', 'utf8'); // 1. Remove all em-dashes content = content.replace(/—/g, '-'); // 2. update useCountUp to accept decimals content = content.replace( `function useCountUp(target: number, duration = 1400) { const ref = useRef(null) const [val, setVal] = useState(0)`, `function useCountUp(target: number, duration = 1400, decimals = 0) { const ref = useRef(null) const [val, setVal] = useState(0)`); content = content.replace( ` const eased = 1 - Math.pow(1 - p, 3) setVal(Math.round(target * eased))`, ` const eased = 1 - Math.pow(1 - p, 3) const currentVal = target * eased setVal(decimals > 0 ? Number(currentVal.toFixed(decimals)) : Math.round(currentVal))`); // 3. update Stat to accept decimals content = content.replace( `function Stat({ value, label }: { value: number; label: string }) { const { ref, val } = useCountUp(value)`, `function Stat({ value, label, decimals = 0 }: { value: number; label: string; decimals?: number }) { const { ref, val } = useCountUp(value, 1400, decimals)`); content = content.replace( ` {val.toLocaleString()} `, ` {decimals > 0 ? val.toFixed(decimals) : val.toLocaleString()} `); // 4. HeroSection text modification content = content.replace( ` Know where to
`, ` cameras already point. `); content = content.replace( ` A living digital twin of Bengaluru's streets - surfacing illegal-parking hotspots before they choke the road. Built for the officers who decide where to look first.`, ` GridLoc separates where parking is recorded from where it actually happens, then hands BTP the gap.`); content = content.replace( ` `, ` `); content = content.replace( ` Know where to
`, ` cameras already point. `); content = content.replace( ` A living digital twin of Bengaluru's streets - surfacing illegal-parking hotspots before they choke the road. Built for the officers who decide where to look first.`, ` GridLoc separates where parking is recorded from where it actually happens, then hands BTP the gap.`); content = content.replace( ` `, ` `); // 5. DescentSection modification content = content.replace( `

Forty million journeys a day
converge on one city.

We cut past the noise to the hexes that matter - the corners where parked vehicles quietly turn a moving road into a standstill.

`, `

Count the busy cells,
call them hotspots,
and you have just redrawn the camera map.

Recorded volume tracks enforcement presence, not reality.

`); // 6. HOW_CARDS content = content.replace( `const HOW_CARDS: CardData[] = [ { id: 'ingest', title: 'Every street, as data', description: 'Traffic and parking signals across Bengaluru are snapped onto an H3 hexagonal grid - one comparable cell for every neighbourhood block.', icon: , }, { id: 'model', title: 'Observed vs. expected', description: 'Each cell is scored on how its real congestion compares to what the model expects for that day and time-window - isolating genuine anomalies.', icon: , }, { id: 'hotspots', title: 'Ranked, not just mapped', description: 'Cells are classified - Confirmed Hotspot, Blind Spot, Calm - and sorted so the worst zones rise to the top of the queue automatically.', icon: , }, ]`, `const HOW_CARDS: CardData[] = [ { id: 'observed', title: 'Observed score', description: 'Impact weighted, percentile ranked, not raw counts.', icon: , }, { id: 'expected', title: 'Expected score', description: 'City conditions only, POI proximity 0.7 plus road hierarchy 0.3, never touches violation data.', icon: , }, { id: 'certify', title: 'Certify', description: 'Getis-Ord Gi star gate, only 47 of 2534 cells survive, z up to 8.59.', icon: , }, ]`); // 7. Remove DataSection and HexBirth content = content.replace(/\/\/ ── 03 · THE DATA ─────────────────────────────────────────────────────────────[\s\S]*?(?=\/\/ ── 04 · FINDINGS \+ CTA)/, ""); // 8. Add new components const newComponents = ` // ── CORE IDEA ──────────────────────────────────────────────────────────────── export function CoreIdeaSection() { const ref = useReveal(0.15) return (
The Core Idea

Observed vs. Expected

A low recorded count can mean a genuinely calm street, or heavy uncaught parking with no camera pointed at it. We estimate where illegal parking should occur from city conditions, and compare it against where it was recorded.

) } function CoreIdeaMatrix() { const tiltRef = useScrollTilt(10) const [hovered, setHovered] = useState(null) const quadrants = [ { id: 'blindspot', col: 'Low Observed', row: 'High Expected', label: 'Blind Spot', count: 661, color: '#9a9a9e', bg: 'rgba(154,154,158,0.2)', desc: 'Conditions predict heavy parking, little recorded. Likely coverage gap. Tell BTP to look here.' }, { id: 'confirmed', col: 'High Observed', row: 'High Expected', label: 'Confirmed', count: 95, color: '#efefef', bg: 'rgba(239,239,239,0.15)', desc: 'Busy in data and conditions agree. Enforce with high confidence.' }, { id: 'calm', col: 'Low Observed', row: 'Low Expected', label: 'Calm', count: 4411, color: '#5c5c60', bg: 'rgba(92,92,96,0.1)', desc: 'Quiet and expected to be quiet. Do not waste patrols.' }, { id: 'quirk', col: 'High Observed', row: 'Low Expected', label: 'Quirk', count: 57, color: '#b0b0b4', bg: 'rgba(176,176,180,0.15)', desc: 'High tickets, low demand. Possible camera trap or one-off event.' }, ] return (
{quadrants.map(q => (
setHovered(q.id)} onMouseLeave={() => setHovered(null)} className="p-6 rounded-xl transition-all duration-300 cursor-default" style={{ background: q.id === 'blindspot' ? 'rgba(154,154,158,0.25)' : q.bg, border: \`1px solid \${q.id === 'blindspot' ? q.color : 'transparent'}\`, boxShadow: q.id === 'blindspot' ? \`0 0 20px \${q.color}40\` : 'none', transform: hovered === q.id ? 'scale(1.02)' : 'scale(1)' }} >
{q.label}
{q.count}
{q.col} / {q.row}
{q.desc}
))}
) } // ── BLIND SPOT RESULTS ─────────────────────────────────────────────────────── export function BlindSpotResultsSection() { const ref = useReveal(0.15) return (
The Output

Blind Spot Results

High-demand corridors where recorded enforcement is lower than conditions warrant. The output no count based method can produce.

{[ { name: 'Outer Ring Road', O: '0.89', E: '1.00' }, { name: 'Whitefield Main Road', O: '0.54', E: '1.00' }, { name: '17th Main Road', O: '0.91', E: '1.00' }, ].map((row, i) => (
{row.name}
O {row.O}
E {row.E}
))}
) } // ── TIME AWARE ─────────────────────────────────────────────────────────────── export function TimeAwareSection() { const ref = useReveal(0.15) return (
Time-Aware

Four data-derived time blocks

The blocks are data-derived ranges with no real-world clock claims. Across these shifts, 36 cells dynamically change their enforcement category.

) } // ── TRUST ──────────────────────────────────────────────────────────────────── export function TrustSection() { const ref = useReveal(0.15) return (

Driven by the data, not by our weight choices.

≥0.998
Spearman rho correlation under weight perturbation
97-100%
of cells keep their category under weight perturbation
100%
of cells resolved to real Bengaluru street names
) } `; content = content.replace(/\/\/ ── FOOTER/, newComponents + "// ── FOOTER"); fs.writeFileSync('src/components/landing/Sections.tsx', content); // LandingPage.tsx let lpContent = fs.readFileSync('src/components/landing/LandingPage.tsx', 'utf8'); lpContent = lpContent.replace(/—/g, '-'); lpContent = lpContent.replace( ` ScrollExpansionHero, DescentSection, HowItWorksSection, DataSection, FindingsSection,`, ` ScrollExpansionHero, DescentSection, CoreIdeaSection, HowItWorksSection, BlindSpotResultsSection, TimeAwareSection, TrustSection, FindingsSection,`); lpContent = lpContent.replace( ` `, ` `); fs.writeFileSync('src/components/landing/LandingPage.tsx', lpContent); console.log("Done updating files!");