/* sema ikutoke Collections — single-file React prototype */ const { useState, useEffect, useRef, useMemo, useCallback } = React; /* ─── tweak defaults ─── */ const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": "cream", "pair": "editorial", "hero": "split", "pricing": "trio", "checkout": "drawer", "canvas": "dots" }/*EDITMODE-END*/; /* ─── data ─── */ const COVER_STYLES = [ // 8 distinct cover gradients for templates / tiles { bg: "linear-gradient(135deg, #E14118 0%, #1B1410 70%)", tag: "Vinyl Co." }, { bg: "linear-gradient(160deg, #1B8B53 0%, #F1E8D1 100%)", tag: "Pasture" }, { bg: "radial-gradient(60% 60% at 30% 30%, #F1582E, #14110D 70%)", tag: "Embers" }, { bg: "linear-gradient(135deg, #2D261F 0%, #C2421A 100%)", tag: "Atelier 03" }, { bg: "linear-gradient(45deg, #5D2BD0 0%, #F4DCD2 90%)", tag: "Stayed" }, { bg: "radial-gradient(circle at 30% 30%, #FFC83D, #C2421A 60%, #14110D 100%)", tag: "Sun&Co" }, { bg: "linear-gradient(135deg, #0E2740 0%, #E14118 95%)", tag: "Nightline" }, { bg: "linear-gradient(180deg, #F8F1DD 0%, #1B8B53 100%)", tag: "Greenroom" }, ]; const TEMPLATES = [ { id: "t1", name: "Quiet Pages", cat: "Writers", price: "KSh 0", note: "Free template" }, { id: "t2", name: "Pasture & Light", cat: "Photographers", price: "KSh 2,400" }, { id: "t3", name: "Atelier 03", cat: "Designers", price: "KSh 1,800" }, { id: "t4", name: "Field Notes", cat: "Writers", price: "KSh 1,200" }, { id: "t5", name: "Embers", cat: "Musicians", price: "KSh 2,000" }, { id: "t6", name: "Stayed", cat: "Course creators", price: "KSh 3,200" }, { id: "t7", name: "Sun & Co.", cat: "Illustrators", price: "KSh 1,500" }, { id: "t8", name: "Nightline", cat: "Podcasters", price: "KSh 2,000" }, { id: "t9", name: "Greenroom", cat: "Filmmakers", price: "KSh 2,800" }, ]; const TICKER = [ "M-PESA Live · 12,847 collections sold today", "Nairobi · Mombasa · Kisumu · Eldoret · Lagos · Kigali · Cape Town · Accra", "Avg. payout 11s after STK approval", "Built in Nairobi, made for makers everywhere", "Bridging KSh, USD, GHS, NGN, ZAR — settled in your wallet", ]; const HOW_STEPS = [ { n: "01", title: "Compose.", body: "Pick a shell, drag in your work. sema ikutoke becomes the single source of truth for your collection.", line: "▸ builder · blocks · drag & drop" }, { n: "02", title: "Distribute.", body: "One click syncs your catalog to WhatsApp, Instagram, Facebook, TikTok — and your own site.", line: "▸ WA · IG · FB · TT · Jumia" }, { n: "03", title: "Get paid.", body: "Buyer tap. M-PESA STK pushes to their phone. Money in your wallet in seconds, every channel.", line: "▸ M-PESA · settle in 11s" }, ]; /* ─── view router stage names ─── */ const VIEWS = [ ["landing", "Landing"], ["signup", "Sign up"], ["templates", "Templates"], ["builder", "Builder"], ["channels", "Channels"], ["store", "Storefront"], ["checkout", "Checkout"], ["dashboard", "Dashboard"], ]; /* ═══════════════════════════════════════════════════════════════════════ Reusable bits ═══════════════════════════════════════════════════════════════════════ */ function Brand() { return (
R sema ikutoke · Collections
); } function TopNav({ goto, view }) { return (
); } function Ticker() { const items = [...TICKER, ...TICKER, ...TICKER]; return (
{items.map((t, i) => ( {t} ))}
); } function ProtoNav({ view, goto }) { return (
{VIEWS.map(([v, label], i) => ( ))}
); } /* ═══════════════════════════════════════════════════════════════════════ LANDING ═══════════════════════════════════════════════════════════════════════ */ function HeroSplit({ goto }) { return (

Make a place
for what you make.

sema ikutoke is a small, opinionated builder for selling digital things — ebooks, presets, courses, lookbooks, beats — directly to anyone with a phone. Built around M-PESA. Loved by clean designers everywhere.

No card. KSh 0 / mo while you build.
); } function HeroCentered({ goto }) { return (
LIVE Now in 14 markets across East & West Africa

A quieter way to sell what you make.

sema ikutoke Collections is a small builder for digital makers. Compose a page. Take payment via M-PESA. Get on with making things.

); } function HeroEditorial({ goto }) { return (
Issue 14 · 2026
Nairobi
sema ikutoke Collections · A builder for digital makers

Sell what you made.

ESTABLISHED in Nairobi · Settles in 11 seconds · For writers, photographers, designers, course creators, musicians, illustrators, podcasters & filmmakers.

A small, opinionated tool for putting your digital work online & getting paid for it via M-PESA. No theme store. No upsells. No 30-step funnel.

M-PESA Daraja · STK push · Card support · USD payouts · No-code editor · Drag-and-drop · Cmd-K everywhere · Open transparently.

); } function HeroCardStack() { return (
collection-22
collection-19
kamau.sema-ikutoke.so
Field Notes Vol. 03 KSh 1,200
23 photographs · 14 essays · 42 MB ★ 4.9 / 312
M-PESA STK push sent to +254 7•• ••• 421
); } function HowItWorks() { return (
§ 01 / Method

Three steps. No fuss.

Average creator ships in 38 min
{HOW_STEPS.map((s) => (
{s.n}

{s.title}

{s.body}

{s.line}
))}
); } function ChannelsStrip({ goto }) { const items = [ { mark: "WA", name: "WhatsApp", color: "#1B8B53", note: "STK push from chat" }, { mark: "IG", name: "Instagram", color: "#E14118", note: "Shoppable posts" }, { mark: "FB", name: "Facebook", color: "#0E2740", note: "FB Shop sync" }, { mark: "TT", name: "TikTok", color: "#161210", note: "Live shopping" }, { mark: "JU", name: "Jumia", color: "#F1582E", note: "Digital catalog" }, { mark: "RI", name: "Your site", color: "#5D2BD0", note: ".sema-ikutoke.so" }, ]; return (
§ 02 / Distribution

Built once. Sold everywhere.

goto("channels")} style={{cursor:"pointer", textDecoration:"underline"}}> See all channels →
{items.map((c) => (
goto("channels")} className="ch-strip-card">
{c.mark}
{c.name}
{c.note}
))}
§ THE PROMISE One catalog. One inbox. One M-PESA wallet. No spreadsheet.
); } function TemplatesStrip({ goto }) { const featured = TEMPLATES.slice(0, 5); return (
§ 03 / Collection

Pick a shell.

goto("templates")} style={{cursor:"pointer", textDecoration:"underline"}}> See all 64 templates →
goto("builder")}>
Quiet Pages
Editor's pick
Writers · Essays · Free Quiet Pages
By sema ikutoke StudioFree
{featured.slice(1, 5).map((t, i) => (
goto("builder")}>
{t.name}
{t.cat} {t.name}
23 blocks{t.price}
))}
); } /* Pricing — varies by tweak */ const PLANS_TRIO = [ { name: "Quiet", price: "0", suffix: "KSh / mo", tag: "Build at your own pace.", features: ["1 collection", "Unlimited blocks", "M-PESA checkout (5% per sale)", "sema-ikutoke.so subdomain"], cta: "Start free" }, { name: "Studio", price: "990", suffix: "KSh / mo", tag: "For makers who ship.", featured: true, features: ["10 collections", "Custom domain", "M-PESA + Card (2.5% per sale)", "Email capture & list", "Analytics that's actually useful"], cta: "Start free trial" }, { name: "Atelier", price: "2,490", suffix: "KSh / mo", tag: "For teams & agencies.", features: ["Unlimited collections", "Team members (5)", "All payment rails (1.9%)", "API & webhooks", "Priority support"], cta: "Talk to us" }, ]; const PLANS_DUO = [ { name: "Solo", price: "0", suffix: "KSh / mo", tag: "Free forever.", features: ["3 collections", "M-PESA checkout", "5% per sale", "sema ikutoke sub-domain", "Community support"], cta: "Start free" }, { name: "Pro", price: "1,490", suffix: "KSh / mo", tag: "Everything, simply.", featured: true, features: ["Unlimited collections", "Custom domain", "M-PESA + Card (1.9%)", "Team seats", "API access"], cta: "Begin trial" }, ]; const PLANS_QUAD = [ { name: "Free", price: "0", suffix: "KSh / mo", tag: "Try it.", features: ["1 collection", "sema ikutoke sub-domain", "5% per sale"], cta: "Start free" }, { name: "Maker", price: "490", suffix: "KSh / mo", tag: "Hobby projects.", features: ["3 collections", "Custom subdomain", "M-PESA (3.5% per sale)"], cta: "Start" }, { name: "Studio", price: "990", suffix: "KSh / mo", tag: "For makers.", featured: true, features: ["10 collections", "Custom domain", "M-PESA + Card (2.5%)", "Analytics"], cta: "Begin trial" }, { name: "Atelier", price: "2,490", suffix: "KSh / mo", tag: "Teams.", features: ["Unlimited", "All rails (1.9%)", "API · 5 seats", "Priority"], cta: "Talk to us" }, ]; function Pricing({ variant, goto }) { const plans = variant === "duo" ? PLANS_DUO : variant === "quad" ? PLANS_QUAD : PLANS_TRIO; return (
§ 04 / Pricing

Honest pricing.

All plans · 14-day trial · Cancel anytime
{plans.map((p) => (
{p.name}
{p.price}{p.suffix}
{p.tag}
    {p.features.map((f, i) =>
  • {f}
  • )}
))}
); } function Footer({ goto }) { return ( ); } function Landing({ tweaks, goto }) { const Hero = tweaks.hero === "centered" ? HeroCentered : tweaks.hero === "editorial" ? HeroEditorial : HeroSplit; return (
); } /* ═══════════════════════════════════════════════════════════════════════ SIGNUP ═══════════════════════════════════════════════════════════════════════ */ function Signup({ goto }) { const [form, setForm] = useState({ name: "", email: "", phone: "", code: "+254", role: "writer" }); const [stage, setStage] = useState("form"); const submit = (e) => { e.preventDefault(); setStage("verifying"); setTimeout(() => goto("templates"), 1400); }; return (
§ FROM THE MANIFESTO

A small, quieter way to sell what you make — on your terms.

"I switched from three other platforms. sema ikutoke lets me focus on the work, not the funnel. STK push, sale done, 4 seconds."
Wambui K., photographer · Nairobi
§ 01 / Begin

Make a place for what you make.

It takes about 90 seconds. We'll set up your sub-domain and a starter collection.

setForm({...form, name: e.target.value})} />
setForm({...form, email: e.target.value})} />
setForm({...form, phone: e.target.value})} />
); } /* ═══════════════════════════════════════════════════════════════════════ TEMPLATES ═══════════════════════════════════════════════════════════════════════ */ const CATEGORIES = ["All", "Writers", "Photographers", "Designers", "Musicians", "Course creators", "Illustrators", "Podcasters", "Filmmakers"]; function Templates({ goto }) { const [cat, setCat] = useState("All"); const list = useMemo(() => cat === "All" ? TEMPLATES : TEMPLATES.filter(t => t.cat === cat), [cat] ); return (
§ 01 / Collection

Sixty-four shells.
One that's yours.

Every template is a starting point — designed to be made yours. Strip it back, add what's missing, push it somewhere unexpected.

{CATEGORIES.map((c) => ( ))}
{list.map((t, i) => { const sp = i === 0 ? "tile-span-6" : (i % 5 === 2 ? "tile-span-3" : "tile-span-3"); const cover = COVER_STYLES[i % COVER_STYLES.length]; return (
goto("builder")}>
{t.name}
{t.note && {t.note}}
{t.cat} {t.name}
{18 + i*2} blocks {t.price}
); })}
); } Object.assign(window, { Brand, TopNav, Ticker, ProtoNav, Landing, Signup, Templates, COVER_STYLES, TEMPLATES, });