Compare commits

..

4 commits

Author SHA1 Message Date
Patrick Mulligan
55c2a1a4cf Rename remaining festival identifiers to summit
- Entity id 'festivals' -> 'summit' (data.ts) + lookups in
  gallery.ts and MyceliumNetwork.vue
- Mycelium flower kind 'festival' -> 'summit', summitCaps,
  .myc-summit class and comments

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 22:28:31 +02:00
Patrick Mulligan
3776ee1c49 Rename gallery festival -> summit; add real photos as webp
- Rename gallery folder festival/ -> summit/ and update gallery.ts
  (id, glob, variable, folder path) + README
- Add 10 Summit Gathering photos (STL_*, Speaker) converted to webp
- Add 1 City photo converted to webp
- Drop the summit placeholder SVGs now that real photos exist

Images resized to max 2048px @ q82 (140-280 KB each).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 22:24:03 +02:00
Patrick Mulligan
1c68b5b1b7 Apply founder slide-by-slide feedback
- Preserve "SolLunar" camel-case inside uppercase kickers/breadcrumb
  (new brandCaseParts helper; was rendering "SOLLUNAR")
- Slide 2: "work began" (not begun); clarify tenants = resident
  businesses (retailers, food co-ops, makers)
- Slide 3: bigger/bolder mycelium labels & zone captions
- Slide 4: spell out near-field communication (NFC); "we" -> "the user"
- Slide 9: membership prices $48/$148/$348; amenity examples
  (cold plunge, sauna, gym); Bitcoin ATM -> Bitcoin terminal
- Slide 10: Yellow Houses -> Cypherpunk Commons A & B; describe
  Outdoor/Office; VIP guest room -> Long-term guest housing
- Slide 13: P&L clearly labelled estimated/projected (recomputed
  from new prices: $65k rev / $31k profit / ~$372k yr)
- Slide 15: "Prove the model in Austin. Prove the replicability in
  France. Achieve decentralization."
- Sync PITCH-CONTENT.md to match

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 22:18:39 +02:00
Patrick Mulligan
3d0ee2f5c7 docs: add PITCH-CONTENT.md — full deck content as markdown
Slide-by-slide plain-text export of the deck (brand, problem, backbone,
entities, ownership, tenants, memberships, building, ecosystem, the
recomputed P&L, roadmap, and the two-option ask) for founders / AI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 02:52:30 +02:00
26 changed files with 370 additions and 133 deletions

272
PITCH-CONTENT.md Normal file
View file

@ -0,0 +1,272 @@
# SolLunar — Investment Pitch Deck (full content)
> Plain-text export of every slide's content from the SolLunar pitch deck, in
> presentation order. Intended for a founder to read or feed to an AI.
> Live deck: `aiolabs/sollunar-pitch`. Contact: **team@l484.com**
>
> **Brand note:** *SolLunar* is the cover brand (the venture / the raise).
> *Lab 484* is the shared tech backbone (open hardware + sovereign software)
> **and** a 45% operating partner. *SolLunar Punk Society (SPS)* is the other
> 45% partner (space + community). Tagline: *One network. Three ways to
> experience it.* / *Energy · Intelligence · Harmony.*
---
## 1 · Title
**SolLunar** — Investment prospectus (draft)
**One network. Three ways to experience it.**
A sovereign network on shared, open infrastructure. The first node — SolLunar
Society, a members' club in Austin — is live, modeled and raising now; the
summit gathering and the farm are next.
- **Three experiences, one backbone:** SolLunar Society · Pop-up Summit Gatherings · Château du Faune
- **Raising now · SolLunar Society · Austin, TX**
---
## 2 · The problem
**Transformation fades without the infrastructure to sustain it.**
- People leave transformational events inspired — then return to environments that don't support the change.
- There's no lasting home for sovereignty-minded community: dreamers, creatives, technologists, regenerative living.
- Peak experiences don't compound without ongoing relationships, education, and a place to practice.
**Thesis:** SolLunar Society is the missing infrastructure — a community hub
where the work began at transformational events continues through membership,
resident businesses (retailers, food co-ops and makers), events and
regenerative living.
---
## 3 · The network — a mycelial network
*What you see are the locations. What makes them work is the network beneath
them — and it grows the same way mycelium does: spread the network once, then
fruit anywhere.*
The diagram: an underground **mycelium = Lab 484**, the shared backbone
("the shared backbone beneath every node"), feeding three surface "flowers"
(the experiences people engage with) — **SolLunar Society** (city), **Pop-up
Summit Gatherings** (travelling), **Château du Faune** (farm) — plus faint
"future" blooms.
- **Lab 484 is the mycelium.** One shared backbone runs unseen beneath every entity — members feel it, they don't see it.
- **Take root anywhere.** Plug into a rich substrate of decentralized tech and grow your own flower — a city hub, a travelling summit gathering, a farm.
---
## 4 · Lab 484 · the shared backbone
**Open hardware, sovereign software.** Lab 484 is the stack under every entity
— owned by the network, documented to be rebuilt anywhere. Build it once; every
place plugs in.
- **Decentralized mesh network** — Community-owned routers and mesh kits blanket each location; connectivity no single provider can switch off.
- **Open hardware** — Servers, routers, exchange kiosks and near-field communication (NFC) hardware from a documented, replicable bill of materials.
- **Sovereign software** — Self-hosted services on a stack the user controls; no platform lock-in, forkable by any future node.
- **Bitcoin & Lightning** — Instant, low-fee settlement at kiosks and NFC points. Value stays in the network, not the middleman.
- **Nostr identity & comms** — Portable identity, messaging and social layer that travels with members across every node.
- **Replicable blueprint** — Every node ships its build docs. Proven once, the whole stack redeploys anywhere in the world.
---
## 5 · Three experiences, one backbone
*One is funded and opening now — SolLunar Society in Austin. The summit
gathering and the farm follow, on the same Lab 484 stack.*
- **SolLunar Society** — City center · the first node (Members' club & community hub · Austin, TX). *The first node and the one we're raising for: a members' club in Austin where sovereignty-minded community — tenants, events, memberships and regenerative living — comes together year-round on the Lab 484 stack.* — **Live P&L · this raise.**
- **Pop-up Summit Gatherings** — Travelling gatherings (e.g. Solar Punk Summit). *A repeatable summit-gathering format that deploys the entire stack anywhere for a few days, then packs down and moves on.* — Vision · on the roadmap.
- **Château du Faune** — Farm center (off-grid · regenerative farm). *An off-grid regenerative farm hosting retreats, artist & developer residencies, and the network's living lab — home to the alpacas.* — Vision · on the roadmap.
**Beneath all three — Lab 484 · Shared backbone:** the invisible foundation every
entity runs on: open hardware and self-hosted software — the mycelium beneath the
whole network. Build it once, and every place plugs in.
---
## 6 · SolLunar Society (the first node)
**Members' club & community hub · Austin, TX** — the first node and the one
we're raising for.
**What makes it unique**
- Live, financially-modeled first node (real P&L)
- Five founding tenants + a three-tier membership
- Bitcoin terminal, vending & the full member ecosystem on site
**Spaces:** Retail space · Event space · Private lounge · Co-working · Cypherpunk Commons hostel & data center
**How it earns:** Memberships · Tenants · Events & venue buyouts
---
## 7 · Ownership — a three-way partnership
SolLunar Society is a joint venture — investors buy in alongside the two
founding partners.
| Entity | Stake |
| --- | --- |
| **SolLunar Punk Society (SPS)** | **45%** |
| **Lab 484** | **45%** |
| **Investors** | **10%** |
**The ask (base):** $400k for 10% · $4.0MM valuation.
*(Partner responsibilities, per the source plan — not yet solidified, shown for
context only: SPS → space, community, leasing, insurance, SOPs, marketing.
Lab 484 → operations, staff, all IT/infrastructure, inbound payments, bootcamps,
tenant & investor relations; note that Lab 484 is also a tenant + event driver,
contributing ~$16k/mo of the revenue below — don't double-count.)*
---
## 8 · Five founding tenants
The hub is anchored by businesses that are also the community — each one a
reason to become a member.
- **Lab 484** — Research lab & startup cluster building a "second internet": Bitcoin, mesh networks, Nostr, e-cash and P2P. User-owned hardware, software and data.
- **Solarpunk Summit** — Transformational platform & community builder: immersive experiences, educational programming and regenerative culture.
- **Noderunners Shop** — Retail for AI computers, mesh gear, Bitcoin nodes and repair. Open-source, secure laptops, phones and servers.
- **Divine Provisions** — A food co-op for low-cost, organic, local groceries — offered as a member service at the building entrance.
- **Kitchen 484** — Community food truck: organic, seed-oil-free, locally sourced. Runs even when disconnected from the internet.
*Tenants pay rent and drive events, retail and food traffic — the same footfall that fills memberships.*
---
## 9 · Memberships — three ways to belong
Recurring membership is the core of the model — priced right for the Austin market.
| Tier | Price / mo | Target members | Includes |
| --- | --- | --- | --- |
| **Solarpunk Society** | $48 | 150 | Member events; amenities (cold plunge, sauna & gym); vending & Bitcoin terminal; access to tenants |
| **Lunarpunk Locals** | $148 | 100 | Coworking days at SolLunar; amenities (cold plunge, sauna & gym); vending & Bitcoin terminal; access to tenants |
| **Cypherpunk Commons** *(flagship)* | $348 | 50 | Coworking with the Lab 484 team; all locations · tech support; cold plunge, sauna, gym & coworking; vending, coffee, tea & Bitcoin terminal; full tenant & amenity access |
**Austin comparables:** Soho House $350 · Bond Collective $300 · Bathe $200 · Stardust Garage $155 · Submersive $41
---
## 10 · The building — one address, three buildings
A members' society up front, Cypherpunk Commons A & B behind — lodging, coworking
and the data center that runs it all. *The Cypherpunk Commons data center makes
SolLunar self-hosting — the Lab 484 stack runs on-site, not in someone else's cloud.*
- **SolLunar Society** — Retail space · Event space · Private office · Private lounge
- **Cypherpunk Commons A** — Hostel room ($40/night) · Healer room · Coworking · Meeting room · Outdoor (activity space, food truck & café)
- **Cypherpunk Commons B** — Long-term guest housing · Office (coworking with amenities) · Data center · Outdoor (activity space, food truck & café)
---
## 11 · Gallery
Photography from each entity — City (SolLunar Society), Farm (Château du Faune),
Summit Gathering. *(Images live in the deck; drop files into the matching folder
and they appear automatically.)*
---
## 12 · One membership, everywhere
**The same full experience, at every location.** Wherever you are in the network
— city, summit gathering or farm — the ecosystem is identical. Your card, your
money, your identity travel with you.
- **One membership card** — A single NFC card is your identity, access and wallet everywhere.
- **Money exchange kiosk** — On-ramp cash to Bitcoin and back at any location. The same kiosk, everywhere.
- **Pay by Lightning** — Tap to pay for drinks, tickets, rooms and experiences — instant, low-fee settlement.
- **The Lab 484 app** — Book spaces, buy tickets, find events and manage membership from one self-hosted app.
- **Portable identity** — Your nostr identity and social graph travel with you between every node and beyond.
- **Member perks** — Access, discounts and priority booking that follow you across the whole network.
---
## 13 · The numbers — SolLunar Society unit economics
**Estimated monthly** P&L for the Austin node — projections, not audited results.
*(Figures recomputed from the source plan's line items; the source summary table
stated $71.4k rev / $38.5k exp, which didn't reconcile — see the caveat below.)*
**Summary (recomputed):**
| | Monthly | Yearly |
| --- | --- | --- |
| **Revenue** | **$65,000** | $780,000 |
| **Expenses** | **$34,000** | $408,000 |
| **Net profit** | **$31,000** | **~$372,000** |
**Revenue — Memberships ($36,100/mo)**
- Cypherpunk Commons — $17,400 (50 × $348)
- Solarpunk Society — $7,200 (150 × $48)
- Lunarpunk Locals — $1,500 ($148/mo · count TBD)
- Vending machine sales — $5,000
- Promo / B2B network sales — $5,000
**Revenue — Events ($21,900/mo)**
- Lab 484 tech events — $8,000
- Lab 484 bootcamps — $6,000
- Venue buyouts — $6,400 ($400/hr · 4hr min · 4×/mo)
- SolLunar Society events — $1,500 ($50 weekend passes)
**Revenue — Tenants ($7,000/mo)**
- Solarpunk Summit — $2,000
- Lab 484 — $2,000
- Divine Provisions — $1,500
- Noderunners Shop — $1,500
**Expenses ($34,000/mo)**
- Staff — $22,500 (4 staff)
- Rent — $6,500 ($4,500 + triple net)
- Overhead — $3,000
- Utilities — $2,000 (electric, water, trash)
> ⚠️ **These are estimated figures — projections, not audited results.** The
> source doc's summary table stated $71,400 revenue / $38,500 expenses / $32,900
> profit / $394,800/yr, which does **not** match the line items above (line items
> give $65,000 / $34,000 / $31,000 / $372,000). Also, **Lunarpunk Locals** income
> ($1,500) doesn't match its "100 × $148" annotation. Numbers here use the
> line-item recomputation.
---
## 14 · Roadmap — the replication play
**Prove it three ways, then grow it anywhere.** The three entities aren't the
endgame — they're the seed. The blueprint is the business.
- **Phase 0 · Now — Raise & open SolLunar:** Close the $400k round, sign the lease, fit out the space and onboard the founding tenants.
- **Phase 1 · ~012 mo — Operate & prove the model:** Run memberships, events and tenants in Austin; validate the P&L publicly on the Lab 484 stack.
- **Phase 2 · ~1218 mo — Add the summit gathering:** Deploy the same stack to a travelling Solarpunk Summit — proving the network is portable, not tied to a building.
- **Phase 3 · 18 mo+ — Add the farm & replicate:** Open Château du Faune and publish the replication kit — new nodes plug into the same backbone anywhere.
*Once the mycelium runs, every new flower is marginal cost, not a new company.*
---
## 15 · The ask — two ways in
Invest in SolLunar Society — the first node, opening in Austin.
| Option | Amount | Equity | Annual profit share¹ | What it funds |
| --- | --- | --- | --- | --- |
| **Get started** | $400k | 10% | ~$37,200 / yr | Seeds the launch — sign the lease, fit out the space and open the doors. |
| **Full execution** *(full build)* | $900k | 25% | ~$93,000 / yr | Funds the full build-out and the first operating year end to end. |
¹ On SolLunar Society's estimated ~$372,000/yr node profit.
- **Prove the model in Austin. Prove the replicability in France. Achieve decentralization.**
- **Contact:** team@l484.com · Book an investor call
---
*Generated from the deck's single source of truth (`src/deck/data.ts`) plus slide
copy. Figures are the current placeholders/recomputations in the deck — verify
against the latest SolLunar Society business plan before circulating externally.*

View file

@ -2,7 +2,7 @@
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { ChevronLeft, ChevronRight, Sun, Moon } from '@lucide/vue' import { ChevronLeft, ChevronRight, Sun, Moon } from '@lucide/vue'
import { useDeck } from './useDeck' import { useDeck } from './useDeck'
import { brand } from './data' import { brand, brandCaseParts } from './data'
import markUrl from '@/deck/assets/mark.png' import markUrl from '@/deck/assets/mark.png'
// theme: dark by default, persisted; a single `.dark` class flips every token // theme: dark by default, persisted; a single `.dark` class flips every token
@ -79,7 +79,9 @@ function onTouchEnd(e: TouchEvent) {
<span class="font-display text-sm font-semibold tracking-wide text-fg">SolLunar</span> <span class="font-display text-sm font-semibold tracking-wide text-fg">SolLunar</span>
</span> </span>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="text-xs uppercase tracking-[0.2em]">{{ current.label }}</span> <span class="text-xs uppercase tracking-[0.2em]">
<span v-for="p in brandCaseParts(current.label)" :key="p.id" :class="{ 'normal-case': p.keep }">{{ p.text }}</span>
</span>
<button <button
class="pointer-events-auto grid size-8 place-items-center rounded-full border border-line bg-surface-2 text-fg transition hover:bg-surface-3" class="pointer-events-auto grid size-8 place-items-center rounded-full border border-line bg-surface-2 text-fg transition hover:bg-surface-3"
:aria-label="dark ? 'Switch to light mode' : 'Switch to dark mode'" :aria-label="dark ? 'Switch to light mode' : 'Switch to dark mode'"

View file

@ -73,21 +73,21 @@ function thread([a, b]: [number, number], i: number) {
} }
const sol = entityById('sollunar') // city const sol = entityById('sollunar') // city
const fest = entityById('festivals') // travelling const fest = entityById('summit') // travelling
const cha = entityById('chateau') // farm const cha = entityById('chateau') // farm
// surface flowers: the three experiences + two faint "future" ones. // surface flowers: the three experiences + two faint "future" ones.
// (Lab 484 is the mycelium itself the network below, not a flower.) // (Lab 484 is the mycelium itself the network below, not a flower.)
const flowers = [ const flowers = [
{ x: 230, kind: 'bloom', color: 'var(--color-indigo)', name: sol.name, tag: sol.role }, { x: 230, kind: 'bloom', color: 'var(--color-indigo)', name: sol.name, tag: sol.role },
{ x: 500, kind: 'festival', color: 'var(--color-rose)', name: fest.name, tag: fest.role }, { x: 500, kind: 'summit', color: 'var(--color-rose)', name: fest.name, tag: fest.role },
{ x: 770, kind: 'bloom', color: 'var(--color-clay)', name: cha.name, tag: cha.role }, { x: 770, kind: 'bloom', color: 'var(--color-clay)', name: cha.name, tag: cha.role },
{ x: 100, kind: 'ghost' }, { x: 100, kind: 'ghost' },
{ x: 900, kind: 'ghost' }, { x: 900, kind: 'ghost' },
] as const ] as const
// small pop-up caps for the ephemeral festival flower // small pop-up caps for the ephemeral summit flower
const festivalCaps = [ const summitCaps = [
{ dx: -18, dy: -58, r: 15 }, { dx: -18, dy: -58, r: 15 },
{ dx: 0, dy: -74, r: 20 }, { dx: 0, dy: -74, r: 20 },
{ dx: 20, dy: -60, r: 14 }, { dx: 20, dy: -60, r: 14 },
@ -196,8 +196,8 @@ const festivalCaps = [
<circle :cx="f.x + 12" :cy="GROUND - 92" r="2.4" fill="hsl(0 0% 100% / 0.45)" /> <circle :cx="f.x + 12" :cy="GROUND - 92" r="2.4" fill="hsl(0 0% 100% / 0.45)" />
</template> </template>
<!-- ephemeral festival cluster (SolLunar) --> <!-- ephemeral summit cluster (SolLunar) -->
<template v-else-if="f.kind === 'festival'"> <template v-else-if="f.kind === 'summit'">
<path <path
:d="`M ${f.x} ${GROUND} C ${f.x - 6} ${GROUND - 20}, ${f.x + 6} ${GROUND - 34}, ${f.x} ${GROUND - 46}`" :d="`M ${f.x} ${GROUND} C ${f.x - 6} ${GROUND - 20}, ${f.x + 6} ${GROUND - 34}, ${f.x} ${GROUND - 46}`"
fill="none" fill="none"
@ -207,8 +207,8 @@ const festivalCaps = [
stroke-linecap="round" stroke-linecap="round"
stroke-dasharray="3 5" stroke-dasharray="3 5"
/> />
<g class="myc-festival" :style="{ animationDelay: `${i * 0.3}s` }"> <g class="myc-summit" :style="{ animationDelay: `${i * 0.3}s` }">
<template v-for="(c, ci) in festivalCaps" :key="ci"> <template v-for="(c, ci) in summitCaps" :key="ci">
<path <path
:d="`M ${f.x + c.dx - c.r} ${GROUND + c.dy} Q ${f.x + c.dx} ${GROUND + c.dy - c.r * 1.1} ${f.x + c.dx + c.r} ${GROUND + c.dy} Q ${f.x + c.dx} ${GROUND + c.dy - c.r * 0.28} ${f.x + c.dx - c.r} ${GROUND + c.dy} Z`" :d="`M ${f.x + c.dx - c.r} ${GROUND + c.dy} Q ${f.x + c.dx} ${GROUND + c.dy - c.r * 1.1} ${f.x + c.dx + c.r} ${GROUND + c.dy} Q ${f.x + c.dx} ${GROUND + c.dy - c.r * 0.28} ${f.x + c.dx - c.r} ${GROUND + c.dy} Z`"
:fill="f.color" :fill="f.color"
@ -255,7 +255,7 @@ const festivalCaps = [
<template v-if="f.kind !== 'ghost'"> <template v-if="f.kind !== 'ghost'">
<text <text
:x="f.x" :x="f.x"
:y="f.kind === 'festival' ? GROUND - 122 : GROUND - 132" :y="f.kind === 'summit' ? GROUND - 122 : GROUND - 132"
text-anchor="middle" text-anchor="middle"
class="myc-label-name" class="myc-label-name"
:fill="f.color" :fill="f.color"
@ -264,7 +264,7 @@ const festivalCaps = [
</text> </text>
<text <text
:x="f.x" :x="f.x"
:y="f.kind === 'festival' ? GROUND - 142 : GROUND - 152" :y="f.kind === 'summit' ? GROUND - 142 : GROUND - 152"
text-anchor="middle" text-anchor="middle"
class="myc-label-tag" class="myc-label-tag"
> >
@ -300,19 +300,22 @@ const festivalCaps = [
<style scoped> <style scoped>
.myc-label-name { .myc-label-name {
font-family: var(--font-display); font-family: var(--font-display);
font-size: 17px; font-size: 19px;
font-weight: 600; font-weight: 700;
} }
.myc-label-tag { .myc-label-tag {
font-size: 10px; font-size: 12.5px;
letter-spacing: 0.22em; font-weight: 600;
fill: var(--color-fg-muted); letter-spacing: 0.16em;
fill: var(--color-fg);
opacity: 0.85;
} }
.myc-zone { .myc-zone {
font-size: 11px; font-size: 13px;
letter-spacing: 0.24em; font-weight: 600;
fill: var(--color-fg-muted); letter-spacing: 0.18em;
opacity: 0.7; fill: var(--color-fg);
opacity: 0.8;
} }
.myc-pulse { .myc-pulse {
@ -360,8 +363,8 @@ const festivalCaps = [
} }
} }
/* festival cluster gently floats + fades — it's ephemeral */ /* summit cluster gently floats + fades — it's ephemeral */
.myc-festival { .myc-summit {
transform-box: fill-box; transform-box: fill-box;
transform-origin: bottom center; transform-origin: bottom center;
animation: myc-float 4.5s ease-in-out infinite; animation: myc-float 4.5s ease-in-out infinite;
@ -397,7 +400,7 @@ const festivalCaps = [
.myc-pulse, .myc-pulse,
.myc-node, .myc-node,
.myc-cap, .myc-cap,
.myc-festival, .myc-summit,
.myc-plus { .myc-plus {
animation: none; animation: none;
} }

View file

@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
/** Shared slide chrome: consistent padding, kicker, title, subtitle + body slot. */ /** Shared slide chrome: consistent padding, kicker, title, subtitle + body slot. */
import { brandCaseParts } from '../data'
defineProps<{ defineProps<{
kicker?: string kicker?: string
title?: string title?: string
@ -17,7 +19,7 @@ defineProps<{
v-if="kicker" v-if="kicker"
class="mb-3 text-xs font-semibold uppercase tracking-[0.25em] text-amber" class="mb-3 text-xs font-semibold uppercase tracking-[0.25em] text-amber"
> >
{{ kicker }} <span v-for="p in brandCaseParts(kicker)" :key="p.id" :class="{ 'normal-case': p.keep }">{{ p.text }}</span>
</p> </p>
<h2 <h2
v-if="title" v-if="title"

View file

@ -44,7 +44,7 @@ export const problem = {
'Peak experiences dont compound without ongoing relationships, education, and a place to practice.', 'Peak experiences dont compound without ongoing relationships, education, and a place to practice.',
], ],
thesis: thesis:
'SolLunar Society is the missing infrastructure — a community hub where the work begun at transformational events continues through membership, tenants, events and regenerative living.', 'SolLunar Society is the missing infrastructure — a community hub where the work began at transformational events continues through membership, resident businesses (retailers, food co-ops and makers), events and regenerative living.',
} }
export type Accent = 'pine' | 'indigo' | 'rose' | 'clay' export type Accent = 'pine' | 'indigo' | 'rose' | 'clay'
@ -81,14 +81,14 @@ export const entities: Entity[] = [
traits: [ traits: [
'Live, financially-modeled first node (real P&L)', 'Live, financially-modeled first node (real P&L)',
'Five founding tenants + a three-tier membership', 'Five founding tenants + a three-tier membership',
'Bitcoin ATM, vending & the full member ecosystem on site', 'Bitcoin terminal, vending & the full member ecosystem on site',
], ],
spaces: ['Retail space', 'Event space', 'Private lounge', 'Co-working', 'Yellow House hostel & data center'], spaces: ['Retail space', 'Event space', 'Private lounge', 'Co-working', 'Cypherpunk Commons hostel & data center'],
revenue: ['Memberships', 'Tenants', 'Events & venue buyouts'], revenue: ['Memberships', 'Tenants', 'Events & venue buyouts'],
icon: 'Building2', icon: 'Building2',
}, },
{ {
id: 'festivals', id: 'summit',
name: 'Pop-up Summit Gatherings', name: 'Pop-up Summit Gatherings',
role: 'Travelling gatherings', role: 'Travelling gatherings',
kind: 'Travelling · ephemeral', kind: 'Travelling · ephemeral',
@ -194,12 +194,12 @@ export const tech = [
}, },
{ {
title: 'Open hardware', title: 'Open hardware',
body: 'Servers, routers, exchange kiosks and NFC hardware from a documented, replicable bill of materials.', body: 'Servers, routers, exchange kiosks and near-field communication (NFC) hardware from a documented, replicable bill of materials.',
icon: 'Cpu', icon: 'Cpu',
}, },
{ {
title: 'Sovereign software', title: 'Sovereign software',
body: 'Self-hosted services on a stack we control — no platform lock-in, forkable by any future node.', body: 'Self-hosted services on a stack the user controls — no platform lock-in, forkable by any future node.',
icon: 'Code', icon: 'Code',
}, },
{ {
@ -324,30 +324,41 @@ export type Membership = {
export const memberships: Membership[] = [ export const memberships: Membership[] = [
{ {
name: 'Solarpunk Society', name: 'Solarpunk Society',
price: 50, price: 48,
target: 150, target: 150,
blurb: 'Events access.', blurb: 'Events access.',
perks: ['Member events', 'Amenities, vending & Bitcoin ATM', 'Access to tenants'], perks: [
'Member events',
'Amenities: cold plunge, sauna & gym',
'Vending & Bitcoin terminal',
'Access to tenants',
],
}, },
{ {
name: 'Cypherpunk Commons', name: 'Cypherpunk Commons',
price: 350, price: 348,
target: 50, target: 50,
featured: true, featured: true,
blurb: 'Full access, all locations.', blurb: 'Full access, all locations.',
perks: [ perks: [
'Coworking with the Lab 484 team', 'Coworking with the Lab 484 team',
'All locations · tech support', 'All locations · tech support',
'Bitcoin ATM, vending, coffee & tea', 'Cold plunge, sauna, gym & coworking',
'Vending, coffee, tea & Bitcoin terminal',
'Full tenant & amenity access', 'Full tenant & amenity access',
], ],
}, },
{ {
name: 'Lunarpunk Locals', name: 'Lunarpunk Locals',
price: 150, price: 148,
target: 100, target: 100,
blurb: 'Coworking days.', blurb: 'Coworking days.',
perks: ['Coworking days at SolLunar', 'Access to tenants', 'Amenities, vending & Bitcoin ATM'], perks: [
'Coworking days at SolLunar',
'Amenities: cold plunge, sauna & gym',
'Vending & Bitcoin terminal',
'Access to tenants',
],
}, },
] ]
@ -384,9 +395,9 @@ export const pnlGroups: PnlGroup[] = [
accent: 'indigo', accent: 'indigo',
kind: 'revenue', kind: 'revenue',
items: [ items: [
{ label: 'Cypherpunk Commons', amount: 17_500, note: '50 × $350' }, { label: 'Cypherpunk Commons', amount: 17_400, note: '50 × $348' },
{ label: 'Solarpunk Society', amount: 7_500, note: '150 × $50' }, { label: 'Solarpunk Society', amount: 7_200, note: '150 × $48' },
{ label: 'Lunarpunk Locals', amount: 1_500, note: '$150/mo · count TBD' }, { label: 'Lunarpunk Locals', amount: 1_500, note: '$148/mo · count TBD' },
{ label: 'Vending machine sales', amount: 5_000 }, { label: 'Vending machine sales', amount: 5_000 },
{ label: 'Promo / B2B network sales', amount: 5_000 }, { label: 'Promo / B2B network sales', amount: 5_000 },
], ],
@ -453,12 +464,23 @@ export const buildings = [
rooms: ['Retail space', 'Event space', 'Private office', 'Private lounge'], rooms: ['Retail space', 'Event space', 'Private office', 'Private lounge'],
}, },
{ {
name: 'Lab 484 · Yellow House 1', name: 'Cypherpunk Commons A',
rooms: ['Hostel room · $40/night', 'Healer room', 'Coworking', 'Meeting room', 'Outdoor'], rooms: [
'Hostel room · $40/night',
'Healer room',
'Coworking',
'Meeting room',
'Outdoor · activity space, food truck & café',
],
}, },
{ {
name: 'Lab 484 · Yellow House 2', name: 'Cypherpunk Commons B',
rooms: ['VIP guest room', 'Office', 'Data center', 'Outdoor'], rooms: [
'Long-term guest housing',
'Office · coworking with amenities',
'Data center',
'Outdoor · activity space, food truck & café',
],
}, },
] ]
@ -520,6 +542,16 @@ export const fmtUsd = (n: number) => {
export const fmtUsdFull = (n: number) => `$${n.toLocaleString('en-US')}` export const fmtUsdFull = (n: number) => `$${n.toLocaleString('en-US')}`
/**
* Split a label so the "SolLunar" brand keeps its camel-case even inside a
* CSS `uppercase` eyebrow the `keep` parts get `normal-case`.
*/
export const brandCaseParts = (text: string) =>
text
.split(/(SolLunar)/)
.filter(Boolean)
.map((t, i) => ({ id: i, text: t, keep: t === 'SolLunar' }))
/** Tailwind class helpers keyed by entity accent — keeps slides declarative. */ /** Tailwind class helpers keyed by entity accent — keeps slides declarative. */
export const accentText: Record<Accent, string> = { export const accentText: Record<Accent, string> = {
pine: 'text-pine-300', pine: 'text-pine-300',

View file

@ -6,7 +6,7 @@
* *
* src/deck/gallery/city/ City (SolLunar Punk Society) * src/deck/gallery/city/ City (SolLunar Punk Society)
* src/deck/gallery/farm/ Farm (Château du Faune) * src/deck/gallery/farm/ Farm (Château du Faune)
* src/deck/gallery/festival/ Summit Gathering (Pop-up Summit Gatherings) * src/deck/gallery/summit/ Summit Gathering (Pop-up Summit Gatherings)
* *
* Supported: jpg jpeg png webp avif gif svg. Images show sorted by filename, * Supported: jpg jpeg png webp avif gif svg. Images show sorted by filename,
* so prefix with 01-, 02-, to control order. The seeded *-placeholder.svg * so prefix with 01-, 02-, to control order. The seeded *-placeholder.svg
@ -31,7 +31,7 @@ const farm = import.meta.glob('./gallery/farm/*.{jpg,jpeg,png,webp,avif,gif,svg}
query: '?url', query: '?url',
import: 'default', import: 'default',
}) as GlobMap }) as GlobMap
const festival = import.meta.glob('./gallery/festival/*.{jpg,jpeg,png,webp,avif,gif,svg}', { const summit = import.meta.glob('./gallery/summit/*.{jpg,jpeg,png,webp,avif,gif,svg}', {
eager: true, eager: true,
query: '?url', query: '?url',
import: 'default', import: 'default',
@ -46,7 +46,7 @@ function toImages(map: GlobMap): GalleryImage[] {
} }
export type GallerySection = { export type GallerySection = {
id: 'city' | 'farm' | 'festival' id: 'city' | 'farm' | 'summit'
label: string label: string
entityName: string entityName: string
accent: Accent accent: Accent
@ -72,11 +72,11 @@ export const gallerySections: GallerySection[] = [
images: toImages(farm), images: toImages(farm),
}, },
{ {
id: 'festival', id: 'summit',
label: 'Summit Gathering', label: 'Summit Gathering',
entityName: entityById('festivals').name, entityName: entityById('summit').name,
accent: 'rose', accent: 'rose',
folder: 'src/deck/gallery/festival/', folder: 'src/deck/gallery/summit/',
images: toImages(festival), images: toImages(summit),
}, },
] ]

View file

@ -7,7 +7,7 @@ they appear automatically** — no code to touch.
| ----------- | -------- | --------------------- | | ----------- | -------- | --------------------- |
| `city/` | City | SolLunar Punk Society | | `city/` | City | SolLunar Punk Society |
| `farm/` | Farm | Château du Faune | | `farm/` | Farm | Château du Faune |
| `festival/` | Summit Gathering | Pop-up Summit Gatherings | | `summit/` | Summit Gathering | Pop-up Summit Gatherings |
- Supported formats: `jpg` `jpeg` `png` `webp` `avif` `gif` `svg`. - Supported formats: `jpg` `jpeg` `png` `webp` `avif` `gif` `svg`.
- Images display **sorted by filename** — prefix `01-`, `02-`, … to order them. - Images display **sorted by filename** — prefix `01-`, `02-`, … to order them.

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View file

@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" width="800" height="800" font-family="Georgia, serif">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="hsl(256 78% 68%)" stop-opacity="0.40"/>
<stop offset="1" stop-color="hsl(160 28% 6%)" stop-opacity="1"/>
</linearGradient>
</defs>
<rect width="800" height="800" fill="hsl(160 28% 6%)"/>
<rect width="800" height="800" fill="url(#g)"/>
<circle cx="740" cy="60" r="120" fill="hsl(256 78% 68%)" opacity="0.12"/>
<circle cx="70" cy="730" r="90" fill="hsl(256 78% 68%)" opacity="0.10"/>
<text x="400" y="360" text-anchor="middle" fill="hsl(256 78% 68%)" font-size="46" font-weight="bold">Summit Gathering</text>
<text x="400" y="406" text-anchor="middle" fill="hsl(44 30% 90%)" font-size="26" opacity="0.85">Photo 01</text>
<text x="400" y="444" text-anchor="middle" fill="hsl(150 8% 62%)" font-size="18" letter-spacing="3">PLACEHOLDER · 800×800</text>
</svg>

Before

Width:  |  Height:  |  Size: 1,000 B

View file

@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 560" width="800" height="560" font-family="Georgia, serif">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="hsl(256 78% 68%)" stop-opacity="0.40"/>
<stop offset="1" stop-color="hsl(160 28% 6%)" stop-opacity="1"/>
</linearGradient>
</defs>
<rect width="800" height="560" fill="hsl(160 28% 6%)"/>
<rect width="800" height="560" fill="url(#g)"/>
<circle cx="740" cy="60" r="120" fill="hsl(256 78% 68%)" opacity="0.12"/>
<circle cx="70" cy="490" r="90" fill="hsl(256 78% 68%)" opacity="0.10"/>
<text x="400" y="240" text-anchor="middle" fill="hsl(256 78% 68%)" font-size="46" font-weight="bold">Summit Gathering</text>
<text x="400" y="286" text-anchor="middle" fill="hsl(44 30% 90%)" font-size="26" opacity="0.85">Photo 02</text>
<text x="400" y="324" text-anchor="middle" fill="hsl(150 8% 62%)" font-size="18" letter-spacing="3">PLACEHOLDER · 800×560</text>
</svg>

Before

Width:  |  Height:  |  Size: 1,000 B

View file

@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 1040" width="800" height="1040" font-family="Georgia, serif">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="hsl(256 78% 68%)" stop-opacity="0.40"/>
<stop offset="1" stop-color="hsl(160 28% 6%)" stop-opacity="1"/>
</linearGradient>
</defs>
<rect width="800" height="1040" fill="hsl(160 28% 6%)"/>
<rect width="800" height="1040" fill="url(#g)"/>
<circle cx="740" cy="60" r="120" fill="hsl(256 78% 68%)" opacity="0.12"/>
<circle cx="70" cy="970" r="90" fill="hsl(256 78% 68%)" opacity="0.10"/>
<text x="400" y="480" text-anchor="middle" fill="hsl(256 78% 68%)" font-size="46" font-weight="bold">Summit Gathering</text>
<text x="400" y="526" text-anchor="middle" fill="hsl(44 30% 90%)" font-size="26" opacity="0.85">Photo 03</text>
<text x="400" y="564" text-anchor="middle" fill="hsl(150 8% 62%)" font-size="18" letter-spacing="3">PLACEHOLDER · 800×1040</text>
</svg>

Before

Width:  |  Height:  |  Size: 1,005 B

View file

@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 700" width="800" height="700" font-family="Georgia, serif">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="hsl(256 78% 68%)" stop-opacity="0.40"/>
<stop offset="1" stop-color="hsl(160 28% 6%)" stop-opacity="1"/>
</linearGradient>
</defs>
<rect width="800" height="700" fill="hsl(160 28% 6%)"/>
<rect width="800" height="700" fill="url(#g)"/>
<circle cx="740" cy="60" r="120" fill="hsl(256 78% 68%)" opacity="0.12"/>
<circle cx="70" cy="630" r="90" fill="hsl(256 78% 68%)" opacity="0.10"/>
<text x="400" y="310" text-anchor="middle" fill="hsl(256 78% 68%)" font-size="46" font-weight="bold">Summit Gathering</text>
<text x="400" y="356" text-anchor="middle" fill="hsl(44 30% 90%)" font-size="26" opacity="0.85">Photo 04</text>
<text x="400" y="394" text-anchor="middle" fill="hsl(150 8% 62%)" font-size="18" letter-spacing="3">PLACEHOLDER · 800×700</text>
</svg>

Before

Width:  |  Height:  |  Size: 1,000 B

View file

@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600" width="800" height="600" font-family="Georgia, serif">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="hsl(256 78% 68%)" stop-opacity="0.40"/>
<stop offset="1" stop-color="hsl(160 28% 6%)" stop-opacity="1"/>
</linearGradient>
</defs>
<rect width="800" height="600" fill="hsl(160 28% 6%)"/>
<rect width="800" height="600" fill="url(#g)"/>
<circle cx="740" cy="60" r="120" fill="hsl(256 78% 68%)" opacity="0.12"/>
<circle cx="70" cy="530" r="90" fill="hsl(256 78% 68%)" opacity="0.10"/>
<text x="400" y="260" text-anchor="middle" fill="hsl(256 78% 68%)" font-size="46" font-weight="bold">Summit Gathering</text>
<text x="400" y="306" text-anchor="middle" fill="hsl(44 30% 90%)" font-size="26" opacity="0.85">Photo 05</text>
<text x="400" y="344" text-anchor="middle" fill="hsl(150 8% 62%)" font-size="18" letter-spacing="3">PLACEHOLDER · 800×600</text>
</svg>

Before

Width:  |  Height:  |  Size: 1,000 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View file

@ -67,7 +67,7 @@ const options = investorAsk.options.map((o) => ({ ...o, annual: Math.round(pnl.y
</div> </div>
<p class="mt-8 max-w-xl text-sm text-fg-muted"> <p class="mt-8 max-w-xl text-sm text-fg-muted">
Prove the model in Austin, then replicate it on Lab 484 the summit gathering and the farm are next. Prove the model in Austin. Prove the replicability in France. Achieve decentralization.
</p> </p>
</SlideFrame> </SlideFrame>
</template> </template>

View file

@ -38,7 +38,7 @@ const revPct = (id: string) =>
<SlideFrame <SlideFrame
kicker="SolLunar Society · unit economics" kicker="SolLunar Society · unit economics"
title="The numbers" title="The numbers"
subtitle="Real monthly P&L for the Austin node. Tap any category to break it down." subtitle="Estimated monthly P&L for the Austin node. Tap any category to break it down."
> >
<!-- headline stats --> <!-- headline stats -->
<div class="grid grid-cols-2 gap-3 sm:grid-cols-4"> <div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
@ -144,8 +144,9 @@ const revPct = (id: string) =>
</div> </div>
<p class="mt-4 text-[11px] text-fg-muted/70"> <p class="mt-4 text-[11px] text-fg-muted/70">
Figures recomputed from the plan's line items. The source summary stated <span class="font-semibold text-amber">Estimated figures projections, not audited results.</span>
{{ fmtUsd(pnlDocSummary.revenue) }} rev / {{ fmtUsd(pnlDocSummary.expenses) }} exp Recomputed from the plan's line items; the source summary stated
{{ fmtUsd(pnlDocSummary.revenue) }} rev / {{ fmtUsd(pnlDocSummary.expenses) }} exp and is
being reconciled. Lunarpunk Locals count is TBD. being reconciled. Lunarpunk Locals count is TBD.
</p> </p>
</SlideFrame> </SlideFrame>

View file

@ -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, two Yellow Houses behind — lodging, coworking and the data center that runs it all." subtitle="A members' society up front, Cypherpunk Commons A & B behind — 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
@ -34,7 +34,7 @@ const icons = ['Building2', 'BedDouble', 'Cpu']
</div> </div>
<p class="mt-6 text-sm text-fg-muted"> <p class="mt-6 text-sm text-fg-muted">
The Yellow House data center makes SolLunar self-hosting the Lab 484 stack runs on-site, The Cypherpunk Commons data center makes SolLunar self-hosting the Lab 484 stack runs on-site,
not in someone else's cloud. not in someone else's cloud.
</p> </p>
</SlideFrame> </SlideFrame>