Safe Note Calculator
blockfinanceY Combinator Post-Money SAFE note valuation, conversion share price, effective discount, and cap table equity dilution simulator with interactive parameter controls and Series A financing sensitivity matrix.
Installation
$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/safe-note-calculator.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/safe-note-calculator.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/safe-note-calculator.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/safe-note-calculator.jsonNamed registry:
npx shadcn-vue@latest add @uipkge/safe-note-calculatorInstalls to:app/components/blocks/Variants
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
class | HTMLAttributes['class'] | — | optional |
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
PresetConfiginterface PresetConfig {
id: RoundPreset
label: string
investment: number
valuationCap: number
hasDiscount: boolean
discountRate: number
shares: number
seriesAPreMoney: number
description: string
}Files installed (1)
app/components/blocks/SafeNoteCalculator.vue37.8 kB
<script setup lang="ts"> import { computed, ref, type HTMLAttributes } from 'vue' import { BadgePercent, Check, CheckCircle2, Copy, DollarSign, FileSpreadsheet, Layers, Percent, PieChart, Scale, ShieldCheck, TrendingUp, } from 'lucide-vue-next' import { cn } from '@/lib/utils' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Separator } from '@/components/ui/separator' import { Slider } from '@/components/ui/slider' import { Switch } from '@/components/ui/switch' import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() type RoundPreset = 'seed-standard' | 'preseed-safe' | 'uncapped-discount' | 'bridge-round' interface PresetConfig { id: RoundPreset label: string investment: number valuationCap: number hasDiscount: boolean discountRate: number shares: number seriesAPreMoney: number description: string } const PRESETS: Record<RoundPreset, PresetConfig> = { 'seed-standard': { id: 'seed-standard', label: 'Standard Seed ($1M @ $15M)', investment: 1_000_000, valuationCap: 15_000_000, hasDiscount: true, discountRate: 20, shares: 10_000_000, seriesAPreMoney: 25_000_000, description: 'Standard YC Post-Money SAFE with $15M valuation cap and optional 20% discount clause.', }, 'preseed-safe': { id: 'preseed-safe', label: 'Pre-Seed ($500K @ $8M)', investment: 500_000, valuationCap: 8_000_000, hasDiscount: true, discountRate: 20, shares: 10_000_000, seriesAPreMoney: 18_000_000, description: 'Early-stage angel or accelerator round with $8M valuation cap.', }, 'uncapped-discount': { id: 'uncapped-discount', label: 'Uncapped (25% Disc)', investment: 750_000, valuationCap: 60_000_000, hasDiscount: true, discountRate: 25, shares: 10_000_000, seriesAPreMoney: 20_000_000, description: 'High valuation cap structure where the 25% discount governs share conversion price.', }, 'bridge-round': { id: 'bridge-round', label: 'Growth Bridge ($2M @ $25M)', investment: 2_000_000, valuationCap: 25_000_000, hasDiscount: true, discountRate: 15, shares: 10_000_000, seriesAPreMoney: 45_000_000, description: 'Late seed extension bridging into a larger institutional Series A equity round.', }, } const INVESTMENT_MARKS = { 100000: '$100K', 1000000: '$1M', 2500000: '$2.5M', 5000000: '$5M', } const VALUATION_CAP_MARKS = { 2000000: '$2M', 15000000: '$15M', 30000000: '$30M', 50000000: '$50M', } const DISCOUNT_RATE_MARKS = { 10: '10%', 15: '15%', 20: '20%', 25: '25%', 30: '30%', } const SERIES_A_MARKS = { 5000000: '$5M', 25000000: '$25M', 50000000: '$50M', 80000000: '$80M', } const SCENARIO_VALUATIONS = [10_000_000, 15_000_000, 20_000_000, 25_000_000, 40_000_000, 60_000_000] const selectedPreset = ref<RoundPreset>('seed-standard') const investmentAmount = ref(1_000_000) const valuationCap = ref(15_000_000) const hasDiscount = ref(true) const discountRate = ref(20) const companyCapitalization = ref(10_000_000) const seriesAPreMoney = ref(25_000_000) const copied = ref(false) function handlePresetChange(value: string | number) { const presetId = String(value) as RoundPreset selectedPreset.value = presetId const preset = PRESETS[presetId] if (preset) { investmentAmount.value = preset.investment valuationCap.value = preset.valuationCap hasDiscount.value = preset.hasDiscount discountRate.value = preset.discountRate companyCapitalization.value = preset.shares seriesAPreMoney.value = preset.seriesAPreMoney } } // Core SAFE conversion economics const calculations = computed(() => { const inv = Math.max(1, investmentAmount.value) const cap = Math.max(1, valuationCap.value) const shares = Math.max(1, companyCapitalization.value) const seriesA = Math.max(1, seriesAPreMoney.value) const disc = hasDiscount.value ? Math.max(0, Math.min(99, discountRate.value)) : 0 // Series A unqualified price per share const seriesAPricePerShare = seriesA / shares // Cap conversion price per share const capPricePerShare = cap / shares // Discount conversion price per share const discountPricePerShare = hasDiscount.value ? seriesAPricePerShare * (1 - disc / 100) : seriesAPricePerShare // In YC Post-Money SAFE, investor converts at the lower of Cap Price or Discount Price let conversionPrice = capPricePerShare let governingMechanism: 'cap' | 'discount' = 'cap' if (hasDiscount.value && discountPricePerShare < capPricePerShare) { conversionPrice = discountPricePerShare governingMechanism = 'discount' } else { conversionPrice = capPricePerShare governingMechanism = 'cap' } // Converted shares issued const safeShares = conversionPrice > 0 ? Math.round(inv / conversionPrice) : 0 // Equity percentage calculation const safeOwnershipPct = Math.min(100, Math.max(0, (safeShares / shares) * 100)) const founderShares = Math.max(0, shares - safeShares) const founderOwnershipPct = Math.max(0, 100 - safeOwnershipPct) // Effective discount achieved vs Series A price const effectiveDiscountPct = seriesAPricePerShare > 0 ? Math.max(0, ((seriesAPricePerShare - conversionPrice) / seriesAPricePerShare) * 100) : 0 // Implied Value of SAFE stake at Series A price const impliedSeriesAValue = safeShares * seriesAPricePerShare const valueGain = Math.max(0, impliedSeriesAValue - inv) const paperRoiMultiple = inv > 0 ? impliedSeriesAValue / inv : 1 return { seriesAPricePerShare, capPricePerShare, discountPricePerShare, conversionPrice, governingMechanism, safeShares, founderShares, totalShares: shares, safeOwnershipPct, founderOwnershipPct, effectiveDiscountPct, impliedSeriesAValue, valueGain, paperRoiMultiple, } }) // Sensitivity scenarios across different Series A pre-money valuations const scenarioResults = computed(() => { const inv = Math.max(1, investmentAmount.value) const cap = Math.max(1, valuationCap.value) const shares = Math.max(1, companyCapitalization.value) const disc = hasDiscount.value ? Math.max(0, Math.min(99, discountRate.value)) : 0 return SCENARIO_VALUATIONS.map((scenarioValuation) => { const seriesAPrice = scenarioValuation / shares const capPrice = cap / shares const discountPrice = hasDiscount.value ? seriesAPrice * (1 - disc / 100) : seriesAPrice let convPrice = capPrice let mechanism = 'Valuation Cap' if (hasDiscount.value && discountPrice < capPrice) { convPrice = discountPrice mechanism = `Discount (${disc}%)` } const issuedShares = convPrice > 0 ? Math.round(inv / convPrice) : 0 const ownershipPct = (issuedShares / shares) * 100 const effectiveDiscount = seriesAPrice > 0 ? Math.max(0, ((seriesAPrice - convPrice) / seriesAPrice) * 100) : 0 const impliedValue = issuedShares * seriesAPrice const isCurrentTarget = scenarioValuation === seriesAPreMoney.value return { valuation: scenarioValuation, seriesAPrice, convPrice, mechanism, issuedShares, ownershipPct, effectiveDiscount, impliedValue, isCurrentTarget, } }) }) // Number & Currency Formatters const fmtCurrency = (val: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(val || 0) } const fmtCurrencyWhole = (val: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(val || 0) } const fmtPercent = (val: number, decimals = 2) => { return `${(val || 0).toFixed(decimals)}%` } const fmtNumber = (val: number) => { return new Intl.NumberFormat('en-US', { maximumFractionDigits: 0, }).format(val || 0) } function copySummary() { const c = calculations.value const text = `YC Post-Money SAFE Conversion Summary: - Investment Amount: ${fmtCurrency(investmentAmount.value)} - Valuation Cap: ${fmtCurrency(valuationCap.value)} - Series A Target: ${fmtCurrency(seriesAPreMoney.value)} Pre-Money - Investor Ownership: ${fmtPercent(c.safeOwnershipPct)} (${fmtNumber(c.safeShares)} shares) - Conversion Price: ${fmtCurrency(c.conversionPrice)} / share (vs Series A ${fmtCurrency(c.seriesAPricePerShare)}) - Effective Discount: ${fmtPercent(c.effectiveDiscountPct)} - Governing Term: ${c.governingMechanism === 'cap' ? 'Valuation Cap' : 'Discount Rate'}` navigator.clipboard?.writeText(text) copied.value = true setTimeout(() => { copied.value = false }, 2000) } </script> <template> <div data-slot="safe-note-calculator" :class="cn('mx-auto w-full max-w-6xl space-y-8 p-4 sm:p-6 lg:p-8', props.class)" > <!-- Header --> <div class="flex flex-col items-center gap-4 text-center"> <Badge wrap variant="outline" class="gap-1.5 px-3 py-1 text-xs font-medium tracking-wider uppercase"> <Scale class="text-primary size-3.5" /> YC Post-Money SAFE v1.1 · Valuation Cap + Discount </Badge> <div class="space-y-2"> <h2 class="text-foreground text-2xl font-bold tracking-tight sm:text-3xl lg:text-4xl"> Y Combinator Post-Money SAFE Calculator </h2> <p class="text-muted-foreground mx-auto max-w-2xl text-sm sm:text-base"> Model founder dilution, investor ownership percentages, and conversion price per share. </p> </div> <!-- Preset Tabs --> <div class="mt-2 flex w-full justify-center"> <Tabs :model-value="selectedPreset" @update:model-value="handlePresetChange" class="w-full sm:w-auto"> <TabsList variant="segmented" class="grid w-full grid-cols-2 sm:flex sm:w-auto"> <TabsTrigger value="seed-standard" class="gap-1.5"> <ShieldCheck class="size-3.5" /> Standard Seed </TabsTrigger> <TabsTrigger value="preseed-safe" class="gap-1.5"> <TrendingUp class="size-3.5" /> Pre-Seed SAFE </TabsTrigger> <TabsTrigger value="uncapped-discount" class="gap-1.5"> <BadgePercent class="size-3.5" /> Uncapped Disc </TabsTrigger> <TabsTrigger value="bridge-round" class="gap-1.5"> <Layers class="size-3.5" /> Growth Bridge </TabsTrigger> </TabsList> </Tabs> </div> </div> <!-- 2-Column Calculator Layout --> <div class="grid grid-cols-1 gap-8 lg:grid-cols-12 lg:items-start"> <!-- Left Input Card --> <div class="space-y-6 lg:col-span-7"> <Card> <CardHeader> <CardTitle class="flex items-center gap-2"> <DollarSign class="text-primary size-5" /> SAFE Terms & Round Inputs </CardTitle> <CardDescription> Configure investment size, valuation cap, optional discount rate, capitalization, and Series A targets. </CardDescription> </CardHeader> <CardContent class="space-y-7"> <!-- 1. Investment Amount --> <div class="space-y-3.5"> <div class="flex items-center justify-between gap-4"> <div> <span class="text-foreground text-sm font-medium">Investment Amount</span> <p class="text-muted-foreground text-xs">Total cash invested into the SAFE.</p> </div> <div class="w-36 sm:w-44"> <Input id="safe-investment-input" type="number" size="small" :min="25000" :max="10000000" :step="25000" prefix="$" :model-value="investmentAmount" @update:model-value="(val) => (investmentAmount = Number(val) || 0)" /> </div> </div> <div class="pb-5"> <Slider :model-value="investmentAmount" :min="100000" :max="5000000" :step="25000" :marks="INVESTMENT_MARKS" :tooltip="(val) => `$${val.toLocaleString('en-US')}`" @update:model-value="(val) => (investmentAmount = typeof val === 'number' ? val : val[0])" /> </div> <div class="flex flex-wrap items-center gap-1.5 pt-1"> <span class="text-muted-foreground text-xs">Quick select:</span> <Button v-for="amt in [250000, 500000, 1000000, 1500000, 2000000, 3000000]" :key="amt" variant="outline" size="sm" class="h-6 px-2 text-xs" @click="investmentAmount = amt" > ${{ amt >= 1000000 ? `${(amt / 1000000).toFixed(amt % 1000000 === 0 ? 0 : 1)}M` : `${amt / 1000}K` }} </Button> </div> </div> <Separator /> <!-- 2. Post-Money Valuation Cap --> <div class="space-y-3.5"> <div class="flex items-center justify-between gap-4"> <div> <span class="text-foreground text-sm font-medium">Post-Money Valuation Cap</span> <p class="text-muted-foreground text-xs">Maximum valuation ceiling for conversion.</p> </div> <div class="w-36 sm:w-44"> <Input id="safe-cap-input" type="number" size="small" :min="500000" :max="100000000" :step="500000" prefix="$" :model-value="valuationCap" @update:model-value="(val) => (valuationCap = Number(val) || 0)" /> </div> </div> <div class="pb-5"> <Slider :model-value="valuationCap" :min="2000000" :max="50000000" :step="500000" :marks="VALUATION_CAP_MARKS" :tooltip="(val) => `$${val.toLocaleString('en-US')}`" @update:model-value="(val) => (valuationCap = typeof val === 'number' ? val : val[0])" /> </div> <div class="flex flex-wrap items-center gap-1.5 pt-1"> <span class="text-muted-foreground text-xs">Cap benchmarks:</span> <Button v-for="cap in [5000000, 8000000, 12000000, 15000000, 20000000, 30000000]" :key="cap" variant="outline" size="sm" class="h-6 px-2 text-xs" @click="valuationCap = cap" > ${{ (cap / 1000000).toFixed(0) }}M </Button> </div> </div> <Separator /> <!-- 3. Discount Rate Input & Toggle --> <div class="space-y-3.5"> <div class="flex items-center justify-between gap-4"> <div class="space-y-1"> <div class="flex items-center gap-2"> <span class="text-foreground text-sm font-medium">Discount Rate Clause</span> <Badge wrap v-if="hasDiscount" variant="outline" class="border-success/20 bg-success/10 text-success text-xs font-normal" > Active </Badge> <Badge wrap v-else variant="outline" class="text-muted-foreground text-xs font-normal"> Cap Only </Badge> </div> <p class="text-muted-foreground text-xs"> Percentage discount on Series A price if cap is not exceeded. </p> </div> <div class="flex flex-wrap items-center gap-3"> <Switch :model-value="hasDiscount" @update:model-value="(val) => (hasDiscount = val)" aria-label="Toggle discount clause" /> <div v-if="hasDiscount" class="w-24 sm:w-28"> <Input id="safe-discount-input" type="number" size="small" :min="0" :max="50" :step="1" suffix="%" :model-value="discountRate" @update:model-value="(val) => (discountRate = Number(val) || 0)" /> </div> </div> </div> <div v-if="hasDiscount" class="space-y-3 pt-1"> <div class="pb-5"> <Slider :model-value="discountRate" :min="5" :max="35" :step="1" :marks="DISCOUNT_RATE_MARKS" :tooltip="(val) => `${val}% Discount`" @update:model-value="(val) => (discountRate = typeof val === 'number' ? val : val[0])" /> </div> <div class="flex flex-wrap items-center gap-1.5 pt-1"> <span class="text-muted-foreground text-xs">Standard rates:</span> <Button v-for="rate in [10, 15, 20, 25, 30]" :key="rate" :variant="discountRate === rate ? 'default' : 'outline'" size="sm" class="h-6 px-2 text-xs" @click="discountRate = rate" > {{ rate }}% </Button> </div> </div> </div> <Separator /> <!-- 4. Company Existing Capitalization --> <div class="space-y-3.5"> <div class="flex items-center justify-between gap-4"> <div> <span class="text-foreground text-sm font-medium">Company Existing Capitalization</span> <p class="text-muted-foreground text-xs">Total pre-conversion issued shares and option pool.</p> </div> <div class="w-36 sm:w-44"> <Input id="safe-shares-input" type="number" size="small" :min="1000000" :max="100000000" :step="500000" suffix="Shares" :model-value="companyCapitalization" @update:model-value="(val) => (companyCapitalization = Number(val) || 0)" /> </div> </div> <div class="flex flex-wrap items-center gap-1.5 pt-1"> <span class="text-muted-foreground text-xs">Common share counts:</span> <Button v-for="count in [5000000, 8000000, 10000000, 12000000, 15000000]" :key="count" :variant="companyCapitalization === count ? 'default' : 'outline'" size="sm" class="h-6 px-2 text-xs" @click="companyCapitalization = count" > {{ (count / 1000000).toFixed(0) }}M Shares </Button> </div> </div> <Separator /> <!-- 5. Series A Pre-Money Target --> <div class="space-y-3.5"> <div class="flex items-center justify-between gap-4"> <div> <span class="text-foreground text-sm font-medium">Series A Pre-Money Target</span> <p class="text-muted-foreground text-xs">Target qualified financing equity valuation.</p> </div> <div class="w-36 sm:w-44"> <Input id="safe-series-a-input" type="number" size="small" :min="1000000" :max="200000000" :step="1000000" prefix="$" :model-value="seriesAPreMoney" @update:model-value="(val) => (seriesAPreMoney = Number(val) || 0)" /> </div> </div> <div class="pb-5"> <Slider :model-value="seriesAPreMoney" :min="5000000" :max="80000000" :step="1000000" :marks="SERIES_A_MARKS" :tooltip="(val) => `$${val.toLocaleString('en-US')}`" @update:model-value="(val) => (seriesAPreMoney = typeof val === 'number' ? val : val[0])" /> </div> <div class="flex flex-wrap items-center gap-1.5 pt-1"> <span class="text-muted-foreground text-xs">Series A benchmarks:</span> <Button v-for="target in [15000000, 20000000, 25000000, 35000000, 50000000, 75000000]" :key="target" variant="outline" size="sm" class="h-6 px-2 text-xs" @click="seriesAPreMoney = target" > ${{ (target / 1000000).toFixed(0) }}M </Button> </div> </div> </CardContent> </Card> </div> <!-- Right Results Card (Sticky on desktop) --> <div class="lg:sticky lg:top-8 lg:col-span-5"> <Card class="border-border bg-card shadow-xs"> <CardHeader class="pb-4"> <div class="flex items-center justify-between"> <span class="text-muted-foreground text-xs font-semibold tracking-wider uppercase"> Investor Ownership Stake </span> <Badge wrap variant="secondary" :class=" calculations.governingMechanism === 'cap' ? 'bg-primary/10 text-primary border-primary/20 text-xs font-semibold' : 'border-success/20 bg-success/10 text-success text-xs font-semibold' " > {{ calculations.governingMechanism === 'cap' ? 'Cap Governs' : 'Discount Governs' }} </Badge> </div> <div class="mt-4"> <div class="flex items-baseline gap-2"> <span class="text-foreground text-3xl font-bold tracking-tight tabular-nums sm:text-4xl"> {{ fmtPercent(calculations.safeOwnershipPct) }} </span> <span class="text-muted-foreground text-sm font-medium">Post-SAFE Ownership</span> </div> <p class="text-muted-foreground mt-1 text-xs"> SAFE investor receives <span class="text-foreground font-semibold tabular-nums">{{ fmtNumber(calculations.safeShares) }}</span> shares at conversion. </p> </div> </CardHeader> <CardContent class="space-y-5"> <Separator /> <!-- Key Economics Metrics Grid --> <div class="grid grid-cols-1 gap-3 sm:grid-cols-2"> <div class="bg-muted/40 rounded-lg border p-3"> <span class="text-muted-foreground block text-xs">SAFE Conversion Price</span> <span class="text-foreground text-base font-bold tabular-nums"> {{ fmtCurrency(calculations.conversionPrice) }} </span> <span class="text-muted-foreground block text-xs tabular-nums"> vs Series A {{ fmtCurrency(calculations.seriesAPricePerShare) }} </span> </div> <div class="bg-muted/40 rounded-lg border p-3"> <span class="text-muted-foreground block text-xs">Converted Shares Issued</span> <span class="text-foreground text-base font-bold tabular-nums"> {{ fmtNumber(calculations.safeShares) }} </span> <span class="text-muted-foreground block text-xs">Equity units</span> </div> <div class="bg-muted/40 rounded-lg border p-3"> <span class="text-muted-foreground block text-xs">Effective Discount</span> <span class="text-success text-success text-base font-bold tabular-nums"> {{ fmtPercent(calculations.effectiveDiscountPct) }} </span> <span class="text-muted-foreground block text-xs">Savings vs Series A</span> </div> <div class="bg-muted/40 rounded-lg border p-3"> <span class="text-muted-foreground block text-xs">Implied Series A Value</span> <span class="text-foreground text-base font-bold tabular-nums"> {{ fmtCurrencyWhole(calculations.impliedSeriesAValue) }} </span> <span class="text-success text-success block text-xs tabular-nums"> +{{ fmtCurrencyWhole(calculations.valueGain) }} ({{ calculations.paperRoiMultiple.toFixed(2) }}x) </span> </div> </div> <Separator /> <!-- Visual Equity Distribution Bar --> <div class="space-y-2.5"> <div class="flex items-center justify-between text-xs font-medium"> <span class="text-foreground">Founders vs. SAFE Investor</span> <span class="text-muted-foreground tabular-nums"> {{ fmtPercent(calculations.founderOwnershipPct) }} / {{ fmtPercent(calculations.safeOwnershipPct) }} </span> </div> <div class="bg-muted relative flex h-3 w-full overflow-hidden rounded-full shadow-inner"> <div class="bg-primary h-full transition-[width] duration-300" :style="{ width: `${calculations.founderOwnershipPct}%` }" /> <div class="bg-success h-full transition-[width] duration-300" :style="{ width: `${calculations.safeOwnershipPct}%` }" /> </div> <div class="text-muted-foreground flex flex-col gap-1.5 text-xs sm:flex-row sm:items-center sm:justify-between" > <div class="flex items-center gap-1.5"> <span class="bg-primary size-2 shrink-0 rounded-full" /> <span >Founders: {{ fmtPercent(calculations.founderOwnershipPct) }} ({{ fmtNumber(calculations.founderShares) }} sh)</span > </div> <div class="flex items-center gap-1.5"> <span class="bg-success size-2 shrink-0 rounded-full" /> <span >SAFE: {{ fmtPercent(calculations.safeOwnershipPct) }} ({{ fmtNumber(calculations.safeShares) }} sh)</span > </div> </div> </div> <Separator /> <!-- Post-Conversion Dilution Breakdown Table --> <div class="space-y-2"> <span class="text-foreground text-xs font-semibold tracking-wider uppercase"> Post-Conversion Dilution Breakdown </span> <div class="overflow-hidden rounded-lg border"> <div class="overflow-x-auto"> <Table density="compact"> <TableHeader> <TableRow> <TableHead class="text-xs">Stakeholder</TableHead> <TableHead class="text-right text-xs">Ownership</TableHead> <TableHead class="text-right text-xs">Shares</TableHead> <TableHead class="text-right text-xs">Implied Value</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell class="text-xs font-medium">Founders & Existing</TableCell> <TableCell class="text-right text-xs font-medium tabular-nums"> {{ fmtPercent(calculations.founderOwnershipPct) }} </TableCell> <TableCell class="text-right text-xs tabular-nums"> {{ fmtNumber(calculations.founderShares) }} </TableCell> <TableCell class="text-right text-xs tabular-nums"> {{ fmtCurrencyWhole(calculations.founderShares * calculations.seriesAPricePerShare) }} </TableCell> </TableRow> <TableRow> <TableCell class="text-success text-xs font-medium"> SAFE Seed Investors </TableCell> <TableCell class="text-success text-success text-right text-xs font-bold tabular-nums"> {{ fmtPercent(calculations.safeOwnershipPct) }} </TableCell> <TableCell class="text-right text-xs font-semibold tabular-nums"> {{ fmtNumber(calculations.safeShares) }} </TableCell> <TableCell class="text-right text-xs font-semibold tabular-nums"> {{ fmtCurrencyWhole(calculations.impliedSeriesAValue) }} </TableCell> </TableRow> </TableBody> <TableFooter> <TableRow> <TableCell class="text-xs font-bold">Total Post-SAFE</TableCell> <TableCell class="text-right text-xs font-bold tabular-nums">100.00%</TableCell> <TableCell class="text-right text-xs font-bold tabular-nums"> {{ fmtNumber(calculations.totalShares) }} </TableCell> <TableCell class="text-right text-xs font-bold tabular-nums"> {{ fmtCurrencyWhole(seriesAPreMoney) }} </TableCell> </TableRow> </TableFooter> </Table> </div> </div> </div> <Separator /> <!-- Key SAFE Takeaways Checklist --> <ul class="text-muted-foreground space-y-2 text-xs"> <li class="flex items-center gap-2"> <CheckCircle2 class="text-primary size-3.5 shrink-0" /> <span>Post-money cap fixes ownership before Series A round</span> </li> <li class="flex items-center gap-2"> <CheckCircle2 class="text-primary size-3.5 shrink-0" /> <span>Converts to Preferred Stock with investor liquidation preference</span> </li> <li class="flex items-center gap-2"> <CheckCircle2 class="text-primary size-3.5 shrink-0" /> <span>No debt maturity dates, no interest accrual compounding</span> </li> </ul> </CardContent> <CardFooter class="flex flex-col gap-2.5 pt-2"> <Button class="w-full gap-2 font-semibold shadow-xs" size="lg" @click="copySummary"> <Check v-if="copied" class="text-success size-4" /> <Copy v-else class="size-4" /> {{ copied ? 'Copied Summary to Clipboard!' : 'Copy Valuation Breakdown' }} </Button> <Button variant="outline" class="w-full gap-2" size="default"> <FileSpreadsheet class="size-4" /> Export Cap Table Summary </Button> </CardFooter> </Card> </div> </div> <!-- Bottom Section: Series A Valuation Sensitivity Table --> <Card> <CardHeader class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between"> <div> <CardTitle class="flex items-center gap-2"> <TrendingUp class="text-primary size-5" /> Series A Qualified Financing Sensitivity Matrix </CardTitle> <CardDescription> Simulate how SAFE investor ownership percentage, share price, and conversion mechanism respond across different next-round valuations. </CardDescription> </div> </CardHeader> <CardContent> <div class="overflow-x-auto"> <Table density="cozy"> <TableHeader> <TableRow> <TableHead>Series A Valuation</TableHead> <TableHead class="text-right">Series A Price</TableHead> <TableHead class="text-right">SAFE Conversion Price</TableHead> <TableHead>Governing Term</TableHead> <TableHead class="text-right">Shares Issued</TableHead> <TableHead class="text-right">SAFE Ownership</TableHead> <TableHead class="text-right">Effective Savings</TableHead> <TableHead class="text-right">Implied Stake Value</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow v-for="row in scenarioResults" :key="row.valuation" :class="row.isCurrentTarget ? 'bg-primary/5 font-medium' : ''" > <TableCell class="font-medium"> <div class="flex items-center gap-2"> <span class="tabular-nums">{{ fmtCurrencyWhole(row.valuation) }}</span> <Badge wrap v-if="row.isCurrentTarget" variant="default" class="h-5 px-1.5 text-xs"> Current Target </Badge> </div> </TableCell> <TableCell class="text-right tabular-nums">{{ fmtCurrency(row.seriesAPrice) }}</TableCell> <TableCell class="text-foreground text-right font-semibold tabular-nums"> {{ fmtCurrency(row.convPrice) }} </TableCell> <TableCell> <Badge wrap variant="outline" :class=" row.mechanism === 'Valuation Cap' ? 'border-primary/20 bg-primary/10 text-primary text-xs' : 'border-success/20 bg-success/10 text-success text-xs' " > {{ row.mechanism }} </Badge> </TableCell> <TableCell class="text-right tabular-nums">{{ fmtNumber(row.issuedShares) }}</TableCell> <TableCell class="text-foreground text-right font-bold tabular-nums"> {{ fmtPercent(row.ownershipPct) }} </TableCell> <TableCell class="text-success text-success text-right font-medium tabular-nums"> {{ fmtPercent(row.effectiveDiscount) }} </TableCell> <TableCell class="text-right font-semibold tabular-nums"> {{ fmtCurrencyWhole(row.impliedValue) }} </TableCell> </TableRow> </TableBody> </Table> </div> </CardContent> </Card> <!-- Post-Money SAFE Legal & Governance Guide --> <div class="grid grid-cols-1 gap-4 sm:grid-cols-3"> <Card class="p-4"> <div class="flex items-start gap-3"> <div class="bg-primary/10 text-primary mt-0.5 rounded-md p-2"> <ShieldCheck class="size-4" /> </div> <div class="space-y-1"> <h4 class="text-foreground text-sm font-semibold">Post-Money Cap Protection</h4> <p class="text-muted-foreground text-xs leading-relaxed"> Acts as an ownership percentage guarantee for seed investors prior to the priced round, regardless of subsequent SAFE issuances. </p> </div> </div> </Card> <Card class="p-4"> <div class="flex items-start gap-3"> <div class="bg-success/10 text-success mt-0.5 rounded-md p-2"> <Percent class="size-4" /> </div> <div class="space-y-1"> <h4 class="text-foreground text-sm font-semibold">Discount Rate Safety Net</h4> <p class="text-muted-foreground text-xs leading-relaxed"> Protects investors if Series A prices below the valuation cap, guaranteeing a 15%–25% discount off the institutional share price. </p> </div> </div> </Card> <Card class="p-4"> <div class="flex items-start gap-3"> <div class="bg-warning/10 text-warning mt-0.5 rounded-md p-2"> <PieChart class="size-4" /> </div> <div class="space-y-1"> <h4 class="text-foreground text-sm font-semibold">Founder Dilution Transparency</h4> <p class="text-muted-foreground text-xs leading-relaxed"> YC v1.1 post-money SAFEs dilute only founders and common shareholders, eliminating pre-money SAFE circular dilution surprises. </p> </div> </div> </Card> </div> </div> </template>
Raw manifest:https://uipkge.dev/r/vue/safe-note-calculator.json