/* @jsx React.createElement */ // Landing sections for INDIE Labs. const { useState, useEffect, useRef } = React; // ============================================================ // HERO — kinetic question that cycles // ============================================================ const HERO_QUESTIONS = [ "Cafe yang dikelola dari data?", "Brand UKM level nasional?", "Founder yang ship, bukan janji?", "Tim yang main bareng AI?", "Pengusaha yang tidur tenang?", ]; function HeroQuestion() { const [i, setI] = useState(0); const [typed, setTyped] = useState(""); const [phase, setPhase] = useState("typing"); // typing | holding | erasing useEffect(() => { let to; const word = HERO_QUESTIONS[i]; if (phase === "typing") { if (typed.length < word.length) { to = setTimeout(() => setTyped(word.slice(0, typed.length + 1)), 28 + Math.random() * 22); } else { to = setTimeout(() => setPhase("holding"), 3600); } } else if (phase === "holding") { to = setTimeout(() => setPhase("erasing"), 200); } else { if (typed.length > 0) { to = setTimeout(() => setTyped(word.slice(0, typed.length - 1)), 14); } else { to = setTimeout(() => { setI((i + 1) % HERO_QUESTIONS.length); setPhase("typing"); }, 360); } } return () => clearTimeout(to); }, [i, typed, phase]); return ( {typed} ); } function Hero() { return (
INDIE Labs. · R&D for software

Mau jadi — Mulai dari satu obrolan.

Kami percaya teknologi itu kendaraan, bukan tujuan. Tujuannya: kamu jadi versi paling siap dari brand-mu — di internet, di operasi, di kepercayaan customer.

); } function Stat({ n, l }) { return (
{n}
{l}
); } function HeroSideCard() { // Live "build log" terminal — playful tech moment const lines = [ { t: "[09:14]", k: "ok", m: "pos.indie.cafe · deployed" }, { t: "[09:42]", k: "ok", m: "acct.umkm.dashboard · build ✓" }, { t: "[10:08]", k: "info", m: "ai.chatbot.coffeshop · 1,204 queries today" }, { t: "[10:31]", k: "ok", m: "lab/14 — landing page · live" }, { t: "[11:02]", k: "warn", m: "client feedback · 2 minor tweaks" }, { t: "[11:18]", k: "ok", m: "merged · main · #lab14" }, ]; const [show, setShow] = useState(0); useEffect(() => { if (show >= lines.length) return; const to = setTimeout(() => setShow(show + 1), 380); return () => clearTimeout(to); }, [show]); useEffect(() => { if (show < lines.length) return; const to = setTimeout(() => setShow(0), 4000); return () => clearTimeout(to); }, [show]); const color = (k) => k === "ok" ? "#8be58b" : k === "warn" ? "#F0D050" : "#6fc1ff"; return (
Live · status
~/indielabs · build-log
# live from the lab
{lines.slice(0, show).map((l, i) => (
{l.t} {l.k.toUpperCase()} {l.m}
))} {show < lines.length && }
{/* Lab flask side seal */}
); } // ============================================================ // TRUST STRIP — "part of INDIE Group" // ============================================================ function TrustStrip() { const SUBS = ["indiebrand","indiepreneur","indiespace","ims","indieruma","indiekost","indiecafe","indielabs","indiepack","indiepaper","pixelindie","yappari"]; const items = [...SUBS, ...SUBS]; // doubled for marquee return (
Part of
INDIE Group
{items.map((id, i) => (
{id} {id}
))}
); } // ============================================================ // SERVICES // ============================================================ const SERVICES = [ { n: "01", id: "web", title: "Web Development", sub: "Landing · Marketing · Brand", body: "Punya rumah online sendiri — bukan numpang di marketplace. Brand kamu hadir di Google, di feed, di klien yang Googling kamu jam 11 malam.", bullets: ["Landing page & micro-site", "Company profile + CMS", "Multi-language ID/EN/JP"], icon: ( ), }, { n: "02", id: "webapp", title: "Web App", sub: "POS · Dashboard · Internal tools", body: "Operasi rapi, kamu tinggal mantau. Bukan kamu yang nge-handle 100 hal harian — tools-mu yang ngerjain, kamu yang mikirin langkah berikutnya.", bullets: ["POS untuk cafe & restoran", "Dashboard sales & inventory", "Multi-user, role-based"], icon: ( ), }, { n: "03", id: "ai", title: "AI Integration", sub: "Chatbot · Automation · LLM", body: "AI yang kamu pamerin ke klien, bukan disimpen di notebook. Dari prompt yang work jadi produk yang dipake harian — dengan auth, billing, log, semuanya rapi.", bullets: ["Chatbot WA / web custom", "Workflow automation", "RAG, embeddings, fine-tune"], icon: ( ), }, { n: "04", id: "consult", title: "IT Consultant", sub: "Tech stack · Architecture · Audit", body: "Keputusan teknologi yang gak bikin nyesel enam bulan lagi. Half-day session — jelas, jujur, tanpa upsell tersembunyi.", bullets: ["Tech stack review", "Architecture & cost audit", "Hiring plan & vendor selection"], icon: ( ), }, ]; function Services() { return (
Empat jalan jadi
versi siap-mu.} desc="Bukan tentang fitur atau platform. Tentang siapa kamu setelah enam minggu kerja bareng — brand yang hadir, operasi yang rapi, AI yang dipakai harian." />
{SERVICES.map((s) => )}
); } function ServiceCard({ s }) { return ( { e.currentTarget.style.transform = "translateY(-2px)"; }} onMouseLeave={(e) => { e.currentTarget.style.transform = "translateY(0)"; }}>
{s.icon}
{s.n}
{s.title}
{s.sub}

{s.body}

); } function SectionHead({ eye, title, desc, alignRight }) { return (
{eye}

{title}

{desc &&

{desc}

}
); } // ============================================================ // USE CASES — F&B POS, SMB Accounting, AI-to-Prod // ============================================================ const USECASES = [ { k: "F&B", color: "var(--indie-orange-500)", title: "Jadi cafe yang dikelola dari data, bukan feeling.", body: "Tau menu mana yang laku jam berapa, mana yang harus di-pensiunin. Closing tinggal liat dashboard, bukan rekap manual sampe tengah malam.", points: ["Order ke kitchen display", "Split bill, diskon, voucher", "Laporan harian otomatis ke WA"], badge: "indiecafe", }, { k: "UKM", color: "var(--indie-cyan-500)", title: "Jadi UKM yang dipercaya brand nasional.", body: "Invoice profesional, stok ke-track, supplier puas. Pas calon klien besar nanya ‘sistemnya gimana?’ — kamu udah punya jawabannya.", points: ["Invoice & quotation generator", "Stok & supplier tracking", "Export ke Excel / e-Faktur"], badge: "indiepack", }, { k: "Founders", color: "var(--labs-accent)", title: "Jadi founder yang ship produk, bukan janji.", body: "Prompt yang work + notebook yang akurat = bukan produk. Kami bantu kemas jadi yang bisa dibayar customer — dengan auth, billing, dan ke-handle 24/7.", points: ["Frontend chat / form / wizard", "Auth, billing, rate-limit", "Hosting & monitoring beres"], badge: "indielabs", }, ]; function UseCases() { return (
Tiga jalan,
tiga jadi-an.} desc="Customer kami biasanya tidak cerita soal fitur — mereka cerita soal siapa mereka jadi setelah kerja bareng. Tiga pola ini paling sering kami dengar." />
{USECASES.map((u) => )}
); } function UseCaseCard({ u }) { return (
{u.k}

{u.title}

{u.body}

    {u.points.map((p) => (
  • {p}
  • ))}
); } // ============================================================ // PROCESS — 4 step // ============================================================ const PROCESS = [ { n: "01", t: "Discovery", j: "ディスカバリー", d: "Ngobrol santai 30-60 menit. Kita mapping problem, goal, dan timeline. Free, no strings." }, { n: "02", t: "Design", j: "デザイン", d: "Wireframe → mockup hi-fi. Kamu review tiap step. Revisi sampai pas, sebelum ngoding sebaris pun." }, { n: "03", t: "Build", j: "ビルド", d: "Sprint mingguan. Demo tiap Jumat. Kamu lihat progress real, bukan janji-janji." }, { n: "04", t: "Launch & care", j: "ローンチ", d: "Deploy, monitor, training tim kamu. 30 hari free support pasca-launch." }, ]; function Process() { return (
Empat tahap. Dari ‘punya
ide’ jadi ‘punya brand’.} desc="Bukan sprint mistis. Empat minggu pertama sudah jelas siapa pegang keputusan apa — supaya gak ada surprise di tengah jalan." />
{PROCESS.map((p, i) => (
{p.n}

{p.t}

{p.j}

{p.d}

))}
); } Object.assign(window, { Hero, TrustStrip, Services, UseCases, Process, SectionHead, SERVICES, USECASES, PROCESS, });