mirror of
https://github.com/Such-Software/such.software.git
synced 2026-10-17 05:32:05 +02:00
services: split the four pillars into dedicated subpages
/services becomes a hub (hero, four linked pillar cards, philosophy, recent work, FAQ, CTA) and each pillar gets its own statically-generated page at /services/[pillar] (commerce/games/crypto/education) with distinct SEO title+description+canonical, its own H1, the products behind it, a pillar-scoped FAQ + FAQ JSON-LD, breadcrumb JSON-LD, and 'the other pillars' cross-links. dynamicParams=false so unknown slugs are a static 404. The pillar/proof/FAQ data + colour maps move to lib/services.ts (single source of truth), ProofCard/PillarCards/ServicesCta/EducationCredentials to components/services, so the hub, subpages, home 'What We Do' preview, and sitemap can't drift. Home preview cards now link to their pillar; sitemap gains the four subpage URLs. All pillar copy kept verbatim. Verified: 4 subpages prebuilt, distinct titles/canonicals, right products per page, click-through nav, education credentials block, bad slug -> 404.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import { DataGrid } from "@repo/ui/procedural/data-grid";
|
||||
import { Header } from "@/components/layout/header";
|
||||
import { MobileNav } from "@/components/layout/mobile-nav";
|
||||
import { ScrollReveal } from "@/components/scroll-reveal";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import type { Metadata } from "next";
|
||||
import { JsonLd, breadcrumbLd, faqLd } from "@/components/seo/json-ld";
|
||||
import { ProofCard } from "@/components/services/proof-card";
|
||||
import { PillarCards } from "@/components/services/pillar-cards";
|
||||
import { ServicesCta } from "@/components/services/services-cta";
|
||||
import { EducationCredentials } from "@/components/services/education-credentials";
|
||||
import { pillars, pillarBySlug, proofFor, faqs, borderL } from "@/lib/services";
|
||||
|
||||
type Props = { params: Promise<{ pillar: string }> };
|
||||
|
||||
// Prebuild the four pillar pages at build time (static); anything else is a static 404
|
||||
// rather than an on-demand render.
|
||||
export const dynamicParams = false;
|
||||
export function generateStaticParams() {
|
||||
return pillars.map((p) => ({ pillar: p.slug }));
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { pillar: slug } = await params;
|
||||
const pillar = pillarBySlug(slug);
|
||||
if (!pillar) return {};
|
||||
return {
|
||||
title: pillar.metaTitle,
|
||||
description: pillar.metaDescription,
|
||||
alternates: { canonical: `/services/${pillar.slug}` },
|
||||
openGraph: { title: pillar.metaTitle, description: pillar.metaDescription, type: "website" },
|
||||
};
|
||||
}
|
||||
|
||||
export default async function PillarPage({ params }: Props) {
|
||||
const { pillar: slug } = await params;
|
||||
const pillar = pillarBySlug(slug);
|
||||
if (!pillar) notFound();
|
||||
|
||||
const proof = proofFor(pillar.slug);
|
||||
const pillarFaqs = faqs.filter((f) => f.pillars.includes(pillar.slug));
|
||||
|
||||
return (
|
||||
<main className="relative min-h-screen flex flex-col items-center bg-background text-foreground overflow-hidden">
|
||||
<JsonLd
|
||||
data={breadcrumbLd([
|
||||
{ name: "Home", path: "/" },
|
||||
{ name: "Services", path: "/services" },
|
||||
{ name: pillar.label, path: `/services/${pillar.slug}` },
|
||||
])}
|
||||
/>
|
||||
{pillarFaqs.length > 0 && <JsonLd data={faqLd(pillarFaqs.map(({ q, a }) => ({ q, a })))} />}
|
||||
<DataGrid />
|
||||
<Header />
|
||||
|
||||
<div id="main-content" className="z-10 w-full max-w-5xl mx-auto py-20 px-4">
|
||||
{/* Breadcrumb */}
|
||||
<nav aria-label="Breadcrumb" className="mb-8 text-sm text-muted-foreground">
|
||||
<Link href="/services" className="hover:text-foreground transition-colors">Services</Link>
|
||||
<span className="mx-2" aria-hidden="true">/</span>
|
||||
<span className="text-foreground">{pillar.label}</span>
|
||||
</nav>
|
||||
|
||||
{/* Pillar header */}
|
||||
<ScrollReveal className="mb-14">
|
||||
<div className={`text-left section-container border-l-4 ${borderL[pillar.accent]}`}>
|
||||
<h1 className="text-4xl md:text-5xl font-bold mb-4">{pillar.title}</h1>
|
||||
<p className="text-muted-foreground text-lg max-w-3xl leading-relaxed">{pillar.lead}</p>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* The products behind this pillar */}
|
||||
<ScrollReveal className="mb-16">
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{proof.map((p) => (
|
||||
<ProofCard key={p.title} p={p} accent={pillar.accent} />
|
||||
))}
|
||||
</div>
|
||||
{pillar.slug === "education" && <EducationCredentials />}
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Pillar-specific FAQ */}
|
||||
{pillarFaqs.length > 0 && (
|
||||
<ScrollReveal className="mb-16">
|
||||
<div className="section-container border-l-4 border-l-indigo-500">
|
||||
<h2 className="text-2xl font-bold mb-6 tracking-tight">Questions</h2>
|
||||
<div className="space-y-6">
|
||||
{pillarFaqs.map((f) => (
|
||||
<div key={f.q}>
|
||||
<h3 className="text-lg font-bold mb-1">{f.q}</h3>
|
||||
<p className="text-muted-foreground leading-relaxed max-w-3xl">{f.a}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
)}
|
||||
|
||||
{/* Explore the other pillars */}
|
||||
<ScrollReveal className="mb-20">
|
||||
<PillarCards exclude={pillar.slug} heading="The other pillars" />
|
||||
</ScrollReveal>
|
||||
|
||||
{/* CTA */}
|
||||
<ScrollReveal>
|
||||
<ServicesCta />
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
<MobileNav />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,241 +1,52 @@
|
||||
import { DataGrid } from "@repo/ui/procedural/data-grid";
|
||||
import { Button } from "@repo/ui/components/button";
|
||||
import { Header } from "@/components/layout/header";
|
||||
import { MobileNav } from "@/components/layout/mobile-nav";
|
||||
import { ScrollReveal } from "@/components/scroll-reveal";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import { JsonLd, faqLd } from "@/components/seo/json-ld";
|
||||
import { PillarCards } from "@/components/services/pillar-cards";
|
||||
import { ServicesCta } from "@/components/services/services-cta";
|
||||
import { faqs } from "@/lib/services";
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
const faqs = [
|
||||
{ q: "What does Such Software build?", a: "Four things, from one small team: custom e-commerce and web apps on revenue share, games and mobile apps we ship ourselves, cryptocurrency and payments software (integration only, never custody), and PhD-led radiation-science education. The pillars below break each down with the products behind them." },
|
||||
{ q: "Do you offer nuclear and radiation education?", a: "Yes. Our founder holds a PhD in radiation-detector materials and spent six years at Lawrence Livermore National Laboratory, plus shielding and spent-fuel work at Holtec. We teach radiation-science fundamentals and Monte Carlo methods, run GEANT4 training, and speak on these topics. Our GEANT4 radiation labs are published open-source (MIT / CC-BY). This is education and published methods." },
|
||||
{ q: "Where are you based?", a: "We are a software studio in Kennett Square, Pennsylvania, working with clients remotely across the US and beyond." },
|
||||
{ q: "Do you build for accessibility?", a: "Yes. We engineer front-ends to meet WCAG 2.2 AA and audit against it, alongside Core Web Vitals, as part of every project." },
|
||||
{ q: "How does a project start?", a: "Reach out through the contact form with what you need. We scope it, propose an approach, and from there it can run as a fixed project or a performance-based revenue-share partnership." },
|
||||
{ q: "Do you take revenue-share work?", a: "Yes. For a limited number of partners we build and operate products (such as webshops) for a share of revenue instead of a large upfront fee, so our incentives line up with yours." },
|
||||
];
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Web, Games, Crypto & Nuclear-Science Education | Such Software",
|
||||
description: "Four pillars from one studio: custom e-commerce and web apps on revenue share, games and mobile apps, crypto and payments software (non-custodial), and PhD-led radiation-science education and GEANT4 training. Kennett Square, PA.",
|
||||
alternates: {
|
||||
canonical: "/services",
|
||||
},
|
||||
description:
|
||||
"Four pillars from one studio: custom e-commerce and web apps on revenue share, games and mobile apps, crypto and payments software (non-custodial), and PhD-led radiation-science education and GEANT4 training. Kennett Square, PA.",
|
||||
alternates: { canonical: "/services" },
|
||||
openGraph: {
|
||||
title: "Web, Games, Crypto & Nuclear-Science Education | Such Software",
|
||||
description: "Four pillars from one studio: custom e-commerce and web apps on revenue share, games and mobile apps, crypto and payments software (non-custodial), and PhD-led radiation-science education and GEANT4 training.",
|
||||
description:
|
||||
"Four pillars from one studio: custom e-commerce and web apps on revenue share, games and mobile apps, crypto and payments software (non-custodial), and PhD-led radiation-science education and GEANT4 training.",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
// ---- Pillar model -------------------------------------------------------
|
||||
|
||||
type Pillar = {
|
||||
id: string;
|
||||
label: string;
|
||||
accent: string; // tailwind colour stem, e.g. "blue"
|
||||
title: string;
|
||||
lead: string;
|
||||
};
|
||||
|
||||
const pillars: Pillar[] = [
|
||||
{
|
||||
id: "commerce",
|
||||
label: "Commerce & Web",
|
||||
accent: "blue",
|
||||
title: "Commerce & custom web",
|
||||
lead: "Proprietary, headless commerce and web apps that you own, built to your business logic instead of a template's limits. Often on revenue share: we build, host, and run it, and earn a share once you are live.",
|
||||
},
|
||||
{
|
||||
id: "games",
|
||||
label: "Games & Apps",
|
||||
accent: "purple",
|
||||
title: "Games & apps",
|
||||
lead: "We do not just consult on software, we ship it. A growing catalog of games and mobile apps built in-house across iOS, Android, web, and desktop, on Godot and Next.js.",
|
||||
},
|
||||
{
|
||||
id: "crypto",
|
||||
label: "Crypto & Payments",
|
||||
accent: "cyan",
|
||||
title: "Crypto & payments",
|
||||
lead: "Software and integration for payments and cryptocurrency. The client, a licensed processor, or the user's own wallet holds the funds; we build the system around it and never take custody.",
|
||||
},
|
||||
{
|
||||
id: "education",
|
||||
label: "Education & Science",
|
||||
accent: "amber",
|
||||
title: "Education & science",
|
||||
lead: "PhD-led radiation-science teaching, training, and speaking from years at a national lab, plus learning-through-play games that teach real science and math. We publish our methods open-source.",
|
||||
},
|
||||
];
|
||||
|
||||
// Border-left colour per accent (literal strings so Tailwind's JIT keeps them).
|
||||
const borderL: Record<string, string> = {
|
||||
blue: "border-l-blue-500",
|
||||
purple: "border-l-purple-500",
|
||||
cyan: "border-l-cyan-500",
|
||||
amber: "border-l-amber-500",
|
||||
};
|
||||
const chipAccent: Record<string, string> = {
|
||||
blue: "bg-blue-500/15 text-blue-700 dark:text-blue-300",
|
||||
purple: "bg-purple-500/15 text-purple-700 dark:text-purple-300",
|
||||
cyan: "bg-cyan-500/15 text-cyan-700 dark:text-cyan-300",
|
||||
amber: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
};
|
||||
const hoverBorder: Record<string, string> = {
|
||||
blue: "hover:border-blue-500/30",
|
||||
purple: "hover:border-purple-500/30",
|
||||
cyan: "hover:border-cyan-500/30",
|
||||
amber: "hover:border-amber-500/30",
|
||||
};
|
||||
|
||||
// ---- Proof items (real products behind each pillar) ---------------------
|
||||
|
||||
type Proof = {
|
||||
title: string;
|
||||
blurb: string;
|
||||
img?: string; // /images/products/*
|
||||
href?: string; // internal detail page or external
|
||||
tag?: string; // status pill: "Live", "Open source", "Beta", "Early", "Flagship"
|
||||
};
|
||||
|
||||
const commerceProof: Proof[] = [
|
||||
{ title: "Webshops", blurb: "Our multi-tenant commerce platform: fully-themed storefronts, print-on-demand, non-custodial crypto checkout, and automated tax, on revenue share.", img: "/images/products/occupy-wallets.png", href: "/products/webshops", tag: "Flagship" },
|
||||
{ title: "Custom builds", blurb: "Real-time web apps, multiplayer experiences, and live dashboards on Next.js, Socket.io, and WebRTC.", img: "/images/products/custom-websites.svg", href: "/products/custom-websites", tag: "Live" },
|
||||
{ title: "Grin BTCPay plugin", blurb: "An open-source BTCPay Server plugin we built to accept Grin (Mimblewimble) payments, including auto-Tor invoice exchange.", tag: "Open source" },
|
||||
{ title: "Evaluetron", blurb: "A self-hostable AI-compute platform: one core that runs a personal image bot or a paid multi-customer service, with an append-only credit ledger and pricing built in.", tag: "Building" },
|
||||
];
|
||||
|
||||
const gamesProof: Proof[] = [
|
||||
{ title: "Suchoice", blurb: "Stop overthinking decisions: snap a photo, let AI read the options, spin the wheel. iOS and Android.", img: "/images/products/suchoice.png", href: "/products/suchoice", tag: "Live" },
|
||||
{ title: "Vegan IQ", blurb: "1,000+ plant-based trivia questions across 8 categories, with a daily challenge and weekly quiz. iOS and Android.", img: "/images/products/vegan-iq.png", href: "/products/vegan-iq", tag: "Live" },
|
||||
{ title: "Bloomword", blurb: "A daily word game where every word you find grows a living 3D typographic tree. Free at bloomword.earth, launching on mobile.", img: "/images/products/bloomword.svg", href: "/products/bloomword", tag: "Live" },
|
||||
{ title: "Bauhaus Echo", blurb: "A visual memory puzzle game inspired by Bauhaus design. Android, iOS, and web.", img: "/images/products/bauhaus-echo.png", href: "/products/bauhaus-echo", tag: "Live" },
|
||||
{ title: "Such Moon Launch", blurb: "Vry rocket, much landing, wow: a Wownero-themed pixel rocket arcade with 11 levels and tilt-to-steer. Everywhere.", img: "/images/products/such-moon-launch.png", href: "/products/such-moon-launch", tag: "Live" },
|
||||
];
|
||||
|
||||
const cryptoProof: Proof[] = [
|
||||
{ title: "Payments consulting", blurb: "Stripe and multi-processor integrations, reconciliation tooling, Monero and on-chain integration. The processor or wallet moves the money; we wire it in.", tag: "Service" },
|
||||
{ title: "Smirk Wallet", blurb: "A non-custodial multi-asset browser wallet: send, receive, and tip by username on Telegram and Discord. BTC, LTC, XMR, WOW, GRIN.", img: "/images/products/smirk-wallet.png", href: "/products/smirk-wallet", tag: "Live" },
|
||||
{ title: "Hash Bags", blurb: "A mobile multi-chain wallet forked from Cake Wallet, tuned for the privacy-coin ecosystem.", tag: "Beta" },
|
||||
{ title: "Evaluetron", blurb: "Pay-for-compute done right: an append-only credit ledger, a job queue, and an evaluator that lets on-demand work preempt opportunistic work. Customers can never self-credit.", tag: "Building" },
|
||||
];
|
||||
|
||||
const educationProof: Proof[] = [
|
||||
{ title: "Barns & Neutrons", blurb: "A cozy exploration-puzzle game across the real Table of Nuclides: capture neutrons, coax decays, and learn honest nuclear physics. Our premiere visual work.", img: "/images/products/barns-and-neutrons.svg", href: "/products/barns-and-neutrons", tag: "Coming soon" },
|
||||
{ title: "Nuclear consulting & training", blurb: "PhD-led radiation-science teaching: Monte Carlo methods with GEANT4, shielding and dose fundamentals, detector physics, and open-source labs.", href: "https://jwinterm.github.io/geant4-radiation-labs/", tag: "Service" },
|
||||
{ title: "Numchangers", blurb: "A kids math game (ages 5-8) where numbers morph into dots, shapes, and 3D characters, so arithmetic becomes a visible action instead of a quiz. Godot, mobile-first.", tag: "Early" },
|
||||
];
|
||||
|
||||
const tagStyle: Record<string, string> = {
|
||||
Flagship: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
|
||||
Live: "bg-green-500/15 text-green-700 dark:text-green-300",
|
||||
Service: "bg-sky-500/15 text-sky-700 dark:text-sky-300",
|
||||
"Open source": "bg-indigo-500/15 text-indigo-700 dark:text-indigo-300",
|
||||
Beta: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
Building: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
Early: "bg-fuchsia-500/15 text-fuchsia-700 dark:text-fuchsia-300",
|
||||
"Coming soon": "bg-fuchsia-500/15 text-fuchsia-700 dark:text-fuchsia-300",
|
||||
};
|
||||
|
||||
function ProofCard({ p, accent }: { p: Proof; accent: string }) {
|
||||
const inner = (
|
||||
<Card className={`glass-card h-full !p-6 transition-colors ${hoverBorder[accent]}`}>
|
||||
<div className="flex items-start gap-4">
|
||||
{p.img ? (
|
||||
<Image
|
||||
src={p.img}
|
||||
alt={p.title}
|
||||
width={48}
|
||||
height={48}
|
||||
className="rounded-xl flex-shrink-0 h-12 w-12 object-cover bg-white/5"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className={`flex-shrink-0 h-12 w-12 rounded-xl flex items-center justify-center text-lg font-bold ${chipAccent[accent]}`}
|
||||
>
|
||||
{p.title.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2 mb-1 flex-wrap">
|
||||
<h3 className="text-lg font-bold text-foreground">{p.title}</h3>
|
||||
{p.tag && (
|
||||
<span className={`text-[11px] font-medium px-2 py-0.5 rounded-full ${tagStyle[p.tag] ?? chipAccent[accent]}`}>
|
||||
{p.tag}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">{p.blurb}</p>
|
||||
{p.href && (
|
||||
<span className="mt-2 inline-block text-sm font-medium text-foreground group-hover:underline">
|
||||
Learn more →
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
||||
if (!p.href) return <div>{inner}</div>;
|
||||
const external = p.href.startsWith("http");
|
||||
return external ? (
|
||||
<a href={p.href} target="_blank" rel="noopener noreferrer" className="group block h-full">
|
||||
{inner}
|
||||
</a>
|
||||
) : (
|
||||
<Link href={p.href} className="group block h-full">
|
||||
{inner}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
function proofFor(id: string): Proof[] {
|
||||
if (id === "commerce") return commerceProof;
|
||||
if (id === "games") return gamesProof;
|
||||
if (id === "crypto") return cryptoProof;
|
||||
return educationProof;
|
||||
}
|
||||
|
||||
export default function ServicesPage() {
|
||||
return (
|
||||
<main className="relative min-h-screen flex flex-col items-center bg-background text-foreground overflow-hidden">
|
||||
<JsonLd data={faqLd(faqs)} />
|
||||
<JsonLd data={faqLd(faqs.map(({ q, a }) => ({ q, a })))} />
|
||||
<DataGrid />
|
||||
<Header />
|
||||
|
||||
<div id="main-content" className="z-10 w-full max-w-5xl mx-auto py-20 px-4">
|
||||
{/* Page Header */}
|
||||
{/* Page header */}
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-4xl md:text-6xl font-bold mb-6 bg-clip-text text-transparent bg-gradient-to-r from-emerald-400 to-blue-500">
|
||||
Four things, done well
|
||||
</h1>
|
||||
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
|
||||
Commerce and custom web, games and apps, crypto and payments, and
|
||||
PhD-led radiation-science education. Each pillar comes with the
|
||||
products behind it.
|
||||
PhD-led radiation-science education. Pick a pillar to see the products
|
||||
behind it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Pillar sub-nav: jump links so the page reads as four clear areas */}
|
||||
<nav aria-label="Service pillars" className="mb-16">
|
||||
<ul className="flex flex-wrap justify-center gap-2 sm:gap-3">
|
||||
{pillars.map((p) => (
|
||||
<li key={p.id}>
|
||||
<a
|
||||
href={`#${p.id}`}
|
||||
className="inline-block px-4 py-2 rounded-full text-sm font-medium mask-backdrop border border-white/10 text-foreground hover:border-white/30 transition-colors"
|
||||
>
|
||||
{p.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
{/* The four pillars, each its own page */}
|
||||
<ScrollReveal className="mb-20">
|
||||
<PillarCards />
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Philosophy */}
|
||||
<ScrollReveal className="mb-20">
|
||||
@@ -248,55 +59,7 @@ export default function ServicesPage() {
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Pillars */}
|
||||
{pillars.map((pillar) => (
|
||||
<section
|
||||
key={pillar.id}
|
||||
id={pillar.id}
|
||||
aria-labelledby={`${pillar.id}-heading`}
|
||||
className="mb-24 scroll-mt-24"
|
||||
>
|
||||
<ScrollReveal>
|
||||
<div className={`text-left mb-10 section-container border-l-4 ${borderL[pillar.accent]}`}>
|
||||
<h2 id={`${pillar.id}-heading`} className="text-3xl font-bold mb-2">
|
||||
{pillar.title}
|
||||
</h2>
|
||||
<p className="text-muted-foreground text-lg max-w-3xl leading-relaxed">
|
||||
{pillar.lead}
|
||||
</p>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
<ScrollReveal>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{proofFor(pillar.id).map((p) => (
|
||||
<ProofCard key={p.title} p={p} accent={pillar.accent} />
|
||||
))}
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Education pillar carries the founder credentials inline */}
|
||||
{pillar.id === "education" && (
|
||||
<ScrollReveal>
|
||||
<Card className="glass-card border-amber-400/20 mt-6 !p-8">
|
||||
<h3 className="text-lg font-bold mb-4">Why us, on the science</h3>
|
||||
<ul className="space-y-2 text-base text-muted-foreground leading-relaxed">
|
||||
<li><span className="font-semibold text-foreground">PhD in radiation-detector materials</span>, UT-Dallas (2014)</li>
|
||||
<li><span className="font-semibold text-foreground">Lawrence Livermore National Laboratory</span> (2015-2021): detector systems, radioisotope battery program, MCNP5 publications</li>
|
||||
<li><span className="font-semibold text-foreground">Holtec International</span>: radiation shielding and spent-fuel-to-dry-cask optimization</li>
|
||||
<li><span className="font-semibold text-foreground">College-level instructor</span>: author of open-source GEANT4 radiation labs</li>
|
||||
</ul>
|
||||
<p className="text-xs text-muted-foreground/70 mt-5">
|
||||
This is education and published open-source methods, not for-hire controlled
|
||||
modeling. We are not a licensed professional-engineering (PE) firm and provide no
|
||||
stamped engineering deliverables.
|
||||
</p>
|
||||
</Card>
|
||||
</ScrollReveal>
|
||||
)}
|
||||
</section>
|
||||
))}
|
||||
|
||||
{/* Recent Work */}
|
||||
{/* Recent work */}
|
||||
<ScrollReveal className="mb-24">
|
||||
<div className="text-left mb-10 section-container border-l-4 border-l-amber-500">
|
||||
<h2 className="text-3xl font-bold mb-2">Recent work</h2>
|
||||
@@ -332,7 +95,7 @@ export default function ServicesPage() {
|
||||
</ScrollReveal>
|
||||
|
||||
{/* FAQ */}
|
||||
<ScrollReveal className="mt-20">
|
||||
<ScrollReveal className="mb-20">
|
||||
<div className="section-container border-l-4 border-l-indigo-500">
|
||||
<h2 className="text-3xl font-bold mb-8 tracking-tight">Frequently asked questions</h2>
|
||||
<div className="space-y-6">
|
||||
@@ -347,18 +110,8 @@ export default function ServicesPage() {
|
||||
</ScrollReveal>
|
||||
|
||||
{/* CTA */}
|
||||
<ScrollReveal className="mt-20 p-16 rounded-[2.5rem] bg-gradient-to-br from-slate-900 via-slate-800 to-indigo-950 text-white text-center shadow-2xl relative overflow-hidden group border-2 border-white/5">
|
||||
<div className="absolute inset-0 bg-blue-500/10 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<h2 className="text-4xl font-bold mb-6 relative z-10 tracking-tight">Let's build together</h2>
|
||||
<p className="mb-10 text-slate-300 text-lg max-w-2xl mx-auto relative z-10 leading-relaxed font-medium">
|
||||
We take on a limited number of revenue-share build partners. Tell us what you're
|
||||
building and we'll run a scope review.
|
||||
</p>
|
||||
<Link href="/contact" className="relative z-10">
|
||||
<Button size="lg" variant="secondary" className="rounded-2xl px-12 py-8 text-xl font-bold hover:scale-105 transition-transform bg-white text-slate-900 hover:bg-slate-100">
|
||||
Request a Consultation
|
||||
</Button>
|
||||
</Link>
|
||||
<ScrollReveal>
|
||||
<ServicesCta />
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
<MobileNav />
|
||||
|
||||
@@ -29,6 +29,10 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
{ url: `${base}/products/meatspace`, lastModified: updated, changeFrequency: "weekly", priority: 0.7 },
|
||||
{ url: `${base}/products/mushroom-capital`, lastModified: updated, changeFrequency: "weekly", priority: 0.7 },
|
||||
{ url: `${base}/services`, lastModified: updated, changeFrequency: "monthly", priority: 0.9 },
|
||||
{ url: `${base}/services/commerce`, lastModified: updated, changeFrequency: "monthly", priority: 0.8 },
|
||||
{ url: `${base}/services/games`, lastModified: updated, changeFrequency: "monthly", priority: 0.8 },
|
||||
{ url: `${base}/services/crypto`, lastModified: updated, changeFrequency: "monthly", priority: 0.8 },
|
||||
{ url: `${base}/services/education`, lastModified: updated, changeFrequency: "monthly", priority: 0.8 },
|
||||
{ url: `${base}/about`, lastModified: updated, changeFrequency: "monthly", priority: 0.7 },
|
||||
{ url: `${base}/support`, lastModified: updated, changeFrequency: "monthly", priority: 0.5 },
|
||||
{ url: `${base}/privacy`, lastModified: updated, changeFrequency: "yearly", priority: 0.3 },
|
||||
|
||||
@@ -1,49 +1,54 @@
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import Link from "next/link";
|
||||
|
||||
// The four "What We Do" cards on the home page, each linking to its /services/<slug> pillar page.
|
||||
const previews = [
|
||||
{
|
||||
href: "/services/commerce",
|
||||
title: "E-Commerce & Hosting",
|
||||
body: "Headless storefronts on Medusa and Next.js, built fast and hosted on our own infrastructure. Stripe Connect with a revenue-share model: you stay the merchant of record, and crypto settles straight to your own wallets.",
|
||||
},
|
||||
{
|
||||
href: "/services/games",
|
||||
title: "Custom App Development",
|
||||
body: "Cross-platform mobile and web apps built to spec. We handle architecture, deployment, and ongoing support so you can focus on your business.",
|
||||
},
|
||||
{
|
||||
href: "/services/crypto",
|
||||
title: "Crypto & Payment Integration",
|
||||
body: "Software and integration for multi-currency checkout and non-custodial crypto payments, in production since 2014. You or a licensed provider hold the funds; we never take custody.",
|
||||
},
|
||||
{
|
||||
href: "/services/education",
|
||||
title: "Nuclear & Radiation Education",
|
||||
body: "Training, talks, and open-source GEANT4 labs on radiation transport and semiconductor detectors, led by a PhD with a Lawrence Livermore background. Published methods and teaching.",
|
||||
},
|
||||
];
|
||||
|
||||
export function ServicesPreview() {
|
||||
return (
|
||||
<div className="w-full max-w-6xl mx-auto px-4 mt-8 mb-16 relative z-10">
|
||||
<div className="text-left mb-8 section-container border-l-4 border-l-emerald-500">
|
||||
<h2 className="text-3xl font-bold mb-3 tracking-tight">What We Do</h2>
|
||||
<p className="text-muted-foreground text-lg max-w-3xl leading-relaxed">
|
||||
We build and host custom e-commerce stores, develop apps to spec, and ship our own
|
||||
titles and games. We handle your project end to end, from architecture to deployment.
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-left mb-8 section-container border-l-4 border-l-emerald-500">
|
||||
<h2 className="text-3xl font-bold mb-3 tracking-tight">What We Do</h2>
|
||||
<p className="text-muted-foreground text-lg max-w-3xl leading-relaxed">
|
||||
We build and host custom e-commerce stores, develop apps to spec, and ship our own
|
||||
titles and games. We handle your project end to end, from architecture to deployment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<Card className="glass-card hover:border-indigo-500/40 text-left">
|
||||
<h3 className="text-xl font-bold mb-3">E-Commerce & Hosting</h3>
|
||||
<p className="text-base text-muted-foreground leading-relaxed">
|
||||
Headless storefronts on Medusa and Next.js, built fast and hosted on our own
|
||||
infrastructure. Stripe Connect with a revenue-share model: you stay the merchant
|
||||
of record, and crypto settles straight to your own wallets.
|
||||
</p>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{previews.map((p) => (
|
||||
<Link key={p.href} href={p.href} className="group block h-full">
|
||||
<Card className="glass-card h-full hover:border-indigo-500/40 text-left transition-colors">
|
||||
<h3 className="text-xl font-bold mb-3">{p.title}</h3>
|
||||
<p className="text-base text-muted-foreground leading-relaxed">{p.body}</p>
|
||||
<span className="mt-3 inline-block text-sm font-medium text-foreground group-hover:underline">
|
||||
Learn more →
|
||||
</span>
|
||||
</Card>
|
||||
<Card className="glass-card hover:border-indigo-500/40 text-left">
|
||||
<h3 className="text-xl font-bold mb-3">Custom App Development</h3>
|
||||
<p className="text-base text-muted-foreground leading-relaxed">
|
||||
Cross-platform mobile and web apps built to spec. We handle architecture,
|
||||
deployment, and ongoing support so you can focus on your business.
|
||||
</p>
|
||||
</Card>
|
||||
<Card className="glass-card hover:border-indigo-500/40 text-left">
|
||||
<h3 className="text-xl font-bold mb-3">Crypto & Payment Integration</h3>
|
||||
<p className="text-base text-muted-foreground leading-relaxed">
|
||||
Software and integration for multi-currency checkout and non-custodial crypto
|
||||
payments, in production since 2014. You or a licensed provider hold the funds;
|
||||
we never take custody.
|
||||
</p>
|
||||
</Card>
|
||||
<Card className="glass-card hover:border-indigo-500/40 text-left">
|
||||
<h3 className="text-xl font-bold mb-3">Nuclear & Radiation Education</h3>
|
||||
<p className="text-base text-muted-foreground leading-relaxed">
|
||||
Training, talks, and open-source GEANT4 labs on radiation transport and
|
||||
semiconductor detectors, led by a PhD with a Lawrence Livermore background.
|
||||
Published methods and teaching.
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
|
||||
// Founder science credentials, shown on the Education & Science pillar page.
|
||||
export function EducationCredentials() {
|
||||
return (
|
||||
<Card className="glass-card border-amber-400/20 mt-6 !p-8">
|
||||
<h3 className="text-lg font-bold mb-4">Why us, on the science</h3>
|
||||
<ul className="space-y-2 text-base text-muted-foreground leading-relaxed">
|
||||
<li><span className="font-semibold text-foreground">PhD in radiation-detector materials</span>, UT-Dallas (2014)</li>
|
||||
<li><span className="font-semibold text-foreground">Lawrence Livermore National Laboratory</span> (2015-2021): detector systems, radioisotope battery program, MCNP5 publications</li>
|
||||
<li><span className="font-semibold text-foreground">Holtec International</span>: radiation shielding and spent-fuel-to-dry-cask optimization</li>
|
||||
<li><span className="font-semibold text-foreground">College-level instructor</span>: author of open-source GEANT4 radiation labs</li>
|
||||
</ul>
|
||||
<p className="text-xs text-muted-foreground/70 mt-5">
|
||||
This is education and published open-source methods, not for-hire controlled
|
||||
modeling. We are not a licensed professional-engineering (PE) firm and provide no
|
||||
stamped engineering deliverables.
|
||||
</p>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import Link from "next/link";
|
||||
import { pillars, borderL, hoverBorder } from "@/lib/services";
|
||||
|
||||
// The four pillar cards, each linking to its /services/<slug> subpage. Used as the hub's
|
||||
// primary nav and, with `exclude`, as the "explore the other pillars" block on a subpage.
|
||||
export function PillarCards({ exclude, heading }: { exclude?: string; heading?: string }) {
|
||||
const shown = pillars.filter((p) => p.slug !== exclude);
|
||||
return (
|
||||
<div>
|
||||
{heading && <h2 className="text-2xl font-bold mb-6">{heading}</h2>}
|
||||
<div className="grid sm:grid-cols-2 gap-6">
|
||||
{shown.map((p) => (
|
||||
<Link key={p.slug} href={`/services/${p.slug}`} className="group block h-full">
|
||||
<Card className={`glass-card h-full !p-7 text-left border-l-4 ${borderL[p.accent]} transition-colors ${hoverBorder[p.accent]}`}>
|
||||
<h3 className="text-xl font-bold mb-2 text-foreground">{p.title}</h3>
|
||||
<p className="text-base text-muted-foreground leading-relaxed">{p.card}</p>
|
||||
<span className="mt-3 inline-block text-sm font-medium text-foreground group-hover:underline">
|
||||
Explore {p.label} →
|
||||
</span>
|
||||
</Card>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Card } from "@repo/ui/components/card";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { chipAccent, hoverBorder, tagStyle, type Proof } from "@/lib/services";
|
||||
|
||||
// One "real product behind a pillar" card. Used on the hub and on every /services/[pillar] page.
|
||||
export function ProofCard({ p, accent }: { p: Proof; accent: string }) {
|
||||
const inner = (
|
||||
<Card className={`glass-card h-full !p-6 transition-colors ${hoverBorder[accent]}`}>
|
||||
<div className="flex items-start gap-4">
|
||||
{p.img ? (
|
||||
<Image
|
||||
src={p.img}
|
||||
alt={p.title}
|
||||
width={48}
|
||||
height={48}
|
||||
className="rounded-xl flex-shrink-0 h-12 w-12 object-cover bg-white/5"
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className={`flex-shrink-0 h-12 w-12 rounded-xl flex items-center justify-center text-lg font-bold ${chipAccent[accent]}`}
|
||||
>
|
||||
{p.title.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2 mb-1 flex-wrap">
|
||||
<h3 className="text-lg font-bold text-foreground">{p.title}</h3>
|
||||
{p.tag && (
|
||||
<span className={`text-[11px] font-medium px-2 py-0.5 rounded-full ${tagStyle[p.tag] ?? chipAccent[accent]}`}>
|
||||
{p.tag}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">{p.blurb}</p>
|
||||
{p.href && (
|
||||
<span className="mt-2 inline-block text-sm font-medium text-foreground group-hover:underline">
|
||||
Learn more →
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
||||
if (!p.href) return <div>{inner}</div>;
|
||||
const external = p.href.startsWith("http");
|
||||
return external ? (
|
||||
<a href={p.href} target="_blank" rel="noopener noreferrer" className="group block h-full">
|
||||
{inner}
|
||||
</a>
|
||||
) : (
|
||||
<Link href={p.href} className="group block h-full">
|
||||
{inner}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Button } from "@repo/ui/components/button";
|
||||
import Link from "next/link";
|
||||
|
||||
// Shared closing CTA for the services hub and every pillar subpage.
|
||||
export function ServicesCta({
|
||||
title = "Let's build together",
|
||||
blurb = "We take on a limited number of revenue-share build partners. Tell us what you're building and we'll run a scope review.",
|
||||
}: {
|
||||
title?: string;
|
||||
blurb?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="p-12 md:p-16 rounded-[2.5rem] bg-gradient-to-br from-slate-900 via-slate-800 to-indigo-950 text-white text-center shadow-2xl relative overflow-hidden group border-2 border-white/5">
|
||||
<div className="absolute inset-0 bg-blue-500/10 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-6 relative z-10 tracking-tight">{title}</h2>
|
||||
<p className="mb-10 text-slate-300 text-lg max-w-2xl mx-auto relative z-10 leading-relaxed font-medium">
|
||||
{blurb}
|
||||
</p>
|
||||
<Link href="/contact" className="relative z-10">
|
||||
<Button size="lg" variant="secondary" className="rounded-2xl px-12 py-8 text-xl font-bold hover:scale-105 transition-transform bg-white text-slate-900 hover:bg-slate-100">
|
||||
Request a Consultation
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// Single source of truth for the Services pillars + the real products behind each.
|
||||
// Consumed by the /services hub, the /services/[pillar] subpages, the home "What We Do"
|
||||
// preview, and the sitemap, so the four pillars can never drift between those surfaces.
|
||||
|
||||
export type Pillar = {
|
||||
slug: "commerce" | "games" | "crypto" | "education";
|
||||
label: string; // short nav label
|
||||
accent: string; // tailwind colour stem, e.g. "blue"
|
||||
title: string; // on-page H1 / section heading
|
||||
lead: string; // the pillar's paragraph
|
||||
// Per-subpage SEO. Kept distinct so each /services/<slug> ranks for its own terms.
|
||||
metaTitle: string;
|
||||
metaDescription: string;
|
||||
// One line for the hub card, tighter than the lead.
|
||||
card: string;
|
||||
};
|
||||
|
||||
export const pillars: Pillar[] = [
|
||||
{
|
||||
slug: "commerce",
|
||||
label: "Commerce & Web",
|
||||
accent: "blue",
|
||||
title: "Commerce & custom web",
|
||||
lead: "Proprietary, headless commerce and web apps that you own, built to your business logic instead of a template's limits. Often on revenue share: we build, host, and run it, and earn a share once you are live.",
|
||||
card: "Headless commerce and custom web apps you own, often on revenue share.",
|
||||
metaTitle: "Custom E-Commerce & Web App Development | Such Software",
|
||||
metaDescription:
|
||||
"Headless, proprietary commerce and web apps built to your business logic on Medusa and Next.js, hosted on our infrastructure, often on a revenue-share partnership. Kennett Square, PA.",
|
||||
},
|
||||
{
|
||||
slug: "games",
|
||||
label: "Games & Apps",
|
||||
accent: "purple",
|
||||
title: "Games & apps",
|
||||
lead: "We do not just consult on software, we ship it. A growing catalog of games and mobile apps built in-house across iOS, Android, web, and desktop, on Godot and Next.js.",
|
||||
card: "A growing catalog of games and mobile apps we build and ship in-house.",
|
||||
metaTitle: "Games & Mobile App Development | Such Software",
|
||||
metaDescription:
|
||||
"A studio that ships its own titles: games and cross-platform mobile apps built in-house on Godot and Next.js for iOS, Android, web, and desktop. Kennett Square, PA.",
|
||||
},
|
||||
{
|
||||
slug: "crypto",
|
||||
label: "Crypto & Payments",
|
||||
accent: "cyan",
|
||||
title: "Crypto & payments",
|
||||
lead: "Software and integration for payments and cryptocurrency. The client, a licensed processor, or the user's own wallet holds the funds; we build the system around it and never take custody.",
|
||||
card: "Payments and cryptocurrency integration. We never take custody of funds.",
|
||||
metaTitle: "Crypto & Payments Integration Software (Non-Custodial) | Such Software",
|
||||
metaDescription:
|
||||
"Non-custodial payments and cryptocurrency software: Stripe and multi-processor integration, Monero and on-chain checkout, in production since 2014. The processor or wallet holds the funds. Kennett Square, PA.",
|
||||
},
|
||||
{
|
||||
slug: "education",
|
||||
label: "Education & Science",
|
||||
accent: "amber",
|
||||
title: "Education & science",
|
||||
lead: "PhD-led radiation-science teaching, training, and speaking from years at a national lab, plus learning-through-play games that teach real science and math. We publish our methods open-source.",
|
||||
card: "PhD-led radiation-science teaching and games that teach real science.",
|
||||
metaTitle: "Nuclear & Radiation-Science Education, GEANT4 Training | Such Software",
|
||||
metaDescription:
|
||||
"PhD-led radiation-science education: Monte Carlo methods with GEANT4, shielding and detector physics, open-source labs, plus learning-through-play science and math games. Lawrence Livermore background.",
|
||||
},
|
||||
];
|
||||
|
||||
export function pillarBySlug(slug: string): Pillar | undefined {
|
||||
return pillars.find((p) => p.slug === slug);
|
||||
}
|
||||
|
||||
// ---- Proof items (real products behind each pillar) ---------------------
|
||||
|
||||
export type Proof = {
|
||||
title: string;
|
||||
blurb: string;
|
||||
img?: string; // /images/products/*
|
||||
href?: string; // internal detail page or external
|
||||
tag?: string; // status pill
|
||||
};
|
||||
|
||||
const commerceProof: Proof[] = [
|
||||
{ title: "Webshops", blurb: "Our multi-tenant commerce platform: fully-themed storefronts, print-on-demand, non-custodial crypto checkout, and automated tax, on revenue share.", img: "/images/products/occupy-wallets.png", href: "/products/webshops", tag: "Flagship" },
|
||||
{ title: "Custom builds", blurb: "Real-time web apps, multiplayer experiences, and live dashboards on Next.js, Socket.io, and WebRTC.", img: "/images/products/custom-websites.svg", href: "/products/custom-websites", tag: "Live" },
|
||||
{ title: "Grin BTCPay plugin", blurb: "An open-source BTCPay Server plugin we built to accept Grin (Mimblewimble) payments, including auto-Tor invoice exchange.", tag: "Open source" },
|
||||
{ title: "Evaluetron", blurb: "A self-hostable AI-compute platform: one core that runs a personal image bot or a paid multi-customer service, with an append-only credit ledger and pricing built in.", tag: "Building" },
|
||||
];
|
||||
|
||||
const gamesProof: Proof[] = [
|
||||
{ title: "Suchoice", blurb: "Stop overthinking decisions: snap a photo, let AI read the options, spin the wheel. iOS and Android.", img: "/images/products/suchoice.png", href: "/products/suchoice", tag: "Live" },
|
||||
{ title: "Vegan IQ", blurb: "1,000+ plant-based trivia questions across 8 categories, with a daily challenge and weekly quiz. iOS and Android.", img: "/images/products/vegan-iq.png", href: "/products/vegan-iq", tag: "Live" },
|
||||
{ title: "Bloomword", blurb: "A daily word game where every word you find grows a living 3D typographic tree. Free at bloomword.earth, launching on mobile.", img: "/images/products/bloomword.svg", href: "/products/bloomword", tag: "Live" },
|
||||
{ title: "Bauhaus Echo", blurb: "A visual memory puzzle game inspired by Bauhaus design. Android, iOS, and web.", img: "/images/products/bauhaus-echo.png", href: "/products/bauhaus-echo", tag: "Live" },
|
||||
{ title: "Such Moon Launch", blurb: "Vry rocket, much landing, wow: a Wownero-themed pixel rocket arcade with 11 levels and tilt-to-steer. Everywhere.", img: "/images/products/such-moon-launch.png", href: "/products/such-moon-launch", tag: "Live" },
|
||||
];
|
||||
|
||||
const cryptoProof: Proof[] = [
|
||||
{ title: "Payments consulting", blurb: "Stripe and multi-processor integrations, reconciliation tooling, Monero and on-chain integration. The processor or wallet moves the money; we wire it in.", tag: "Service" },
|
||||
{ title: "Smirk Wallet", blurb: "A non-custodial multi-asset browser wallet: send, receive, and tip by username on Telegram and Discord. BTC, LTC, XMR, WOW, GRIN.", img: "/images/products/smirk-wallet.png", href: "/products/smirk-wallet", tag: "Live" },
|
||||
{ title: "Hash Bags", blurb: "A mobile multi-chain wallet forked from Cake Wallet, tuned for the privacy-coin ecosystem.", tag: "Beta" },
|
||||
{ title: "Evaluetron", blurb: "Pay-for-compute done right: an append-only credit ledger, a job queue, and an evaluator that lets on-demand work preempt opportunistic work. Customers can never self-credit.", tag: "Building" },
|
||||
];
|
||||
|
||||
const educationProof: Proof[] = [
|
||||
{ title: "Barns & Neutrons", blurb: "A cozy exploration-puzzle game across the real Table of Nuclides: capture neutrons, coax decays, and learn honest nuclear physics. Our premiere visual work.", img: "/images/products/barns-and-neutrons.svg", href: "/products/barns-and-neutrons", tag: "Coming soon" },
|
||||
{ title: "Nuclear consulting & training", blurb: "PhD-led radiation-science teaching: Monte Carlo methods with GEANT4, shielding and dose fundamentals, detector physics, and open-source labs.", href: "https://jwinterm.github.io/geant4-radiation-labs/", tag: "Service" },
|
||||
{ title: "Numchangers", blurb: "A kids math game (ages 5-8) where numbers morph into dots, shapes, and 3D characters, so arithmetic becomes a visible action instead of a quiz. Godot, mobile-first.", tag: "Early" },
|
||||
];
|
||||
|
||||
export function proofFor(slug: string): Proof[] {
|
||||
if (slug === "commerce") return commerceProof;
|
||||
if (slug === "games") return gamesProof;
|
||||
if (slug === "crypto") return cryptoProof;
|
||||
return educationProof;
|
||||
}
|
||||
|
||||
// ---- FAQ, tagged by pillar so each subpage shows the relevant ones -------
|
||||
|
||||
export type Faq = { q: string; a: string; pillars: Pillar["slug"][] };
|
||||
|
||||
export const faqs: Faq[] = [
|
||||
{ q: "What does Such Software build?", a: "Four things, from one small team: custom e-commerce and web apps on revenue share, games and mobile apps we ship ourselves, cryptocurrency and payments software (integration only, never custody), and PhD-led radiation-science education. The pillars below break each down with the products behind them.", pillars: ["commerce", "games", "crypto", "education"] },
|
||||
{ q: "Do you take revenue-share work?", a: "Yes. For a limited number of partners we build and operate products (such as webshops) for a share of revenue instead of a large upfront fee, so our incentives line up with yours.", pillars: ["commerce"] },
|
||||
{ q: "Do you build for accessibility?", a: "Yes. We engineer front-ends to meet WCAG 2.2 AA and audit against it, alongside Core Web Vitals, as part of every project.", pillars: ["commerce", "games"] },
|
||||
{ q: "Do you offer nuclear and radiation education?", a: "Yes. Our founder holds a PhD in radiation-detector materials and spent six years at Lawrence Livermore National Laboratory, plus shielding and spent-fuel work at Holtec. We teach radiation-science fundamentals and Monte Carlo methods, run GEANT4 training, and speak on these topics. Our GEANT4 radiation labs are published open-source (MIT / CC-BY). This is education and published methods.", pillars: ["education"] },
|
||||
{ q: "Where are you based?", a: "We are a software studio in Kennett Square, Pennsylvania, working with clients remotely across the US and beyond.", pillars: ["commerce", "games", "crypto", "education"] },
|
||||
{ q: "How does a project start?", a: "Reach out through the contact form with what you need. We scope it, propose an approach, and from there it can run as a fixed project or a performance-based revenue-share partnership.", pillars: ["commerce", "crypto"] },
|
||||
];
|
||||
|
||||
// ---- Shared colour maps (literal strings so Tailwind's JIT keeps them) ---
|
||||
|
||||
export const borderL: Record<string, string> = {
|
||||
blue: "border-l-blue-500",
|
||||
purple: "border-l-purple-500",
|
||||
cyan: "border-l-cyan-500",
|
||||
amber: "border-l-amber-500",
|
||||
};
|
||||
export const chipAccent: Record<string, string> = {
|
||||
blue: "bg-blue-500/15 text-blue-700 dark:text-blue-300",
|
||||
purple: "bg-purple-500/15 text-purple-700 dark:text-purple-300",
|
||||
cyan: "bg-cyan-500/15 text-cyan-700 dark:text-cyan-300",
|
||||
amber: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
};
|
||||
export const hoverBorder: Record<string, string> = {
|
||||
blue: "hover:border-blue-500/30",
|
||||
purple: "hover:border-purple-500/30",
|
||||
cyan: "hover:border-cyan-500/30",
|
||||
amber: "hover:border-amber-500/30",
|
||||
};
|
||||
export const tagStyle: Record<string, string> = {
|
||||
Flagship: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
|
||||
Live: "bg-green-500/15 text-green-700 dark:text-green-300",
|
||||
Service: "bg-sky-500/15 text-sky-700 dark:text-sky-300",
|
||||
"Open source": "bg-indigo-500/15 text-indigo-700 dark:text-indigo-300",
|
||||
Beta: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
Building: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
||||
Early: "bg-fuchsia-500/15 text-fuchsia-700 dark:text-fuchsia-300",
|
||||
"Coming soon": "bg-fuchsia-500/15 text-fuchsia-700 dark:text-fuchsia-300",
|
||||
};
|
||||
Reference in New Issue
Block a user