/* Brand Lens — the living photography style guide (built from your real calls) */ function StyleGuide({ recs, goReview }) { const reviewed = useMemo(() => recs.filter((r) => r.user && r.ai), [recs]); const liked = useMemo(() => recs.filter((r) => r.user && r.user.like).sort((a, b) => (b.ai ? b.ai.score : 0) - (a.ai ? a.ai.score : 0)), [recs]); const disliked = useMemo(() => recs.filter((r) => r.user && !r.user.like), [recs]); const [guide, setGuide] = useState(() => { try { return JSON.parse(localStorage.getItem('lens-guide') || 'null'); } catch (e) { return null; } }); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); async function build() { setBusy(true); setErr(null); try { const g = await window.Lens.generateGuide(recs); setGuide(g); localStorage.setItem('lens-guide', JSON.stringify(g)); } catch (e) { setErr(e.message || 'Generation failed'); } setBusy(false); } if (reviewed.length < 3) { return ; } const stale = guide && guide.basedOn !== reviewed.length; return (
Proper Sky · Photography

Your living style guide

{busy ? <> Synthesizing… : guide ? 'Refresh from latest' : 'Generate style guide'}

Distilled from your {reviewed.length} reviewed images and your own comments. Generating or refreshing it re-teaches the judge — your next Calibrate round will score with this folded in, so agreement climbs over rounds.

{err &&
{err}
} {!guide && !busy && (
Ready to synthesize
Generate the guide from your {reviewed.length} calls and comments.
)} {guide && (
The judge is now calibrated from this guide. Your next Calibrate round reflects it — watch the scoreboard agreement climb.
{stale && (
Built from {guide.basedOn} reviews — you now have {reviewed.length}. Refresh to fold in the new ones.
)} {/* summary */}
The taste, in a sentence
{guide.summary}
{/* do / don't */}
{/* looks like this / not this */}
{/* trends */} {guide.trends && guide.trends.length > 0 && (
{guide.trends.map((t, i) => (
{t.tag}
{t.note}
))}
)} {/* social-specific guidance */} {guide.social && (guide.social.note || (guide.social.rules && guide.social.rules.length > 0)) && (
{guide.social.note && (

{guide.social.note}

)} {guide.social.rules && guide.social.rules.length > 0 && (
    {guide.social.rules.map((t, i) => (
  • {t}
  • ))}
)}
)} {/* channels */} {guide.channels && guide.channels.length > 0 && (
{guide.channels.map((c, i) => (
{c.channel}
{c.guidance}
{c.ratios}
))}
)} {/* divergence / recalibration */} {guide.divergence && (
{guide.divergence}
)}
Generated {new Date(guide.generatedAt).toLocaleString()} · from {guide.basedOn} reviewed images.
)}
); } function Section({ title, sub, children }) { return (

{title}

{sub &&

{sub}

} {children}
); } function RuleCol({ kind, items }) { const isDo = kind === 'do'; return (

{isDo ? 'Do' : "Don't"}

    {items.map((t, i) => (
  • {t}
  • ))}
); } function Gallery({ recs, tone, empty }) { if (!recs.length) return

{empty}

; return (
{recs.map((r) => (
{r.name} {r.user.comment && (
“{r.user.comment.length > 60 ? r.user.comment.slice(0, 58) + '…' : r.user.comment}”
)}
))}
); } window.StyleGuide = StyleGuide;