refactor(deck): model 3 collaborating entities under Solunar Punk Society

Reframe from one brand + two locations to a collaboration between
Archipelago (city center), Solunar Society (pop-up festivals) and
Chateau du Faune (farm center). Add entities[], the shared userEcosystem,
a 4th "shared core stack" cost category, and per-accent class helpers.
All figures remain placeholders.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-07-28 18:34:19 +02:00
commit b0a64502dc
5 changed files with 192 additions and 212 deletions

View file

@ -1,59 +0,0 @@
<script setup lang="ts">
import SlideFrame from './SlideFrame.vue'
import Icon from './Icon.vue'
import PlaceholderBadge from './PlaceholderBadge.vue'
import type { Location } from '../data'
const props = defineProps<{ location: Location; accent: 'pine' | 'clay' }>()
const tone =
props.accent === 'pine'
? { text: 'text-pine-300', chip: 'bg-pine-500/10 text-pine-300', ring: 'border-pine-500/30' }
: { text: 'text-clay-400', chip: 'bg-clay-400/10 text-clay-400', ring: 'border-clay-400/30' }
</script>
<template>
<SlideFrame :kicker="location.kind">
<div class="flex items-center gap-2">
<h2 class="font-display text-4xl font-semibold text-sand lg:text-5xl">{{ location.name }}</h2>
<PlaceholderBadge label="name" />
</div>
<p class="mt-4 max-w-2xl text-lg text-sand-dim">{{ location.blurb }}</p>
<div class="mt-10 grid gap-8 lg:grid-cols-[1fr_1fr]">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.2em]" :class="tone.text">
Why it matters
</p>
<ul class="mt-4 space-y-3">
<li
v-for="h in location.highlights"
:key="h"
class="flex items-start gap-3 text-sand-dim"
>
<span class="mt-1 grid size-5 shrink-0 place-items-center rounded-full" :class="tone.chip">
<Icon name="Check" class="size-3" />
</span>
{{ h }}
</li>
</ul>
</div>
<div class="rounded-2xl border p-6" :class="tone.ring">
<p class="text-xs font-semibold uppercase tracking-[0.2em]" :class="tone.text">
Spaces on site
</p>
<div class="mt-4 grid grid-cols-1 gap-2 sm:grid-cols-2">
<div
v-for="s in location.spaces"
:key="s"
class="flex items-center gap-2 rounded-lg bg-white/[0.03] px-3 py-2 text-sm text-sand"
>
<span class="size-1.5 rounded-full" :class="accent === 'pine' ? 'bg-pine-400' : 'bg-clay-400'" />
{{ s }}
</div>
</div>
</div>
</div>
</SlideFrame>
</template>

View file

@ -1,11 +1,17 @@
/**
* ARCHIPELAGO pitch deck content & figures.
* SOLUNAR PUNK SOCIETY pitch deck content & figures.
*
* EVERYTHING IN THIS FILE IS A PLACEHOLDER.
* This is the single source of truth for the deck. To turn the deck into
* the real pitch, edit values here no slide component hard-codes a number,
* a tier price, or a location name. Search for `PLACEHOLDER` to find every
* spot that needs your real data.
* a tier price, or an entity name. Search for `PLACEHOLDER` for every spot
* that needs your real data.
*
* The pitch is a collaboration between three entities, all running the same
* core stack + user ecosystem so members get the full experience anywhere:
* Archipelago hardware/software city center (the tech backbone)
* Solunar Society pop-up festivals (the ephemeral, travelling node)
* Chateau du Faune regenerative farm center (the rural node)
*
* Currency: all figures are USD unless noted.
*/
@ -13,14 +19,13 @@
export const PLACEHOLDER = true
export const brand = {
name: 'ARCHIPELAGO',
fullName: 'The Archipelago Network',
// archipelago = islands that look separate above the water but are joined
// beneath it — the network of self-sustaining locations, connected below.
tagline: 'A replicable network of decentralized, self-sustaining locations.',
name: 'Solunar Punk Society',
short: 'Solunar Punk',
// solarpunk by day, lunarpunk by night — sovereign tech, regenerative culture.
tagline: 'One sovereign network. Three ways to experience it.',
subtagline:
'Two proof-of-concept launches. Open hardware, sovereign software, real revenue — a blueprint anyone can deploy anywhere.',
contactEmail: 'invest@archipelago.example', // PLACEHOLDER
'A collaboration between Archipelago, Solunar Society and Chateau du Faune — every location runs the full core stack, so the membership, the payments and the experience travel with you.',
contactEmail: 'invest@solunarpunk.example', // PLACEHOLDER
// Seam for later: an LNbits instance + the founder's nostr npub power the
// "contribute" tiers. Left null until wired (see src/features/{lnbits,nostr}).
lnbitsBaseUrl: null as string | null,
@ -36,14 +41,123 @@ export const problem = {
'Every "smart" venue you can name is a walled garden that rents you access.',
],
thesis:
'We build physical nodes that own their own network, payments, and data — and prove they can pay for themselves.',
'We build sovereign places that own their network, payments and data — a city hub, a travelling festival, and a farm — all on one shared stack, each proving it can pay for itself.',
}
/** The technology stack shown on the Tech slide. */
export type Accent = 'pine' | 'indigo' | 'clay'
export type Entity = {
id: string
name: string
role: string // short label, e.g. "City center"
kind: string
accent: Accent
blurb: string
traits: string[] // what makes THIS entity unique
spaces: string[]
revenue: string[] // how this entity earns
icon: string
}
/** The three collaborating entities. PLACEHOLDER names & details. */
export const entities: Entity[] = [
{
id: 'archipelago',
name: 'Archipelago',
role: 'City center',
kind: 'Hardware & software hub · urban event space',
accent: 'pine',
blurb:
'The tech backbone of the collaboration: a downtown flagship where the stack is built, demonstrated and run in front of thousands.',
traits: [
'Builds & maintains the core stack every node runs',
'High-footfall public demonstration of the technology',
'Anchors partnerships, brand and the developer community',
],
spaces: ['Event hall', 'Co-working floor', 'Exchange kiosk', 'Café & bar', 'Studio / lab'],
revenue: ['Venue & desk hire', 'Events & workshops', 'Network & kiosk fees'],
icon: 'Building2',
},
{
id: 'solunar',
name: 'Solunar Society',
role: 'Pop-up festivals',
kind: 'Travelling · ephemeral gatherings',
accent: 'indigo',
blurb:
'The travelling node: solarpunk-by-day, lunarpunk-by-night festivals that deploy the entire stack anywhere for days at a time, then vanish.',
traits: [
'Deploys the full stack from a mobile kit — anywhere',
'Proves the network is portable, not tied to a building',
'Turns every festival into a member-onboarding event',
],
spaces: ['Main stage', 'Mobile exchange kiosk', 'Mesh & power rig', 'Camp & vendors', 'Workshop tents'],
revenue: ['Ticket sales', 'Vendor & bar revenue', 'Sponsorships'],
icon: 'Tent',
},
{
id: 'chateau',
name: 'Chateau du Faune',
role: 'Farm center',
kind: 'Off-grid · regenerative farm',
accent: 'clay',
blurb:
'The rural node: an off-grid regenerative farm hosting retreats, artist & developer residencies, and the networks living lab — home to the alpacas.',
traits: [
'Proves the stack runs off-grid, anywhere',
'Premium revenue from retreats & residencies',
'Sponsor-an-alpaca connects small backers to the land',
],
spaces: ['Retreat lodging', 'Residency studios', 'Event barn', 'Alpaca paddocks', 'Regenerative gardens'],
revenue: ['Lodging & retreats', 'Residencies', 'Experiences & venue hire'],
icon: 'Trees',
},
]
export const entityById = (id: string) => entities.find((e) => e.id === id)!
/**
* The user ecosystem every location shares the "full experience regardless
* of location" promise. This is what a member touches at any node.
*/
export const userEcosystem = [
{
title: 'One membership card',
body: 'A single NFC card is your identity, access and wallet at every node — city, festival or farm.',
icon: 'CreditCard',
},
{
title: 'Money exchange kiosk',
body: 'On-ramp cash to Bitcoin and back at any location. The same kiosk, everywhere.',
icon: 'Coins',
},
{
title: 'Pay by Lightning',
body: 'Tap to pay for drinks, tickets, rooms and experiences — instant, low-fee settlement.',
icon: 'Zap',
},
{
title: 'The Solunar app',
body: 'Book spaces, buy tickets, find events and manage membership from one self-hosted app.',
icon: 'Sparkles',
},
{
title: 'Portable identity',
body: 'Your nostr identity and social graph travel with you between every node and beyond.',
icon: 'KeyRound',
},
{
title: 'Member perks',
body: 'Access, discounts and priority booking that follow you across the whole network.',
icon: 'HeartHandshake',
},
]
/** The underlying technology / core stack (the infrastructure pillars). */
export const tech = [
{
title: 'Decentralized mesh network',
body: 'Community-owned routers and mesh kits blanket each location — connectivity that no single provider can switch off.',
body: 'Community-owned routers and mesh kits blanket each location — connectivity no single provider can switch off.',
icon: 'Wifi',
},
{
@ -53,11 +167,11 @@ export const tech = [
},
{
title: 'Sovereign software',
body: 'Self-hosted services on a stack you control — no platform lock-in, forkable by any future node.',
body: 'Self-hosted services on a stack we control — no platform lock-in, forkable by any future node.',
icon: 'Code',
},
{
title: 'Bitcoin & Lightning payments',
title: 'Bitcoin & Lightning',
body: 'Instant, low-fee settlement at kiosks and NFC points. Value stays in the network, not the middleman.',
icon: 'Zap',
},
@ -68,61 +182,19 @@ export const tech = [
},
{
title: 'Replicable blueprint',
body: 'Every node ships its own build docs. Proven once, the whole stack redeploys anywhere in the world.',
body: 'Every node ships its build docs. Proven once, the whole stack redeploys anywhere in the world.',
icon: 'Globe',
},
]
export type Location = {
id: string
name: string
kind: string
blurb: string
highlights: string[]
spaces: string[]
icon: string
}
/** The two proof-of-concept launches. PLACEHOLDER names & details. */
export const locations: Record<'city' | 'farm', Location> = {
city: {
id: 'city',
name: 'Isla Ciudad', // PLACEHOLDER — real city-node name
kind: 'Urban node · event space',
blurb:
'A downtown flagship: co-working, exchange kiosk, and a public-facing event venue that puts the technology in front of thousands.',
highlights: [
'High-footfall demonstration of the full stack',
'Exchange kiosk + NFC payments live to the public',
'Anchors the networks brand and partnerships',
],
spaces: ['Event hall', 'Co-working floor', 'Exchange kiosk', 'Café & bar', 'Studio / podcast room'],
icon: 'Building2',
},
farm: {
id: 'farm',
name: 'Isla Granja', // PLACEHOLDER — real farm-node name
kind: 'Rural node · regenerative farm',
blurb:
'An off-grid regenerative farm: retreats, artist & developer residencies, and the networks living lab — home to the alpacas.',
highlights: [
'Off-grid power + mesh proves the stack anywhere',
'Retreats & residencies generate premium revenue',
'Sponsor-an-alpaca connects small backers to the land',
],
spaces: ['Retreat lodging', 'Residency studios', 'Event barn', 'Alpaca paddocks', 'Regenerative gardens'],
icon: 'Trees',
},
}
/** Revenue streams the operational event spaces generate. */
/** Revenue streams across the collaboration. */
export const revenueStreams = [
{ title: 'Room & lodging rentals', note: 'Nightly stays across both nodes', icon: 'BedDouble' },
{ title: 'Experiences & workshops', note: 'Ticketed classes, tastings, tours', icon: 'Sparkles' },
{ title: 'Retreats', note: 'Multi-day hosted programs', icon: 'Mountain' },
{ title: 'Artist & developer residencies', note: 'Paid & sponsored residencies', icon: 'Palette' },
{ title: 'Event & venue hire', note: 'Weddings, launches, conferences', icon: 'PartyPopper' },
{ title: 'Network services', note: 'Connectivity, payments, kiosk fees', icon: 'Router' },
{ title: 'Tickets & festivals', note: 'Solunar Society gatherings', icon: 'Ticket' },
{ title: 'Room & lodging rentals', note: 'City & farm stays', icon: 'BedDouble' },
{ title: 'Retreats & residencies', note: 'Hosted programs at the farm', icon: 'Mountain' },
{ title: 'Experiences & workshops', note: 'Classes, tastings, tours', icon: 'Palette' },
{ title: 'Venue & event hire', note: 'Weddings, launches, conferences', icon: 'PartyPopper' },
{ title: 'Network services', note: 'Connectivity, kiosk & payment fees', icon: 'Router' },
]
export type CostItem = { label: string; amount: number; note?: string }
@ -131,32 +203,35 @@ export type CostCategory = {
title: string
subtitle: string
icon: string
accent: Accent | 'amber'
items: CostItem[]
}
/**
* The three investment cost categories. PLACEHOLDER amounts (USD).
* `total` is derived from items() below edit line items, not totals.
* Investment cost categories. PLACEHOLDER amounts (USD).
* One shared core stack + one build per entity.
*/
export const costCategories: CostCategory[] = [
{
id: 'core',
title: 'Base hardware & development',
subtitle: 'Servers, routers, exchange kiosks, NFC hardware + core dev salaries',
title: 'Shared core stack & development',
subtitle: 'Servers, routers, kiosks, NFC + core dev salaries — powers all three',
icon: 'Cpu',
accent: 'amber',
items: [
{ label: 'Edge servers & compute', amount: 60_000 },
{ label: 'Mesh routers & networking', amount: 45_000 },
{ label: 'Exchange kiosks', amount: 50_000, note: '2 units' },
{ label: 'NFC hardware & POS', amount: 25_000 },
{ label: 'Membership-card & NFC systems', amount: 25_000 },
{ label: 'Core development salaries', amount: 300_000, note: '4 engineers · 12 mo' },
],
},
{
id: 'city',
title: 'City location build',
subtitle: 'Fit-out & launch of the urban event node',
id: 'archipelago',
title: 'Archipelago · city center',
subtitle: 'Fit-out & launch of the urban hub',
icon: 'Building2',
accent: 'pine',
items: [
{ label: 'Lease deposit & permits', amount: 60_000 },
{ label: 'Renovation & fit-out', amount: 260_000 },
@ -166,10 +241,24 @@ export const costCategories: CostCategory[] = [
],
},
{
id: 'farm',
title: 'Farm location build',
subtitle: 'Land, structures & off-grid infrastructure for the rural node',
id: 'solunar',
title: 'Solunar Society · festivals',
subtitle: 'Mobile deployment kit + first-season production',
icon: 'Tent',
accent: 'indigo',
items: [
{ label: 'Mobile mesh & power rig', amount: 60_000 },
{ label: 'Mobile exchange kiosk & POS', amount: 45_000 },
{ label: 'Stage, structures & staging gear', amount: 70_000 },
{ label: 'First-season production & launch', amount: 45_000 },
],
},
{
id: 'chateau',
title: 'Chateau du Faune · farm center',
subtitle: 'Land, structures & off-grid infrastructure',
icon: 'Trees',
accent: 'clay',
items: [
{ label: 'Land improvements & access', amount: 90_000 },
{ label: 'Lodging & studio structures', amount: 300_000 },
@ -191,7 +280,7 @@ export type AngelTier = {
featured?: boolean
}
/** Angel investment — equity + benefits. PLACEHOLDER terms. */
/** Angel investment — equity + benefits across the collaboration. PLACEHOLDER terms. */
export const angelTiers: AngelTier[] = [
{
name: 'Seed Angel',
@ -199,7 +288,7 @@ export const angelTiers: AngelTier[] = [
equity: 'Equity from a common SAFE',
benefits: [
'Pro-rata equity in the network',
'Founding-member access to both nodes',
'Founding-member access to all three entities',
'Quarterly investor updates',
],
},
@ -211,7 +300,7 @@ export const angelTiers: AngelTier[] = [
benefits: [
'Everything in Seed, plus:',
'Advisory input on network direction',
'Complimentary retreat & residency weeks',
'Festival, retreat & residency weeks',
'Named node sponsor',
],
},
@ -242,7 +331,7 @@ export const contributorTiers: ContributorTier[] = [
{
name: 'Backer',
amount: 25,
blurb: 'Fund a member NFC card and get your name on the founders wall.',
blurb: 'Fund a member card and get your name on the founders wall.',
icon: 'CreditCard',
},
{
@ -254,7 +343,7 @@ export const contributorTiers: ContributorTier[] = [
{
name: 'Mesh Kit',
amount: 250,
blurb: 'Sponsor a full mesh kit that extends coverage across a location.',
blurb: 'Sponsor a full mesh kit that lights up a location — or a festival.',
icon: 'Wifi',
featured: true,
},
@ -262,7 +351,7 @@ export const contributorTiers: ContributorTier[] = [
name: 'Sponsor an Alpaca',
amount: 500,
unit: '/yr',
blurb: 'Name & sponsor an alpaca at the farm. Photos, updates, and a visit.',
blurb: 'Name & sponsor an alpaca at Chateau du Faune. Photos, updates, and a visit.',
icon: 'Origami',
},
]
@ -277,21 +366,21 @@ export const roadmap = [
},
{
phase: 'Phase 1',
title: 'Build the two nodes',
title: 'Launch the three entities',
when: '~69 mo',
body: 'Fit out the city node and the farm node in parallel; deploy the full stack.',
body: 'Fit out Archipelago and Chateau du Faune; stage the first Solunar festival.',
},
{
phase: 'Phase 2',
title: 'Operate & prove revenue',
when: '~918 mo',
body: 'Run events, retreats and residencies; validate the unit economics publicly.',
body: 'Run events, festivals, retreats and residencies; validate the unit economics publicly.',
},
{
phase: 'Phase 3',
title: 'Open the blueprint',
when: '18 mo+',
body: 'Publish the replication kit; onboard new nodes worldwide on shared infrastructure.',
body: 'Publish the replication kit; onboard new nodes & festivals worldwide on shared infrastructure.',
},
]
@ -302,3 +391,20 @@ export const fmtUsd = (n: number) =>
: `$${n.toLocaleString('en-US')}`
export const fmtUsdFull = (n: number) => `$${n.toLocaleString('en-US')}`
/** Tailwind class helpers keyed by entity accent — keeps slides declarative. */
export const accentText: Record<Accent, string> = {
pine: 'text-pine-300',
indigo: 'text-indigo-300',
clay: 'text-clay-400',
}
export const accentDot: Record<Accent, string> = {
pine: 'bg-pine-400',
indigo: 'bg-indigo-400',
clay: 'bg-clay-400',
}
export const accentRing: Record<Accent, string> = {
pine: 'border-pine-500/30 bg-pine-500/5',
indigo: 'border-indigo-500/30 bg-indigo-500/5',
clay: 'border-clay-400/30 bg-clay-400/5',
}

View file

@ -1,8 +0,0 @@
<script setup lang="ts">
import LocationDetail from '../components/LocationDetail.vue'
import { locations } from '../data'
</script>
<template>
<LocationDetail :location="locations.city" accent="pine" />
</template>

View file

@ -1,8 +0,0 @@
<script setup lang="ts">
import LocationDetail from '../components/LocationDetail.vue'
import { locations } from '../data'
</script>
<template>
<LocationDetail :location="locations.farm" accent="clay" />
</template>

View file

@ -1,51 +0,0 @@
<script setup lang="ts">
import SlideFrame from '../components/SlideFrame.vue'
import Icon from '../components/Icon.vue'
import PlaceholderBadge from '../components/PlaceholderBadge.vue'
import { locations } from '../data'
const list = [locations.city, locations.farm]
const accents = ['text-pine-300 border-pine-500/30 bg-pine-500/5', 'text-clay-400 border-clay-400/30 bg-clay-400/5']
</script>
<template>
<SlideFrame
kicker="Two proof-of-concept launches"
title="One network, two very different flowers"
subtitle="Deliberately opposite environments — an urban flagship and an off-grid farm — to prove the stack works anywhere."
>
<div class="grid gap-6 md:grid-cols-2">
<div
v-for="(loc, i) in list"
:key="loc.id"
class="flex flex-col rounded-2xl border p-6"
:class="accents[i]"
>
<div class="flex items-center gap-3">
<span class="grid size-11 place-items-center rounded-xl bg-white/5">
<Icon :name="loc.icon" class="size-6" />
</span>
<div>
<div class="flex items-center gap-2">
<h3 class="font-display text-2xl font-semibold text-sand">{{ loc.name }}</h3>
<PlaceholderBadge label="name" />
</div>
<p class="text-xs uppercase tracking-wider text-sand-dim">{{ loc.kind }}</p>
</div>
</div>
<p class="mt-4 text-sm leading-relaxed text-sand-dim">{{ loc.blurb }}</p>
<div class="mt-5 flex flex-wrap gap-2">
<span
v-for="s in loc.spaces"
:key="s"
class="rounded-full border border-white/10 bg-white/5 px-3 py-1 text-xs text-sand"
>
{{ s }}
</span>
</div>
</div>
</div>
</SlideFrame>
</template>