496 lines
15 KiB
TypeScript
496 lines
15 KiB
TypeScript
/**
|
||
* Social Media Campaign seed — "MycoFi Earth Launch" campaign
|
||
*
|
||
* Demonstrates the folk-social-post component with a realistic
|
||
* multi-platform product launch campaign connected by folk-arrows
|
||
* in an n8n-style "this then that" flow.
|
||
*
|
||
* Flow layout (left-to-right, with parallel branches):
|
||
*
|
||
* [Trigger] → [X Teaser] → [LinkedIn Thought] → [IG Carousel] ──┐
|
||
* ├→ [YT Video] → [X Launch] → [LinkedIn Ann.] ──┐
|
||
* │ ├→ [IG Reel] → [Threads] → [Bluesky]
|
||
* └───────────────────────────────────────────────┘
|
||
*/
|
||
|
||
import {
|
||
addShapes,
|
||
communityExists,
|
||
createCommunity,
|
||
getDocumentData,
|
||
loadCommunity,
|
||
} from "./community-store";
|
||
|
||
// ── Layout constants ────────────────────────────────────────────
|
||
const COL_WIDTH = 320;
|
||
const COL_GAP = 100;
|
||
const ROW_HEIGHT = 420;
|
||
const ROW_GAP = 60;
|
||
const START_X = 60;
|
||
const START_Y = 60;
|
||
const NODE_W = 300;
|
||
const NODE_H = 380;
|
||
|
||
function col(n: number): number {
|
||
return START_X + n * (COL_WIDTH + COL_GAP);
|
||
}
|
||
function row(n: number): number {
|
||
return START_Y + n * (ROW_HEIGHT + ROW_GAP);
|
||
}
|
||
|
||
// ── Campaign seed data ──────────────────────────────────────────
|
||
|
||
const CAMPAIGN_SHAPES: Record<string, unknown>[] = [
|
||
// ────────────────────────────────────────────────────────────
|
||
// TRIGGER NODE (campaign start)
|
||
// ────────────────────────────────────────────────────────────
|
||
{
|
||
id: "campaign-trigger",
|
||
type: "folk-workflow-block",
|
||
x: col(0),
|
||
y: row(0) + 100,
|
||
width: 220,
|
||
height: 140,
|
||
rotation: 0,
|
||
blockType: "trigger",
|
||
label: "Campaign Start",
|
||
inputs: [],
|
||
outputs: [{ name: "launch", type: "trigger" }],
|
||
},
|
||
|
||
// ────────────────────────────────────────────────────────────
|
||
// PHASE 1: Pre-Launch Hype (Days -3 to -1)
|
||
// ────────────────────────────────────────────────────────────
|
||
{
|
||
id: "post-x-teaser",
|
||
type: "folk-social-post",
|
||
x: col(1),
|
||
y: row(0),
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "x",
|
||
postType: "thread",
|
||
stepNumber: 1,
|
||
content:
|
||
"Something is growing in the mycelium... 🍄\n\nFor the past 2 years, we've been building the infrastructure for a regenerative economy.\n\nOn Feb 24, we reveal everything.\n\nA thread on why the old financial system is composting itself 🧵👇",
|
||
mediaUrl: "",
|
||
mediaType: "",
|
||
scheduledAt: "2026-02-21T09:00:00",
|
||
status: "scheduled",
|
||
hashtags: ["MycoFi", "RegenFinance", "Web3", "ComingSoon"],
|
||
},
|
||
|
||
{
|
||
id: "post-linkedin-thought",
|
||
type: "folk-social-post",
|
||
x: col(2),
|
||
y: row(0),
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "linkedin",
|
||
postType: "article",
|
||
stepNumber: 2,
|
||
content:
|
||
"The regenerative finance movement isn't just about returns — it's about redesigning incentive structures from the ground up.\n\nIn this article, I break down why mycelial network theory offers the best model for decentralized economic coordination.\n\n3 key insights from 2 years of building MycoFi Earth...",
|
||
mediaUrl: "",
|
||
mediaType: "image",
|
||
scheduledAt: "2026-02-22T11:00:00",
|
||
status: "scheduled",
|
||
hashtags: ["RegenerativeFinance", "DeFi", "SystemsThinking", "Leadership"],
|
||
},
|
||
|
||
{
|
||
id: "post-ig-carousel",
|
||
type: "folk-social-post",
|
||
x: col(3),
|
||
y: row(0),
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "instagram",
|
||
postType: "carousel",
|
||
stepNumber: 3,
|
||
content:
|
||
"5 Ways Mycelium Networks Mirror the Future of Finance 🌍🍄\n\nSlide 1: The problem with extractive finance\nSlide 2: How mycelium redistributes nutrients\nSlide 3: Token-weighted funding circles\nSlide 4: Community governance that actually works\nSlide 5: Join the launch — Feb 24",
|
||
mediaUrl: "",
|
||
mediaType: "carousel",
|
||
scheduledAt: "2026-02-23T14:00:00",
|
||
status: "scheduled",
|
||
hashtags: [
|
||
"MycoFi",
|
||
"RegenerativeEconomy",
|
||
"Infographic",
|
||
"Web3Education",
|
||
],
|
||
},
|
||
|
||
// ────────────────────────────────────────────────────────────
|
||
// PHASE 2: Launch Day (Day 0)
|
||
// ────────────────────────────────────────────────────────────
|
||
{
|
||
id: "post-yt-launch",
|
||
type: "folk-social-post",
|
||
x: col(4),
|
||
y: row(0) - 30,
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "youtube",
|
||
postType: "video",
|
||
stepNumber: 4,
|
||
content:
|
||
"MycoFi Earth — Official Launch Video\n\nThe regenerative economy starts here. Watch how mycelial intelligence is reshaping finance, governance, and community coordination.\n\nFeaturing interviews with 12 builders from the ecosystem.\n\n[18:42]",
|
||
mediaUrl: "",
|
||
mediaType: "video",
|
||
scheduledAt: "2026-02-24T10:00:00",
|
||
status: "draft",
|
||
hashtags: [
|
||
"MycoFiLaunch",
|
||
"RegenerativeFinance",
|
||
"Documentary",
|
||
"Web3",
|
||
],
|
||
},
|
||
|
||
{
|
||
id: "post-x-launch",
|
||
type: "folk-social-post",
|
||
x: col(5),
|
||
y: row(0) - 60,
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "x",
|
||
postType: "thread",
|
||
stepNumber: 5,
|
||
content:
|
||
"🍄 MycoFi Earth is LIVE 🍄\n\nAfter 2 years of building, the regenerative finance platform is here.\n\nWhat is it?\n• Token-weighted funding circles\n• Mycelial governance (no whales)\n• Composting mechanism for failed proposals\n• 100% on-chain, 100% community-owned\n\n👇 Full breakdown thread",
|
||
mediaUrl: "",
|
||
mediaType: "image",
|
||
scheduledAt: "2026-02-24T10:15:00",
|
||
status: "draft",
|
||
hashtags: [
|
||
"MycoFi",
|
||
"Launch",
|
||
"RegenFinance",
|
||
"DeFi",
|
||
"DAO",
|
||
],
|
||
},
|
||
|
||
{
|
||
id: "post-linkedin-launch",
|
||
type: "folk-social-post",
|
||
x: col(6),
|
||
y: row(0) - 30,
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "linkedin",
|
||
postType: "text",
|
||
stepNumber: 6,
|
||
content:
|
||
"Today we're launching MycoFi Earth — a regenerative finance platform modeled on mycelial networks.\n\nWhy it matters for the future of organizational design:\n\n1. Composting mechanism: Failed proposals return resources to the network\n2. Nutrient routing: Funds flow to where they're needed most\n3. No single point of failure: True decentralization\n\nFull video + docs in comments ↓",
|
||
mediaUrl: "",
|
||
mediaType: "image",
|
||
scheduledAt: "2026-02-24T11:00:00",
|
||
status: "draft",
|
||
hashtags: [
|
||
"Launch",
|
||
"RegenerativeFinance",
|
||
"Innovation",
|
||
"FutureOfWork",
|
||
],
|
||
},
|
||
|
||
// ────────────────────────────────────────────────────────────
|
||
// PHASE 3: Post-Launch Amplification (Day +1)
|
||
// ────────────────────────────────────────────────────────────
|
||
{
|
||
id: "post-ig-reel",
|
||
type: "folk-social-post",
|
||
x: col(7),
|
||
y: row(0) - 30,
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "instagram",
|
||
postType: "reel",
|
||
stepNumber: 7,
|
||
content:
|
||
"60-second explainer: How MycoFi Earth works 🍄✨\n\nVisual breakdown of the token flow from contributor → funding circle → project → compost.\n\nSet to lo-fi beats with mycelium time-lapse footage.\n\nCTA: Link in bio to join the first funding circle.",
|
||
mediaUrl: "",
|
||
mediaType: "video",
|
||
scheduledAt: "2026-02-25T12:00:00",
|
||
status: "draft",
|
||
hashtags: [
|
||
"MycoFi",
|
||
"RegenFinance",
|
||
"Explainer",
|
||
"Web3",
|
||
"Reels",
|
||
],
|
||
},
|
||
|
||
{
|
||
id: "post-threads-xpost",
|
||
type: "folk-social-post",
|
||
x: col(8),
|
||
y: row(0) - 60,
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "threads",
|
||
postType: "text",
|
||
stepNumber: 8,
|
||
content:
|
||
"We just launched MycoFi Earth and the response has been incredible 🌟\n\nThe idea is simple: what if finance worked like mycelium?\n\nMycelium doesn't hoard — it redistributes. MycoFi applies that logic to community funding.\n\nEarly access is open. Come grow with us 🌱",
|
||
mediaUrl: "",
|
||
mediaType: "",
|
||
scheduledAt: "2026-02-25T14:00:00",
|
||
status: "draft",
|
||
hashtags: ["MycoFi", "RegenEconomy", "Community"],
|
||
},
|
||
|
||
{
|
||
id: "post-bluesky-launch",
|
||
type: "folk-social-post",
|
||
x: col(9),
|
||
y: row(0),
|
||
width: NODE_W,
|
||
height: NODE_H,
|
||
rotation: 0,
|
||
platform: "bluesky",
|
||
postType: "text",
|
||
stepNumber: 9,
|
||
content:
|
||
"MycoFi Earth just went live 🍄\n\nIt's a regenerative finance platform where funding flows like nutrients through a mycelial network.\n\nNo VCs. No whales. Just communities funding what matters.\n\nmycofi.earth",
|
||
mediaUrl: "",
|
||
mediaType: "",
|
||
scheduledAt: "2026-02-25T15:00:00",
|
||
status: "draft",
|
||
hashtags: ["MycoFi", "RegenFinance", "Bluesky"],
|
||
},
|
||
|
||
// ────────────────────────────────────────────────────────────
|
||
// CAMPAIGN SUMMARY NODE
|
||
// ────────────────────────────────────────────────────────────
|
||
{
|
||
id: "campaign-summary",
|
||
type: "folk-markdown",
|
||
x: col(0),
|
||
y: row(0) - 200,
|
||
width: 500,
|
||
height: 160,
|
||
rotation: 0,
|
||
content:
|
||
"# 🍄 MycoFi Earth Launch Campaign\n\n**Duration:** Feb 21–25, 2026 (5 days)\n**Platforms:** X, LinkedIn, Instagram, YouTube, Threads, Bluesky\n**Posts:** 9 total across 3 phases\n\n| Phase | Days | Posts |\n|-------|------|-------|\n| Pre-Launch Hype | Day -3 to -1 | 3 posts |\n| Launch Day | Day 0 | 3 posts |\n| Amplification | Day +1 | 3 posts |",
|
||
},
|
||
|
||
// ────────────────────────────────────────────────────────────
|
||
// PHASE LABELS (markdown notes as section headers)
|
||
// ────────────────────────────────────────────────────────────
|
||
{
|
||
id: "label-phase1",
|
||
type: "folk-markdown",
|
||
x: col(1),
|
||
y: row(0) - 55,
|
||
width: COL_WIDTH * 3 + COL_GAP * 2,
|
||
height: 36,
|
||
rotation: 0,
|
||
content:
|
||
"### 📣 Phase 1: Pre-Launch Hype (Feb 21–23)",
|
||
},
|
||
{
|
||
id: "label-phase2",
|
||
type: "folk-markdown",
|
||
x: col(4),
|
||
y: row(0) - 85,
|
||
width: COL_WIDTH * 3 + COL_GAP * 2,
|
||
height: 36,
|
||
rotation: 0,
|
||
content: "### 🚀 Phase 2: Launch Day (Feb 24)",
|
||
},
|
||
{
|
||
id: "label-phase3",
|
||
type: "folk-markdown",
|
||
x: col(7),
|
||
y: row(0) - 85,
|
||
width: COL_WIDTH * 3 + COL_GAP * 2,
|
||
height: 36,
|
||
rotation: 0,
|
||
content:
|
||
"### 📡 Phase 3: Amplification (Feb 25)",
|
||
},
|
||
|
||
// ────────────────────────────────────────────────────────────
|
||
// ARROWS (flow connections)
|
||
// ────────────────────────────────────────────────────────────
|
||
|
||
// Trigger → X Teaser
|
||
{
|
||
id: "arrow-trigger-to-teaser",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "campaign-trigger",
|
||
targetId: "post-x-teaser",
|
||
color: "#64748b",
|
||
},
|
||
|
||
// X Teaser → LinkedIn Thought Leadership
|
||
{
|
||
id: "arrow-teaser-to-linkedin",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-x-teaser",
|
||
targetId: "post-linkedin-thought",
|
||
color: "#0A66C2",
|
||
},
|
||
|
||
// LinkedIn Thought → IG Carousel
|
||
{
|
||
id: "arrow-linkedin-to-ig",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-linkedin-thought",
|
||
targetId: "post-ig-carousel",
|
||
color: "#E4405F",
|
||
},
|
||
|
||
// IG Carousel → YouTube Launch (phase transition)
|
||
{
|
||
id: "arrow-ig-to-yt",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-ig-carousel",
|
||
targetId: "post-yt-launch",
|
||
color: "#FF0000",
|
||
},
|
||
|
||
// YouTube → X Launch Thread
|
||
{
|
||
id: "arrow-yt-to-x-launch",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-yt-launch",
|
||
targetId: "post-x-launch",
|
||
color: "#000000",
|
||
},
|
||
|
||
// X Launch → LinkedIn Announcement
|
||
{
|
||
id: "arrow-x-to-linkedin-launch",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-x-launch",
|
||
targetId: "post-linkedin-launch",
|
||
color: "#0A66C2",
|
||
},
|
||
|
||
// LinkedIn Announcement → IG Reel (phase transition)
|
||
{
|
||
id: "arrow-linkedin-to-reel",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-linkedin-launch",
|
||
targetId: "post-ig-reel",
|
||
color: "#E4405F",
|
||
},
|
||
|
||
// IG Reel → Threads
|
||
{
|
||
id: "arrow-reel-to-threads",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-ig-reel",
|
||
targetId: "post-threads-xpost",
|
||
color: "#000000",
|
||
},
|
||
|
||
// Threads → Bluesky
|
||
{
|
||
id: "arrow-threads-to-bluesky",
|
||
type: "folk-arrow",
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
rotation: 0,
|
||
sourceId: "post-threads-xpost",
|
||
targetId: "post-bluesky-launch",
|
||
color: "#0085FF",
|
||
},
|
||
];
|
||
|
||
/**
|
||
* Ensure the campaign demo community exists and is seeded.
|
||
* Called on server startup alongside the main demo.
|
||
*/
|
||
export async function ensureCampaignDemo(): Promise<void> {
|
||
const slug = "campaign-demo";
|
||
const exists = await communityExists(slug);
|
||
|
||
if (!exists) {
|
||
await createCommunity(
|
||
"Social Media Campaign Demo",
|
||
slug,
|
||
null,
|
||
"public",
|
||
);
|
||
console.log(
|
||
"[Campaign] Created campaign-demo community with visibility: public",
|
||
);
|
||
} else {
|
||
await loadCommunity(slug);
|
||
}
|
||
|
||
// Check if already seeded
|
||
const data = getDocumentData(slug);
|
||
const shapeCount = data ? Object.keys(data.shapes || {}).length : 0;
|
||
|
||
if (shapeCount === 0) {
|
||
addShapes(slug, CAMPAIGN_SHAPES);
|
||
console.log(
|
||
`[Campaign] Seeded ${CAMPAIGN_SHAPES.length} shapes into campaign-demo`,
|
||
);
|
||
} else {
|
||
console.log(
|
||
`[Campaign] campaign-demo already has ${shapeCount} shapes`,
|
||
);
|
||
}
|
||
}
|