// ============================================================================
// Principia White Paper — Chart library (part 2: flow, economics, structure)
// ============================================================================
// ════════════════════════════════════════════════════════════════════════
// FIG — From 5 intermediaries to zero (settlement flow comparison)
// ════════════════════════════════════════════════════════════════════════
function IntermediaryFlow() {
const [ref, seen] = useReveal();
const today = ['Sender', 'Originating bank', 'Correspondent', 'Correspondent', 'Beneficiary bank', 'Recipient'];
const ours = ['Sender', 'Digital Bank — direct settlement', 'Recipient'];
const Node = ({ label, tone, i, n }) => (
{label}
);
const Arrow = ({ i, danger }) => (
→
);
return (
Today · 5–7 parties
$15–35 per hop · any bank can exit
{today.map((t, i) => (
{i < today.length - 1 && }
))}
Our model · 2 parties
€0.002 per instant payment · cannot be de-risked
{ours.map((t, i) => (
{i < ours.length - 1 && }
))}
);
}
// ════════════════════════════════════════════════════════════════════════
// FIG — Partner economics: net margin per $200 transfer (+105%)
// ════════════════════════════════════════════════════════════════════════
function MarginCompare() {
const [ref, seen] = useReveal();
const mobile = useIsMobile(640);
const H = mobile ? 200 : 300, MAX = 16;
const cols = [
{
title: 'Today', tone: C_DANGER,
segs: [
{ label: 'Net margin', value: 4.0, color: C_INK, net: true, display: '$4.00' },
{ label: 'Compliance + ops', value: 4.0, color: 'rgba(91,107,133,0.45)', display: '–$4.00' },
{ label: 'Intermediary fees', value: 8.0, color: C_DANGER2, display: '–$8.00' },
],
},
{
title: 'On our rails', tone: C_SUCCESS,
segs: [
{ label: 'Net margin', value: 8.2, color: C_SUCCESS, net: true, display: '$8.20' },
{ label: 'Payout (mobile money)', value: 4.0, color: 'rgba(91,107,133,0.45)', display: '–$4.00' },
{ label: 'Our fee (1.90%)', value: 3.8, color: C_ACCENT, display: '–$3.80' },
],
},
];
const netToday = useCountUp(4, seen, { decimals: 2 });
const netOurs = useCountUp(8.2, seen, { decimals: 2 });
return (
{cols.map((col, ci) => (
{col.segs.map((s, si) => (
))}
{col.segs.slice().reverse().map((s, si) => (
))}
{col.title}
${ci === 0 ? netToday : netOurs}
net margin · per $200 transfer
))}
+105%
net margin improvement. Same price to the customer. Same volume — four layers of intermediaries removed.
);
}
// ════════════════════════════════════════════════════════════════════════
// FIG — Competitive matrix (capabilities × providers)
// ════════════════════════════════════════════════════════════════════════
function CompetitiveMatrix() {
const [ref, seen] = useReveal(0.12);
const mobile = useIsMobile(640);
const caps = [
'Direct ECB (TARGET2 / TIPS)',
'Direct BoE (FPS / CHAPS)',
'Nordic direct (SEK / DKK / NOK)',
'MC / Visa principal membership',
'Own POS acquiring stack',
'Sub-Saharan Africa corridor',
'Zero intermediary dependency',
];
// 2 = full, 1 = partial, 0 = none
const providers = [
{ name: 'Banking Circle', vals: [2, 0, 1, 0, 0, 0, 0], score: '2 / 7' },
{ name: 'ClearBank', vals: [0, 2, 0, 0, 0, 0, 0], score: '1 / 7' },
{ name: 'Modulr', vals: [0, 0, 0, 2, 0, 0, 0], score: '1 / 7' },
{ name: 'Digital Bank', vals: [2, 2, 2, 2, 2, 2, 2], score: '7 / 7', us: true },
];
const Dot = ({ v, us, delay }) => {
const color = v === 2 ? (us ? '#fff' : C_INK) : v === 1 ? C_ACCENT : 'transparent';
return (
{v === 1 ? (
) : v === 2 ? (
) : (
)}
);
};
if (mobile) {
const StatusIcon = ({ v }) => v === 2 ? ✓ : v === 1 ? ½ : —;
return (
{providers.map((p) => (
{caps.map((cap, ri) => (
{cap}
))}
))}
✓ Full
½ Partial
— None
);
}
return (
{/* header */}
{providers.map((p) => (
))}
{/* rows */}
{caps.map((cap, ri) => (
{cap}
{providers.map((p) => (
))}
))}
{/* score */}
Score
{providers.map((p) => (
{p.score}
))}
Full
Partial
None
);
}
// ════════════════════════════════════════════════════════════════════════
// FIG — Five currencies, five central banks, direct (hub diagram)
// ════════════════════════════════════════════════════════════════════════
function CentralBanksDiagram() {
const [ref, seen] = useReveal();
const banks = [
{ cur: 'EUR', bank: 'ECB', rail: 'TARGET2 / TIPS' },
{ cur: 'GBP', bank: 'Bank of England', rail: 'FPS / CHAPS' },
{ cur: 'SEK', bank: 'Riksbanken', rail: 'RIX' },
{ cur: 'DKK', bank: 'Nationalbanken', rail: 'TARGET DKK' },
{ cur: 'NOK', bank: 'Norges Bank', rail: 'NBO' },
];
return (
One licence
Lithuanian specialised bank
{banks.map((b, i) => (
{b.cur}
{b.bank}
{b.rail}
))}
No correspondent bank required for any major European currency
);
}
// ════════════════════════════════════════════════════════════════════════
// FIG — Settlement rails table (currency lanes)
// ════════════════════════════════════════════════════════════════════════
function CurrencyRails() {
const [ref, seen] = useReveal(0.15);
const mobile = useIsMobile(640);
const rows = [
{ cur: 'EUR', rail: 'TARGET2 / TIPS', cost: '€0.002', speed: '<10 sec', entity: 'Lithuanian specialised bank — direct ECB' },
{ cur: 'GBP', rail: 'FPS / CHAPS', cost: '£0.487', speed: '<2 sec', entity: 'PRA branch — Year 2 (CHAPS direct)' },
{ cur: 'SEK', rail: 'RIX-INST', cost: '~SEK 0.02', speed: '<10 sec', entity: 'Direct — Riksbanken (Apr 2025, TIPS-based)' },
{ cur: 'DKK', rail: 'TARGET DKK', cost: '~DKK 0.015', speed: '<10 sec', entity: 'Direct — ECB TIPS infrastructure' },
{ cur: 'NOK', rail: 'NBO', cost: 'Fixed fee', speed: 'Same-day', entity: 'Direct — Norges Bank (NBO INST H1 2028)' },
];
if (mobile) {
return (
{rows.map((r, i) => (
))}
);
}
return (
Cur.
Rail
Cost / txn
Speed
Settlement entity
{rows.map((r, i) => (
{r.cur}
{r.rail}
{r.cost}
{r.speed}
{r.entity}
))}
);
}
// ════════════════════════════════════════════════════════════════════════
// FIG — Partner onboarding timeline (Day 1 → 7)
// ════════════════════════════════════════════════════════════════════════
function OnboardingTimeline() {
const [ref, seen] = useReveal();
const steps = [
{ day: '1–3', t: 'Onboarding & due diligence', d: 'EDD, AML/CTF policy & procedures, external audit document. KYC/KYB. Sanctions screening. Risk assessment.' },
{ day: '3–4', t: 'Account setup', d: 'Segregated safeguarding account. API credentials. Sandbox access.' },
{ day: '4–5', t: 'Integration', d: 'Iframe drop-in or API integration. Test transactions in sandbox.' },
{ day: '5–7', t: 'Go-live', d: 'Production switch. First live transaction. Settlement cycle begins.' },
];
return (
{steps.map((s, i) => (
{i + 1}
Day {s.day}
{s.t}
{s.d}
))}
);
}
// ════════════════════════════════════════════════════════════════════════
// FIG — Platform architecture (layered stack)
// ════════════════════════════════════════════════════════════════════════
function ArchitectureStack() {
const [ref, seen] = useReveal(0.12);
const layers = [
{ name: 'Regulatory', items: [
['EU', 'Lithuanian specialised bank', 'EEA passporting · SEPA direct · MC/Visa principal'],
['UK', 'PRA branch', 'BoE settlement · FPS/CHAPS · Year 2'],
['Nordics', 'Direct clearing', 'Riksbanken · Nationalbanken · Norges Bank'],
] },
{ name: 'Infrastructure', items: [
['Core banking', 'Mambu', 'Cloud SaaS · ledger · FX engine'],
['Payments', 'SWIFT + TIPS', 'Own BIC · HSM + PKI · direct participant'],
['Cards', 'MC/Visa principal', 'Own BIN · issuing + acquiring'],
['Risk', 'Onfido / Sumsub', 'KYC/AML · Chainalysis · Dow Jones screening'],
] },
{ name: 'Partner', items: [
['API', 'REST / GraphQL', 'OpenAPI 3.0 · OAuth 2.0 · webhooks'],
['Gateway', 'Hosted iframe + SDK', 'PCI-compliant · 48-hour go-live'],
['Portal', 'Dashboard', 'Transactions · settlements · reconciliation'],
] },
];
return (
{layers.map((layer, li) => (
Layer {li + 1}
{layer.name}
{layer.items.map((it, ii) => (
))}
))}
);
}
Object.assign(window, {
IntermediaryFlow, MarginCompare, CompetitiveMatrix, CentralBanksDiagram,
CurrencyRails, OnboardingTimeline, ArchitectureStack,
});