Reframe deck for a first-time reader (Bucket 2)
Title: "One soil, three flowers" not "3-in-1" — spells out the So·lL·unar wordmark, labels each flower with its type + place (incl. the French farm), and shows a "future flowers" slot. Entities slide echoes the metaphor and names the southern-France environment. Ask: "Choose your way in" with numbered Option 1 / Option 2, framing it as a decision rather than a menu. Roadmap: unpacks the "blueprint is the business" riddle. Memberships: reframed as three recurring-revenue streams with revenue-at-target per tier. Building: literal front/back layout. P&L: adds a "Tap to expand" affordance so the breakdown is discoverable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
1ee4d64cb1
commit
1edfa8c9c3
7 changed files with 66 additions and 25 deletions
|
|
@ -4,15 +4,20 @@ import Icon from '../components/Icon.vue'
|
||||||
import { brand, investorAsk, pnl, fmtUsd } from '../data'
|
import { brand, investorAsk, pnl, fmtUsd } from '../data'
|
||||||
|
|
||||||
const pct = (n: number) => Math.round(n * 100)
|
const pct = (n: number) => Math.round(n * 100)
|
||||||
// annual profit share per option, on the recomputed yearly profit
|
// annual profit share per option, on the recomputed yearly profit.
|
||||||
const options = investorAsk.options.map((o) => ({ ...o, annual: Math.round(pnl.yearlyProfit * o.equity) }))
|
// Number them so the ask reads as a choice ("which way in?"), not a menu of two.
|
||||||
|
const options = investorAsk.options.map((o, i) => ({
|
||||||
|
...o,
|
||||||
|
choice: `Option ${i + 1}`,
|
||||||
|
annual: Math.round(pnl.yearlyProfit * o.equity),
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SlideFrame center>
|
<SlideFrame center>
|
||||||
<p class="text-xs font-semibold uppercase tracking-[0.3em] text-amber">The ask</p>
|
<p class="text-xs font-semibold uppercase tracking-[0.3em] text-amber">The ask</p>
|
||||||
<h2 class="mt-4 font-display text-4xl font-semibold text-fg sm:text-5xl">Two ways in</h2>
|
<h2 class="mt-4 font-display text-4xl font-semibold text-fg sm:text-5xl">Choose your way in</h2>
|
||||||
<p class="mt-3 text-fg-muted">Invest in SolLunar Society — the first node, opening in Austin.</p>
|
<p class="mt-3 text-fg-muted">Invest in SolLunar Society — the first node, opening in Austin. Pick the entry that fits.</p>
|
||||||
|
|
||||||
<!-- the two options -->
|
<!-- the two options -->
|
||||||
<div class="mx-auto mt-9 grid w-full max-w-2xl gap-5 sm:grid-cols-2">
|
<div class="mx-auto mt-9 grid w-full max-w-2xl gap-5 sm:grid-cols-2">
|
||||||
|
|
@ -29,9 +34,10 @@ const options = investorAsk.options.map((o) => ({ ...o, annual: Math.round(pnl.y
|
||||||
Full build
|
Full build
|
||||||
</span>
|
</span>
|
||||||
<p
|
<p
|
||||||
class="text-xs font-semibold uppercase tracking-wider"
|
class="flex items-center gap-2 text-xs font-semibold uppercase tracking-wider"
|
||||||
:class="o.featured ? 'text-indigo' : 'text-fg-muted'"
|
:class="o.featured ? 'text-indigo' : 'text-fg-muted'"
|
||||||
>
|
>
|
||||||
|
<span class="rounded-full border border-current px-2 py-0.5">{{ o.choice }}</span>
|
||||||
{{ o.label }}
|
{{ o.label }}
|
||||||
</p>
|
</p>
|
||||||
<div class="mt-1 flex items-baseline gap-2">
|
<div class="mt-1 flex items-baseline gap-2">
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ const backbone = entityById('lab484')
|
||||||
<template>
|
<template>
|
||||||
<SlideFrame
|
<SlideFrame
|
||||||
kicker="The collaboration"
|
kicker="The collaboration"
|
||||||
title="Three experiences, one backbone"
|
title="One soil, three flowers"
|
||||||
subtitle="One is funded and opening now — SolLunar Society in Austin. The summit gathering and the farm follow, on the same Lab 484 stack."
|
subtitle="One flower is funded and opening now — SolLunar Society in Austin. A regenerative farm in southern France and travelling pop-up gatherings follow — the same Lab 484 stack, proven in three very different environments."
|
||||||
>
|
>
|
||||||
<div class="grid gap-5 md:grid-cols-3">
|
<div class="grid gap-5 md:grid-cols-3">
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,18 @@ import SlideFrame from '../components/SlideFrame.vue'
|
||||||
import Icon from '../components/Icon.vue'
|
import Icon from '../components/Icon.vue'
|
||||||
import { memberships, membershipComparables, fmtUsd } from '../data'
|
import { memberships, membershipComparables, fmtUsd } from '../data'
|
||||||
|
|
||||||
// display low → high price
|
// display low → high price; carry each tier's monthly revenue at its member target
|
||||||
const tiers = [...memberships].sort((a, b) => a.price - b.price)
|
// so the slide reads as three recurring-revenue streams, not a "buy a membership" pitch
|
||||||
|
const tiers = [...memberships]
|
||||||
|
.map((t) => ({ ...t, atTarget: t.price * t.target }))
|
||||||
|
.sort((a, b) => a.price - b.price)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SlideFrame
|
<SlideFrame
|
||||||
kicker="SolLunar Society · memberships"
|
kicker="SolLunar Society · recurring revenue"
|
||||||
title="Three ways to belong"
|
title="Three recurring-revenue streams"
|
||||||
subtitle="Recurring membership is the core of the model — priced right for the Austin market."
|
subtitle="Memberships are the model's core revenue engine — three tiers, each a predictable monthly stream. Below each tier is its revenue at target, priced against the Austin market."
|
||||||
>
|
>
|
||||||
<div class="grid gap-5 md:grid-cols-3">
|
<div class="grid gap-5 md:grid-cols-3">
|
||||||
<div
|
<div
|
||||||
|
|
@ -30,9 +33,13 @@ const tiers = [...memberships].sort((a, b) => a.price - b.price)
|
||||||
<h3 class="font-display text-xl font-semibold text-fg">{{ t.name }}</h3>
|
<h3 class="font-display text-xl font-semibold text-fg">{{ t.name }}</h3>
|
||||||
<div class="mt-2 flex items-baseline gap-1">
|
<div class="mt-2 flex items-baseline gap-1">
|
||||||
<span class="font-display text-4xl font-bold text-fg">{{ fmtUsd(t.price) }}</span>
|
<span class="font-display text-4xl font-bold text-fg">{{ fmtUsd(t.price) }}</span>
|
||||||
<span class="text-sm text-fg-muted">/mo</span>
|
<span class="text-sm text-fg-muted">/mo · per member</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-1 text-xs text-fg-muted">{{ t.blurb }} · target {{ t.target }} members</p>
|
<p class="mt-2 font-display text-sm font-semibold text-indigo">
|
||||||
|
≈ {{ fmtUsd(t.atTarget) }}/mo
|
||||||
|
<span class="font-sans font-normal text-fg-muted">revenue at {{ t.target }} members</span>
|
||||||
|
</p>
|
||||||
|
<p class="mt-1 text-xs text-fg-muted">{{ t.blurb }}</p>
|
||||||
|
|
||||||
<ul class="mt-5 flex-1 space-y-2">
|
<ul class="mt-5 flex-1 space-y-2">
|
||||||
<li v-for="p in t.perks" :key="p" class="flex items-start gap-2 text-sm text-fg-muted">
|
<li v-for="p in t.perks" :key="p" class="flex items-start gap-2 text-sm text-fg-muted">
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,9 @@ const revPct = (id: string) =>
|
||||||
<span class="shrink-0 font-display text-lg font-semibold" :class="text[g.accent]">
|
<span class="shrink-0 font-display text-lg font-semibold" :class="text[g.accent]">
|
||||||
{{ fmtUsd(groupTotal(g)) }}
|
{{ fmtUsd(groupTotal(g)) }}
|
||||||
</span>
|
</span>
|
||||||
|
<span class="hidden shrink-0 text-[10px] uppercase tracking-wider text-fg-muted/70 sm:inline">
|
||||||
|
{{ selected === g.id ? 'Hide' : 'Tap to expand' }}
|
||||||
|
</span>
|
||||||
<Icon name="ChevronRight" class="size-4 shrink-0 text-fg-muted transition-transform" :class="selected === g.id ? 'rotate-90' : ''" />
|
<Icon name="ChevronRight" class="size-4 shrink-0 text-fg-muted transition-transform" :class="selected === g.id ? 'rotate-90' : ''" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { roadmap } from '../data'
|
||||||
<SlideFrame
|
<SlideFrame
|
||||||
kicker="The replication play"
|
kicker="The replication play"
|
||||||
title="Prove it three ways, then grow it anywhere"
|
title="Prove it three ways, then grow it anywhere"
|
||||||
subtitle="The three entities aren't the endgame — they're the seed. The blueprint is the business."
|
subtitle="The three entities aren't the endgame — they're the proof. The real business is the replicable blueprint: prove it once, then open new locations on the same backbone at marginal cost."
|
||||||
>
|
>
|
||||||
<ol class="relative grid gap-6 md:grid-cols-4">
|
<ol class="relative grid gap-6 md:grid-cols-4">
|
||||||
<!-- connecting line -->
|
<!-- connecting line -->
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ const icons = ['Building2', 'BedDouble', 'Cpu']
|
||||||
<SlideFrame
|
<SlideFrame
|
||||||
kicker="SolLunar Society · the building"
|
kicker="SolLunar Society · the building"
|
||||||
title="One address, three buildings"
|
title="One address, three buildings"
|
||||||
subtitle="A members' society up front, Cypherpunk Commons A & B behind — lodging, coworking and the data center that runs it all."
|
subtitle="A members' club building in front, with Cypherpunk Commons A & B in the back — lodging, coworking and the data center that runs it all."
|
||||||
>
|
>
|
||||||
<div class="grid gap-4 md:grid-cols-3">
|
<div class="grid gap-4 md:grid-cols-3">
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,14 @@ import PlaceholderBadge from '../components/PlaceholderBadge.vue'
|
||||||
import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert'
|
import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert'
|
||||||
import { brand, surfaceEntities, accentText } from '../data'
|
import { brand, surfaceEntities, accentText } from '../data'
|
||||||
import logoUrl from '@/deck/assets/logo.webp'
|
import logoUrl from '@/deck/assets/logo.webp'
|
||||||
|
|
||||||
|
// the "flowers" that grow from the Lab 484 soil — type + where each one lives,
|
||||||
|
// so a first-time reader immediately places them (incl. the French farm)
|
||||||
|
const flowerMeta: Record<string, { type: string; place: string }> = {
|
||||||
|
sollunar: { type: 'City', place: 'Austin, TX' },
|
||||||
|
summit: { type: 'Pop-up', place: 'Travelling' },
|
||||||
|
chateau: { type: 'Farm', place: 'S. France' },
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -37,19 +45,36 @@ import logoUrl from '@/deck/assets/logo.webp'
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-7 max-w-2xl text-balance text-xl text-fg sm:text-2xl">
|
<!-- wordmark: the mark reads "So·lL·unar" — spell it out so the lL ligature isn't misread -->
|
||||||
|
<p class="mt-5 font-display text-2xl font-semibold tracking-wide text-fg">
|
||||||
|
So<span class="text-amber">lL</span>unar
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="mt-4 max-w-2xl text-balance text-xl text-fg sm:text-2xl">
|
||||||
{{ brand.tagline }}
|
{{ brand.tagline }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- the three collaborating entities -->
|
<!-- the metaphor, made explicit: Lab 484 is the soil; three flowers grow from it -->
|
||||||
<div class="mt-10 flex flex-wrap items-center justify-center gap-x-3 gap-y-2 text-sm text-fg-muted">
|
<div class="mt-10 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-sm text-fg-muted">
|
||||||
<span class="uppercase tracking-[0.2em]">Three experiences, one backbone</span>
|
<span class="uppercase tracking-[0.2em]">Lab 484 is the soil</span>
|
||||||
|
<span class="text-fg-muted/50">— three flowers grow from it —</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 flex flex-wrap items-center justify-center gap-3">
|
<div class="mt-4 flex flex-wrap items-center justify-center gap-3">
|
||||||
<template v-for="(e, i) in surfaceEntities" :key="e.id">
|
<span
|
||||||
<span class="font-display text-lg font-semibold" :class="accentText[e.accent]">{{ e.name }}</span>
|
v-for="e in surfaceEntities"
|
||||||
<span v-if="i < surfaceEntities.length - 1" class="text-fg-muted">·</span>
|
:key="e.id"
|
||||||
</template>
|
class="flex flex-col items-center rounded-xl border border-line bg-surface px-4 py-2"
|
||||||
|
>
|
||||||
|
<span class="font-display text-base font-semibold" :class="accentText[e.accent]">{{ e.name }}</span>
|
||||||
|
<span class="text-[11px] uppercase tracking-wider text-fg-muted">
|
||||||
|
{{ flowerMeta[e.id].type }} · {{ flowerMeta[e.id].place }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<!-- room to grow: future flowers -->
|
||||||
|
<span class="flex flex-col items-center rounded-xl border border-dashed border-line-2 px-4 py-2 opacity-60">
|
||||||
|
<span class="font-display text-base font-semibold text-fg-muted">+ more</span>
|
||||||
|
<span class="text-[11px] uppercase tracking-wider text-fg-muted">Future flowers</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-8 max-w-xl text-balance text-sm text-fg-muted">
|
<p class="mt-8 max-w-xl text-balance text-sm text-fg-muted">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue