랜딩 페이지: D3RO 브랜드 프로모션 사이트 + GitHub Pages 배포

- Vite + React 19 + Tailwind CSS
- 4가지 디자인 레퍼런스 통합 (CRT 스크린, 크로스헤어, 노이즈, 인스트루먼트)
- 섹션 9개: Hero, Features, HowItWorks, Privacy, Pricing, FAQ, CTA, Header, Footer
- 재사용 컴포넌트 8개 (Badge, Container, InstrumentCard, GlowButton 등)
- i18n 10개 국어 (en/ko/ja/zh/es/fr/de/pt/ru/vi)
- GitHub Pages 자동 배포 워크플로우
This commit is contained in:
Yun Chan 2026-04-05 23:55:13 +09:00
parent eb83682269
commit 5892125740
45 changed files with 6225 additions and 0 deletions

30
site/src/App.tsx Normal file
View file

@ -0,0 +1,30 @@
import { I18nProvider } from './i18n'
import { Header } from './sections/Header'
import { Hero } from './sections/Hero'
import { Features } from './sections/Features'
import { HowItWorks } from './sections/HowItWorks'
import { Privacy } from './sections/Privacy'
import { Pricing } from './sections/Pricing'
import { FAQ } from './sections/FAQ'
import { CTA } from './sections/CTA'
import { Footer } from './sections/Footer'
export function App() {
return (
<I18nProvider>
<div className="min-h-screen bg-surface-950">
<Header />
<main>
<Hero />
<Features />
<HowItWorks />
<Privacy />
<Pricing />
<FAQ />
<CTA />
</main>
<Footer />
</div>
</I18nProvider>
)
}

View file

@ -0,0 +1,26 @@
import type { ReactNode } from 'react'
import { Led } from './Led'
interface BadgeProps {
children: ReactNode
led?: boolean
ledColor?: 'amber' | 'green' | 'red'
className?: string
}
export function Badge({ children, led = false, ledColor = 'amber', className = '' }: BadgeProps) {
return (
<span
className={`
inline-flex items-center gap-2 px-3 py-1
font-mono text-nano uppercase tracking-widest
text-neutral-400 bg-surface-700/50 border border-white/[0.06]
rounded-sm select-none
${className}
`}
>
{led && <Led color={ledColor} size="sm" />}
{children}
</span>
)
}

View file

@ -0,0 +1,14 @@
import type { ReactNode } from 'react'
interface ContainerProps {
children: ReactNode
className?: string
}
export function Container({ children, className = '' }: ContainerProps) {
return (
<div className={`mx-auto w-full max-w-7xl px-5 md:px-8 lg:px-12 ${className}`}>
{children}
</div>
)
}

View file

@ -0,0 +1,14 @@
import type { ReactNode } from 'react'
interface CrosshairProps {
className?: string
children: ReactNode
}
export function Crosshair({ className = '', children }: CrosshairProps) {
return (
<div className={`crosshair-box ${className}`}>
{children}
</div>
)
}

View file

@ -0,0 +1,22 @@
interface DataPointProps {
label: string
value: string
unit?: string
className?: string
}
export function DataPoint({ label, value, unit, className = '' }: DataPointProps) {
return (
<div className={`flex flex-col ${className}`}>
<span className="font-mono text-nano uppercase tracking-widest text-neutral-500 mb-1">
{label}
</span>
<span className="font-display text-2xl md:text-3xl font-bold text-neutral-100 tracking-tight">
{value}
{unit && (
<span className="text-sm font-mono text-neutral-500 ml-1">{unit}</span>
)}
</span>
</div>
)
}

View file

@ -0,0 +1,45 @@
import type { ReactNode } from 'react'
interface GlowButtonProps {
children: ReactNode
href?: string
variant?: 'primary' | 'secondary'
size?: 'md' | 'lg'
className?: string
}
export function GlowButton({
children,
href,
variant = 'primary',
size = 'md',
className = '',
}: GlowButtonProps) {
const base = 'glow-btn inline-flex items-center justify-center font-mono text-sm font-medium tracking-wide uppercase rounded-panel select-none'
const variants = {
primary: 'bg-brand-amber text-white hover:bg-brand-amber-light',
secondary: 'bg-surface-500 text-neutral-200 border border-white/[0.08] hover:border-brand-amber/30',
}
const sizes = {
md: 'px-6 py-3 text-xs',
lg: 'px-8 py-4 text-sm',
}
const cls = `${base} ${variants[variant]} ${sizes[size]} ${className}`
if (href) {
return (
<a href={href} className={cls}>
<span className="relative z-10">{children}</span>
</a>
)
}
return (
<button className={cls}>
<span className="relative z-10">{children}</span>
</button>
)
}

View file

@ -0,0 +1,26 @@
import type { ReactNode } from 'react'
interface InstrumentCardProps {
children: ReactNode
className?: string
hover?: boolean
}
export function InstrumentCard({ children, className = '', hover = true }: InstrumentCardProps) {
return (
<div
className={`
relative noise-texture
bg-surface-600 border border-white/[0.06]
rounded-card shadow-chassis
p-5 md:p-6
${hover ? 'transition-all duration-250 hover:border-brand-amber/20 hover:shadow-glow-sm' : ''}
${className}
`}
>
<div className="relative z-10">
{children}
</div>
</div>
)
}

View file

@ -0,0 +1,82 @@
import { useState, useRef, useEffect } from 'react'
import { useI18n, LOCALES } from '../i18n'
export function LanguageSwitcher() {
const { locale, setLocale } = useI18n()
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)
const current = LOCALES.find((l) => l.code === locale)
useEffect(() => {
function handleClick(e: MouseEvent) {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false)
}
}
document.addEventListener('mousedown', handleClick)
return () => document.removeEventListener('mousedown', handleClick)
}, [])
return (
<div ref={ref} className="relative">
<button
onClick={() => setOpen(!open)}
className="flex items-center gap-1.5 px-2.5 py-1.5 font-mono text-nano uppercase tracking-widest text-neutral-400 hover:text-white border border-white/[0.06] rounded-panel transition-colors"
aria-label="Change language"
>
<GlobeIcon />
{current?.label ?? 'EN'}
<ChevronIcon open={open} />
</button>
{open && (
<div className="absolute right-0 top-full mt-2 w-40 py-1 bg-surface-700 border border-white/[0.08] rounded-card shadow-lg z-50 max-h-80 overflow-y-auto">
{LOCALES.map((l) => (
<button
key={l.code}
onClick={() => {
setLocale(l.code)
setOpen(false)
}}
className={`w-full text-left px-3 py-2 font-mono text-xs flex items-center justify-between transition-colors ${
l.code === locale
? 'text-brand-amber bg-brand-amber/[0.08]'
: 'text-neutral-400 hover:text-white hover:bg-surface-600'
}`}
>
<span>{l.nativeName}</span>
<span className="text-nano text-neutral-600 uppercase">{l.label}</span>
</button>
))}
</div>
)}
</div>
)
}
function GlobeIcon() {
return (
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M2 12h20" />
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
</svg>
)
}
function ChevronIcon({ open }: { open: boolean }) {
return (
<svg
className={`w-3 h-3 transition-transform ${open ? 'rotate-180' : ''}`}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="6 9 12 15 18 9" />
</svg>
)
}

View file

@ -0,0 +1,37 @@
interface LedProps {
color?: 'amber' | 'green' | 'red'
pulse?: boolean
size?: 'sm' | 'md'
className?: string
}
const colorMap = {
amber: {
bg: 'bg-brand-amber',
shadow: 'shadow-[0_0_6px_rgba(242,91,41,0.8)]',
},
green: {
bg: 'bg-emerald-400',
shadow: 'shadow-[0_0_6px_rgba(52,211,153,0.8)]',
},
red: {
bg: 'bg-red-500',
shadow: 'shadow-[0_0_6px_rgba(239,68,68,0.8)]',
},
} as const
const sizeMap = {
sm: 'w-1.5 h-1.5',
md: 'w-2 h-2',
} as const
export function Led({ color = 'amber', pulse = false, size = 'sm', className = '' }: LedProps) {
const c = colorMap[color]
const s = sizeMap[size]
return (
<span
className={`inline-block rounded-full ${c.bg} ${c.shadow} ${s} ${pulse ? 'animate-glow-pulse' : ''} ${className}`}
aria-hidden="true"
/>
)
}

View file

@ -0,0 +1,27 @@
interface SectionHeaderProps {
index: string
title: string
subtitle?: string
className?: string
}
export function SectionHeader({ index, title, subtitle, className = '' }: SectionHeaderProps) {
return (
<div className={`mb-12 md:mb-16 ${className}`}>
<div className="flex items-center gap-4 mb-4">
<span className="font-mono text-nano uppercase tracking-widest text-brand-amber">
{index}
</span>
<div className="h-px flex-1 bg-white/[0.06]" />
</div>
<h2 className="font-display text-display font-bold text-neutral-50 tracking-tight">
{title}
</h2>
{subtitle && (
<p className="mt-3 max-w-xl text-base text-neutral-400 leading-relaxed">
{subtitle}
</p>
)}
</div>
)
}

View file

@ -0,0 +1,47 @@
import { useEffect, useRef } from 'react'
const BAR_COUNT = 9
const COS_WEIGHTS = Array.from({ length: BAR_COUNT }, (_, i) =>
Math.cos((i - 4) * (Math.PI / 9)),
)
interface WaveBarsProps {
className?: string
}
export function WaveBars({ className = '' }: WaveBarsProps) {
const barsRef = useRef<(HTMLDivElement | null)[]>([])
useEffect(() => {
let frame: number
let t = 0
const animate = () => {
t += 0.05
barsRef.current.forEach((bar, i) => {
if (!bar) return
const base = COS_WEIGHTS[i]
const wave = Math.sin(t + i * 0.4) * 0.5 + 0.5
const h = 4 + base * wave * 28
bar.style.height = `${h}px`
})
frame = requestAnimationFrame(animate)
}
frame = requestAnimationFrame(animate)
return () => cancelAnimationFrame(frame)
}, [])
return (
<div className={`flex items-center gap-[3px] h-10 ${className}`} aria-hidden="true">
{Array.from({ length: BAR_COUNT }, (_, i) => (
<div
key={i}
ref={(el) => { barsRef.current[i] = el }}
className="w-[3px] rounded-full bg-brand-amber/60"
style={{ height: 4, transition: 'height 60ms ease-out' }}
/>
))}
</div>
)
}

View file

@ -0,0 +1,31 @@
import { useEffect, useRef } from 'react'
/**
* Intersection Observer hook for reveal-on-scroll animations.
* Returns a ref to attach to the element that should animate in.
*/
export function useReveal<T extends HTMLElement = HTMLDivElement>(
threshold = 0.15,
) {
const ref = useRef<T>(null)
useEffect(() => {
const el = ref.current
if (!el) return
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
el.classList.add('visible')
observer.unobserve(el)
}
},
{ threshold },
)
observer.observe(el)
return () => observer.disconnect()
}, [threshold])
return ref
}

227
site/src/i18n/index.ts Normal file
View file

@ -0,0 +1,227 @@
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'
import { createElement } from 'react'
import { en } from './locales/en'
import { ko } from './locales/ko'
import { ja } from './locales/ja'
import { zh } from './locales/zh'
import { es } from './locales/es'
import { fr } from './locales/fr'
import { de } from './locales/de'
import { pt } from './locales/pt'
import { ru } from './locales/ru'
import { vi } from './locales/vi'
// ── Types ──────────────────────────────────────────────
export type Locale = 'en' | 'ko' | 'ja' | 'zh' | 'es' | 'fr' | 'de' | 'pt' | 'ru' | 'vi'
export interface FeatureItem {
title: string
description: string
}
export interface PipelineStep {
label: string
title: string
description: string
detail: string
}
export interface PrivacyMetricItem {
label: string
value: string
}
export interface FaqItem {
q: string
a: string
}
export interface PricingFeatureRow {
feature: string
free: string | boolean
pro: string | boolean
proPlus: string | boolean
}
export interface Translations {
nav: {
features: string
pipeline: string
privacy: string
pricing: string
faq: string
download: string
}
hero: {
badge: string
title1: string
title2: string
title3: string
subtitle: string
downloadBtn: string
viewFeatures: string
dataProcessing: string
dataCloudTraffic: string
dataLatency: string
dataPrivacy: string
systemStatus: string
protocol: string
}
features: {
index: string
title: string
subtitle: string
items: [FeatureItem, FeatureItem, FeatureItem, FeatureItem, FeatureItem, FeatureItem, FeatureItem, FeatureItem, FeatureItem]
}
pipeline: {
index: string
title: string
subtitle: string
steps: [PipelineStep, PipelineStep, PipelineStep, PipelineStep]
panelTitle: string
panelActive: string
panelLatency: string
sttReady: string
llmConnected: string
transcription: string
aiPolish: string
sampleInput: string
sampleOutput: string
}
privacy: {
index: string
title: string
subtitle: string
monitorTitle: string
allClear: string
metrics: [PrivacyMetricItem, PrivacyMetricItem, PrivacyMetricItem, PrivacyMetricItem, PrivacyMetricItem, PrivacyMetricItem]
guarantees: [string, string, string, string, string, string]
}
pricing: {
index: string
title: string
subtitle: string
featureLabel: string
free: string
pro: string
proPlus: string
forever: string
oneTime: string
popular: string
downloadFree: string
getPro: string
getProPlus: string
taxNote: string
rows: [PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow, PricingFeatureRow]
}
faq: {
index: string
title: string
items: [FaqItem, FaqItem, FaqItem, FaqItem, FaqItem, FaqItem]
}
cta: {
title1: string
title2: string
subtitle1: string
subtitle2: string
downloadBtn: string
systemReq: string
}
footer: {
description: string
copyright: string
builtWith: string
}
}
// ── Locale metadata ────────────────────────────────────
export interface LocaleMeta {
code: Locale
label: string
nativeName: string
}
export const LOCALES: LocaleMeta[] = [
{ code: 'en', label: 'EN', nativeName: 'English' },
{ code: 'ko', label: 'KO', nativeName: '한국어' },
{ code: 'ja', label: 'JA', nativeName: '日本語' },
{ code: 'zh', label: 'ZH', nativeName: '中文' },
{ code: 'es', label: 'ES', nativeName: 'Espanol' },
{ code: 'fr', label: 'FR', nativeName: 'Francais' },
{ code: 'de', label: 'DE', nativeName: 'Deutsch' },
{ code: 'pt', label: 'PT', nativeName: 'Portugues' },
{ code: 'ru', label: 'RU', nativeName: 'Русский' },
{ code: 'vi', label: 'VI', nativeName: 'Tieng Viet' },
]
// ── Translations map ───────────────────────────────────
const translations: Record<Locale, Translations> = {
en, ko, ja, zh, es, fr, de, pt, ru, vi,
}
// ── Storage ────────────────────────────────────────────
const STORAGE_KEY = 'd3ro-locale'
function detectLocale(): Locale {
// 1. Check localStorage
try {
const stored = localStorage.getItem(STORAGE_KEY)
if (stored && stored in translations) return stored as Locale
} catch { /* noop */ }
// 2. Check browser language
const browserLang = navigator.language.toLowerCase()
const exact = LOCALES.find((l) => browserLang === l.code || browserLang.startsWith(l.code + '-'))
if (exact) return exact.code
// 3. Fallback
return 'en'
}
function persistLocale(locale: Locale): void {
try {
localStorage.setItem(STORAGE_KEY, locale)
} catch { /* noop */ }
}
// ── Context ────────────────────────────────────────────
interface I18nContextValue {
locale: Locale
t: Translations
setLocale: (locale: Locale) => void
}
const I18nContext = createContext<I18nContextValue | null>(null)
export function useI18n(): I18nContextValue {
const ctx = useContext(I18nContext)
if (!ctx) throw new Error('useI18n must be used within I18nProvider')
return ctx
}
// ── Provider ───────────────────────────────────────────
interface I18nProviderProps {
children: ReactNode
}
export function I18nProvider({ children }: I18nProviderProps) {
const [locale, setLocaleState] = useState<Locale>(detectLocale)
const setLocale = useCallback((newLocale: Locale) => {
setLocaleState(newLocale)
persistLocale(newLocale)
document.documentElement.lang = newLocale
}, [])
useEffect(() => {
document.documentElement.lang = locale
}, [locale])
const value: I18nContextValue = {
locale,
t: translations[locale],
setLocale,
}
return createElement(I18nContext.Provider, { value }, children)
}

144
site/src/i18n/locales/de.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const de: Translations = {
nav: {
features: 'FUNKTIONEN',
pipeline: 'PIPELINE',
privacy: 'DATENSCHUTZ',
pricing: 'PREISE',
faq: 'FAQ',
download: 'Download',
},
hero: {
badge: '100% LOKAL \u00b7 NULL CLOUD',
title1: 'LOKALER KI',
title2: 'SPRACH',
title3: 'ASSISTENT.',
subtitle: 'Whisper + Ollama betriebene Sprache-zu-Text-Pipeline lauft komplett auf Ihrem Rechner. Diktat, KI-Korrektur, Echtzeit-Untertitel, Sprachgesprache \u2014 kein Internet erforderlich.',
downloadBtn: 'Fur Windows herunterladen',
viewFeatures: 'Funktionen ansehen',
dataProcessing: 'Verarbeitung',
dataCloudTraffic: 'Cloud-Verkehr',
dataLatency: 'STT-Latenz',
dataPrivacy: 'Datenschutz-Score',
systemStatus: 'SYSTEMSTATUS: BETRIEBSBEREIT',
protocol: 'PROTOKOLL: 2025.04',
},
features: {
index: '01 / FUNKTIONEN',
title: 'Vollstandige Sprachintelligenz.',
subtitle: 'Vom Diktat bis zum KI-Gesprach. Alles lauft offline auf Ihrer Hardware.',
items: [
{ title: 'Sprachdiktat', description: 'Hotkey halten, sprechen, loslassen. Whisper transkribiert und fugt Text sofort in Ihre aktive App ein.' },
{ title: 'KI-Textkorrektur', description: 'Ollama LLM verfeinert Ihren transkribierten Text zu sauberer, grammatisch korrekter Prosa. Formell oder leger.' },
{ title: 'Sofortige Ubersetzung', description: 'Sprechen Sie in einer Sprache, erhalten Sie Text in einer anderen. Automatische Quellerkennung, Ubersetzung auf dem Gerat.' },
{ title: 'Live-Untertitel', description: 'Echtzeit-Untertitel-Overlay auf Ihrem Bildschirm. Meetings, Vorlesungen, Videos. Automatischer Export von Besprechungsnotizen.' },
{ title: 'Sprachgesprach', description: 'Lokaler ChatGPT-Sprachmodus. Vollstandige STT-LLM-TTS-Schleife fur naturliche KI-Gesprache, komplett offline.' },
{ title: 'Datei-Transkription', description: 'Audio- oder Videodateien per Drag & Drop. Whisper transkribiert den gesamten Inhalt mit Zeitstempeln.' },
{ title: 'Multi-LLM-Kette', description: 'Verketten Sie mehrere KI-Befehle: Transkribieren, Ubersetzen, dann Zusammenfassen mit einem Tastendruck.' },
{ title: 'Bildschirmkontext', description: 'Erfasst automatisch aktive App und markierten Text. Sagen Sie "erklare diesen Code" und die KI sieht, was Sie sehen.' },
{ title: 'Sprachnotiz', description: 'Automatisch organisierte Sprachnotizen mit #Tags. Als Markdown exportieren. Suchen, filtern, kategorisieren.' },
],
},
pipeline: {
index: '02 / PIPELINE',
title: 'Vier Schritte. Zwei Sekunden.',
subtitle: 'Ein Tastendruck und Ihre Sprache wird zu poliertem Text.',
steps: [
{ label: 'EINGABE', title: 'Hotkey drucken', description: 'Right Alt (oder Ihre benutzerdefinierte Taste) gedruckt halten zum Aufnehmen. Doppeltippen fur KI-Modus. Umschalten fur Freisprechen.', detail: 'Halten / Umschalten / Doppeldruck' },
{ label: 'TRANSKRIBIEREN', title: 'Whisper STT', description: 'Lokale faster-whisper Engine konvertiert 16kHz PCM-Audio in Echtzeit zu Text. GPU-Beschleunigung unterstutzt.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'VERARBEITEN', title: 'Ollama LLM', description: 'Lokales LLM korrigiert Grammatik, passt den Ton an, ubersetzt oder fasst zusammen. Benutzerdefinierte Anweisungen unterstutzt.', detail: 'qwen3 / llama3 / gemma3 / benutzerdefiniert' },
{ label: 'AUSGABE', title: 'Auto-Einfugen', description: 'Korrigierter Text wird an der Cursorposition in jeder App eingefugt. Notepad, VS Code, Chrome, Slack, uberall.', detail: 'Zwischenablage + Ctrl+V / 100ms Latenz' },
],
panelTitle: 'D3RO Voice Pipeline',
panelActive: 'Aktiv',
panelLatency: 'LATENZ: 1.2s',
sttReady: 'STT Bereit',
llmConnected: 'LLM Verbunden',
transcription: 'Transkription',
aiPolish: 'KI-Korrektur',
sampleInput: 'Bitte fassen Sie die heutigen Besprechungsnotizen zusammen...',
sampleOutput: 'Bitte fassen Sie die heutigen Besprechungsnotizen zusammen.',
},
privacy: {
index: '03 / DATENSCHUTZ',
title: 'Ihre Stimme verlasst nie den Rechner.',
subtitle: 'Jedes Byte Audio, jede Transkription, jede KI-Interaktion bleibt auf Ihrem Gerat.',
monitorTitle: 'Datenschutz-Monitor',
allClear: 'ALLES OK',
metrics: [
{ label: 'CLOUD-VERKEHR', value: '0 BYTES' },
{ label: 'DATENVERSCHLUSSELUNG', value: 'LOKALES SQLite' },
{ label: 'TELEMETRIE', value: 'DEAKTIVIERT' },
{ label: 'NETZWERK ERFORDERLICH', value: 'NEIN' },
{ label: 'AUDIOSPEICHER', value: 'NUR LOKAL' },
{ label: 'OPEN SOURCE', value: 'JA' },
],
guarantees: [
'Kein Internet nach dem initialen Modell-Download erforderlich',
'Sprachaufnahmen nur in lokalem SQLite gespeichert',
'Alle Daten jederzeit mit einem Klick loschen',
'Open Source - jede Zeile Code einsehbar',
'Keine Konten, keine Anmeldungen, kein Tracking',
'Whisper und Ollama laufen beide auf Ihrer Hardware',
],
},
pricing: {
index: '04 / PREISE',
title: 'Kein Abo. Niemals.',
subtitle: 'Keine Cloud bedeutet keine monatlichen Kosten. Einmalkauf, lebenslange Nutzung.',
featureLabel: 'Funktion',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'fur immer gratis',
oneTime: 'einmalig',
popular: 'Beliebt',
downloadFree: 'Gratis herunterladen',
getPro: 'Pro holen',
getProPlus: 'Pro+ holen',
taxNote: 'Alle Preise zzgl. MwSt. Sichere Zahlung uber LemonSqueezy.',
rows: [
{ feature: 'Sprachdiktat', free: '15/Tag', pro: true, proPlus: true },
{ feature: 'KI-Textkorrektur', free: '3/Tag', pro: true, proPlus: true },
{ feature: 'Verlaufsaufbewahrung', free: '3 Tage', pro: true, proPlus: true },
{ feature: 'Benutzerdefinierte Anweisungen', free: 'Voreinstellungen', pro: true, proPlus: true },
{ feature: 'Live-Untertitel', free: false, pro: true, proPlus: true },
{ feature: 'Bildschirmkontext', free: false, pro: true, proPlus: true },
{ feature: 'Sprachnotiz + Tags', free: false, pro: true, proPlus: true },
{ feature: 'Multi-LLM-Kette', free: false, pro: true, proPlus: true },
{ feature: 'Sprachbefehle', free: false, pro: true, proPlus: true },
{ feature: 'Verlauf exportieren', free: false, pro: true, proPlus: true },
{ feature: 'Datei-Transkription', free: false, pro: false, proPlus: true },
{ feature: 'Sprachgesprach', free: false, pro: false, proPlus: true },
{ feature: 'Besprechungszusammenfassung', free: false, pro: false, proPlus: true },
{ feature: 'Lokales RAG', free: false, pro: false, proPlus: true },
{ feature: 'OS-Automatisierung', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Haufige Fragen.',
items: [
{ q: 'Muss ich Ollama und Whisper separat installieren?', a: 'Whisper (faster-whisper) ist in der App enthalten - keine separate Installation notig. Ollama wird nur fur KI-Korrektur/Ubersetzung benotigt und kann einfach uber die App installiert werden. Basisdiktat funktioniert ohne Ollama.' },
{ q: 'Welche GPU brauche ich?', a: 'Keine GPU erforderlich - funktioniert nur mit CPU. Eine NVIDIA GPU (CUDA) beschleunigt die Transkription 5-10x. Mit dem base-Modell ist Echtzeit-Transkription auf CPU moglich.' },
{ q: 'Funktioniert es komplett offline?', a: 'Ja. Sobald Sie die Whisper- und Ollama-Modelle heruntergeladen haben, funktioniert alles ohne Internet. Die Lizenzverifizierung ist nur bei der Erstaktivierung online, danach 30 Tage Offline-Karenzzeit.' },
{ q: 'Wie genau ist die Spracherkennung?', a: 'Whisper large-v3 bietet hervorragende Genauigkeit fur uber 99 Sprachen. Die benutzerdefinierte Worterbuchfunktion verbessert die Genauigkeit fur Fachterminologie zusatzlich.' },
{ q: 'Ist das ein Abonnement?', a: 'Nein. Pro und Pro+ sind Einmalkaufe. Einmal zahlen, fur immer nutzen. Wichtige Updates inklusive. Ohne Cloud-Serverkosten brauchen wir kein Abomodell.' },
{ q: 'Was ist mit macOS und Linux?', a: 'Derzeit nur Windows. Auf Electron aufgebaut, ist macOS/Linux-Unterstutzung technisch machbar und je nach Nachfrage geplant.' },
],
},
cta: {
title1: 'Sprechen.',
title2: 'KI schreibt.',
subtitle1: 'Keine Cloud. Kein Abo. Keine Datenschutzbedenken.',
subtitle2: 'Jetzt starten.',
downloadBtn: 'Fur Windows herunterladen',
systemReq: 'Windows 10/11 \u00b7 64-Bit \u00b7 ~200MB \u00b7 In Sekunden bereit',
},
footer: {
description: 'Vollstandig lokaler KI-Sprachassistent. Angetrieben von Whisper und Ollama. Ihre Stimme, Ihr Rechner, Ihre Daten.',
copyright: '\u00a9 {year} D3RO Voice. Alle Rechte vorbehalten.',
builtWith: 'Gebaut mit Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/en.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const en: Translations = {
nav: {
features: 'FEATURES',
pipeline: 'PIPELINE',
privacy: 'PRIVACY',
pricing: 'PRICING',
faq: 'FAQ',
download: 'Download',
},
hero: {
badge: '100% LOCAL \u00b7 ZERO CLOUD',
title1: 'LOCAL AI',
title2: 'VOICE',
title3: 'ASSISTANT.',
subtitle: 'Whisper + Ollama powered voice-to-text pipeline running entirely on your machine. Dictation, AI polish, real-time captions, voice conversations \u2014 no internet required.',
downloadBtn: 'Download for Windows',
viewFeatures: 'View Features',
dataProcessing: 'Processing',
dataCloudTraffic: 'Cloud Traffic',
dataLatency: 'STT Latency',
dataPrivacy: 'Privacy Score',
systemStatus: 'SYSTEM STATUS: OPERATIONAL',
protocol: 'PROTOCOL: 2025.04',
},
features: {
index: '01 / FEATURES',
title: 'Full Voice Intelligence.',
subtitle: 'From dictation to AI conversation. Everything runs on your hardware, offline.',
items: [
{ title: 'Voice Dictation', description: 'Hold a hotkey, speak, release. Whisper transcribes and inserts text into your active app instantly.' },
{ title: 'AI Text Polish', description: 'Ollama LLM refines your transcribed text into clean, grammatically correct prose. Formal or casual.' },
{ title: 'Instant Translation', description: 'Speak in one language, get text in another. Auto-detect source, translate on-device.' },
{ title: 'Live Captions', description: 'Real-time subtitle overlay on your screen. Meetings, lectures, videos. Auto meeting notes export.' },
{ title: 'Voice Conversation', description: 'Local ChatGPT voice mode. Full STT-LLM-TTS loop for natural AI conversations, completely offline.' },
{ title: 'File Transcription', description: 'Drag and drop audio or video files. Whisper transcribes the entire content with timestamps.' },
{ title: 'Multi-LLM Chain', description: 'Pipeline multiple AI commands: transcribe, translate, then summarize with a single hotkey press.' },
{ title: 'Screen Context', description: 'Auto-captures active app and selected text. Ask "explain this code" and the AI sees what you see.' },
{ title: 'Voice Memo', description: 'Auto-organized voice notes with #tags. Export as markdown. Search, filter, categorize.' },
],
},
pipeline: {
index: '02 / PIPELINE',
title: 'Four Steps. Two Seconds.',
subtitle: 'One hotkey press and your speech becomes polished text.',
steps: [
{ label: 'INPUT', title: 'Press Hotkey', description: 'Hold Right Alt (or your custom key) to start recording. Double-tap for AI mode. Toggle for hands-free.', detail: 'Hold-to-talk / Toggle / Double-press' },
{ label: 'TRANSCRIBE', title: 'Whisper STT', description: 'Local faster-whisper engine converts 16kHz PCM audio to text in real-time. GPU acceleration supported.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'PROCESS', title: 'Ollama LLM', description: 'Local LLM polishes grammar, adjusts tone, translates, or summarizes. Custom instructions supported.', detail: 'qwen3 / llama3 / gemma3 / custom' },
{ label: 'OUTPUT', title: 'Auto Insert', description: 'Polished text is pasted at your cursor position in any app. Notepad, VS Code, Chrome, Slack, anywhere.', detail: 'Clipboard + Ctrl+V / 100ms latency' },
],
panelTitle: 'D3RO Voice Pipeline',
panelActive: 'Active',
panelLatency: 'LATENCY: 1.2s',
sttReady: 'STT Ready',
llmConnected: 'LLM Connected',
transcription: 'Transcription',
aiPolish: 'AI Polish',
sampleInput: 'Please summarize the meeting notes from today...',
sampleOutput: 'Please summarize today\u2019s meeting notes.',
},
privacy: {
index: '03 / PRIVACY',
title: 'Your Voice Never Leaves.',
subtitle: 'Every byte of audio, every transcription, every AI interaction stays on your machine.',
monitorTitle: 'Privacy Monitor',
allClear: 'ALL CLEAR',
metrics: [
{ label: 'CLOUD TRAFFIC', value: '0 BYTES' },
{ label: 'DATA ENCRYPTION', value: 'LOCAL SQLite' },
{ label: 'TELEMETRY', value: 'DISABLED' },
{ label: 'NETWORK REQUIRED', value: 'NO' },
{ label: 'AUDIO STORAGE', value: 'LOCAL ONLY' },
{ label: 'OPEN SOURCE', value: 'YES' },
],
guarantees: [
'Zero internet required after initial model download',
'Voice recordings stored in local SQLite only',
'Delete all data anytime with one click',
'Open source - inspect every line of code',
'No accounts, no sign-ups, no tracking',
'Whisper and Ollama both run on your hardware',
],
},
pricing: {
index: '04 / PRICING',
title: 'No Subscription. Ever.',
subtitle: 'No cloud means no monthly bills. One-time purchase, lifetime use.',
featureLabel: 'Feature',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'forever',
oneTime: 'one-time',
popular: 'Popular',
downloadFree: 'Download Free',
getPro: 'Get Pro',
getProPlus: 'Get Pro+',
taxNote: 'All prices exclude tax. Secure payment via LemonSqueezy.',
rows: [
{ feature: 'Voice Dictation', free: '15/day', pro: true, proPlus: true },
{ feature: 'AI Text Polish', free: '3/day', pro: true, proPlus: true },
{ feature: 'History Retention', free: '3 days', pro: true, proPlus: true },
{ feature: 'Custom Instructions', free: 'Presets', pro: true, proPlus: true },
{ feature: 'Live Captions', free: false, pro: true, proPlus: true },
{ feature: 'Screen Context', free: false, pro: true, proPlus: true },
{ feature: 'Voice Memo + Tags', free: false, pro: true, proPlus: true },
{ feature: 'Multi-LLM Chain', free: false, pro: true, proPlus: true },
{ feature: 'Voice Commands', free: false, pro: true, proPlus: true },
{ feature: 'History Export', free: false, pro: true, proPlus: true },
{ feature: 'File Transcription', free: false, pro: false, proPlus: true },
{ feature: 'Voice Conversation', free: false, pro: false, proPlus: true },
{ feature: 'Meeting Summary', free: false, pro: false, proPlus: true },
{ feature: 'Local RAG', free: false, pro: false, proPlus: true },
{ feature: 'OS Automation', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Common Questions.',
items: [
{ q: 'Do I need to install Ollama and Whisper separately?', a: 'Whisper (faster-whisper) is bundled with the app - no separate install needed. Ollama is required only for AI polish/translation features and can be easily installed via in-app guidance. Basic dictation works without Ollama.' },
{ q: 'What GPU do I need?', a: 'No GPU required - it works on CPU alone. An NVIDIA GPU (CUDA) accelerates transcription 5-10x. With the base model, CPU real-time transcription is possible.' },
{ q: 'Does it work completely offline?', a: 'Yes. Once you download the Whisper and Ollama models, everything works without internet. License verification is online only for initial activation, then 30-day offline grace period.' },
{ q: 'How accurate is the speech recognition?', a: 'Whisper large-v3 provides excellent accuracy for 99+ languages. The custom dictionary feature further improves accuracy for domain-specific terminology.' },
{ q: 'Is this a subscription?', a: 'No. Pro and Pro+ are one-time purchases. Pay once, use forever. Major updates included. Since there are no cloud server costs, we do not need a subscription model.' },
{ q: 'What about macOS and Linux?', a: 'Currently Windows only. Built on Electron so macOS/Linux support is technically feasible and planned based on demand.' },
],
},
cta: {
title1: 'Speak.',
title2: 'AI Writes.',
subtitle1: 'No cloud. No subscription. No privacy concerns.',
subtitle2: 'Start now.',
downloadBtn: 'Download for Windows',
systemReq: 'Windows 10/11 \u00b7 64-bit \u00b7 ~200MB \u00b7 Ready in seconds',
},
footer: {
description: 'Fully local AI voice assistant. Powered by Whisper and Ollama. Your voice, your machine, your data.',
copyright: '\u00a9 {year} D3RO Voice. All rights reserved.',
builtWith: 'Built with Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/es.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const es: Translations = {
nav: {
features: 'FUNCIONES',
pipeline: 'PROCESO',
privacy: 'PRIVACIDAD',
pricing: 'PRECIOS',
faq: 'FAQ',
download: 'Descargar',
},
hero: {
badge: '100% LOCAL \u00b7 CERO NUBE',
title1: 'IA LOCAL',
title2: 'ASISTENTE',
title3: 'DE VOZ.',
subtitle: 'Pipeline de voz a texto con Whisper + Ollama ejecutandose completamente en tu equipo. Dictado, pulido con IA, subtitulos en tiempo real, conversaciones por voz \u2014 sin internet.',
downloadBtn: 'Descargar para Windows',
viewFeatures: 'Ver funciones',
dataProcessing: 'Procesamiento',
dataCloudTraffic: 'Trafico en la nube',
dataLatency: 'Latencia STT',
dataPrivacy: 'Puntuacion de privacidad',
systemStatus: 'ESTADO DEL SISTEMA: OPERATIVO',
protocol: 'PROTOCOLO: 2025.04',
},
features: {
index: '01 / FUNCIONES',
title: 'Inteligencia de voz completa.',
subtitle: 'Desde dictado hasta conversacion con IA. Todo se ejecuta en tu hardware, sin conexion.',
items: [
{ title: 'Dictado por voz', description: 'Manten una tecla, habla, suelta. Whisper transcribe e inserta texto en tu app activa al instante.' },
{ title: 'Pulido con IA', description: 'Ollama LLM refina tu texto transcrito en prosa limpia y gramaticalmente correcta. Formal o casual.' },
{ title: 'Traduccion instantanea', description: 'Habla en un idioma, obtene texto en otro. Deteccion automatica del idioma, traduccion en el dispositivo.' },
{ title: 'Subtitulos en vivo', description: 'Subtitulos en tiempo real superpuestos en tu pantalla. Reuniones, clases, videos. Exportacion automatica de notas.' },
{ title: 'Conversacion por voz', description: 'Modo de voz ChatGPT local. Bucle completo STT-LLM-TTS para conversaciones naturales con IA, totalmente offline.' },
{ title: 'Transcripcion de archivos', description: 'Arrastra y suelta archivos de audio o video. Whisper transcribe todo el contenido con marcas de tiempo.' },
{ title: 'Cadena multi-LLM', description: 'Encadena multiples comandos de IA: transcribir, traducir, luego resumir con una sola pulsacion.' },
{ title: 'Contexto de pantalla', description: 'Captura automatica de la app activa y texto seleccionado. Di "explica este codigo" y la IA ve lo que tu ves.' },
{ title: 'Notas de voz', description: 'Notas de voz auto-organizadas con #etiquetas. Exporta como markdown. Busca, filtra, categoriza.' },
],
},
pipeline: {
index: '02 / PROCESO',
title: 'Cuatro pasos. Dos segundos.',
subtitle: 'Una pulsacion y tu voz se convierte en texto pulido.',
steps: [
{ label: 'ENTRADA', title: 'Pulsa la tecla', description: 'Manten Right Alt (o tu tecla personalizada) para grabar. Doble toque para modo IA. Alternar para manos libres.', detail: 'Mantener / Alternar / Doble pulsacion' },
{ label: 'TRANSCRIBIR', title: 'Whisper STT', description: 'El motor local faster-whisper convierte audio PCM 16kHz a texto en tiempo real. Compatible con aceleracion GPU.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'PROCESAR', title: 'Ollama LLM', description: 'El LLM local pule la gramatica, ajusta el tono, traduce o resume. Instrucciones personalizadas soportadas.', detail: 'qwen3 / llama3 / gemma3 / personalizado' },
{ label: 'SALIDA', title: 'Insercion automatica', description: 'El texto pulido se pega en la posicion del cursor en cualquier app. Bloc de notas, VS Code, Chrome, Slack, donde sea.', detail: 'Portapapeles + Ctrl+V / 100ms latencia' },
],
panelTitle: 'D3RO Voice Pipeline',
panelActive: 'Activo',
panelLatency: 'LATENCIA: 1.2s',
sttReady: 'STT Listo',
llmConnected: 'LLM Conectado',
transcription: 'Transcripcion',
aiPolish: 'Pulido IA',
sampleInput: 'Por favor resume las notas de la reunion de hoy...',
sampleOutput: 'Por favor, resume las notas de la reunion de hoy.',
},
privacy: {
index: '03 / PRIVACIDAD',
title: 'Tu voz nunca sale.',
subtitle: 'Cada byte de audio, cada transcripcion, cada interaccion con IA permanece en tu equipo.',
monitorTitle: 'Monitor de privacidad',
allClear: 'TODO OK',
metrics: [
{ label: 'TRAFICO EN NUBE', value: '0 BYTES' },
{ label: 'CIFRADO DE DATOS', value: 'SQLite LOCAL' },
{ label: 'TELEMETRIA', value: 'DESACTIVADA' },
{ label: 'RED REQUERIDA', value: 'NO' },
{ label: 'ALMACENAMIENTO DE AUDIO', value: 'SOLO LOCAL' },
{ label: 'CODIGO ABIERTO', value: 'SI' },
],
guarantees: [
'Sin internet despues de la descarga inicial del modelo',
'Grabaciones de voz almacenadas solo en SQLite local',
'Elimina todos los datos en cualquier momento con un clic',
'Codigo abierto - inspecciona cada linea de codigo',
'Sin cuentas, sin registros, sin rastreo',
'Whisper y Ollama se ejecutan en tu hardware',
],
},
pricing: {
index: '04 / PRECIOS',
title: 'Sin suscripcion. Nunca.',
subtitle: 'Sin nube significa sin facturas mensuales. Compra unica, uso de por vida.',
featureLabel: 'Funcion',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'gratis siempre',
oneTime: 'pago unico',
popular: 'Popular',
downloadFree: 'Descargar gratis',
getPro: 'Obtener Pro',
getProPlus: 'Obtener Pro+',
taxNote: 'Todos los precios sin impuestos. Pago seguro via LemonSqueezy.',
rows: [
{ feature: 'Dictado por voz', free: '15/dia', pro: true, proPlus: true },
{ feature: 'Pulido con IA', free: '3/dia', pro: true, proPlus: true },
{ feature: 'Retencion de historial', free: '3 dias', pro: true, proPlus: true },
{ feature: 'Instrucciones personalizadas', free: 'Presets', pro: true, proPlus: true },
{ feature: 'Subtitulos en vivo', free: false, pro: true, proPlus: true },
{ feature: 'Contexto de pantalla', free: false, pro: true, proPlus: true },
{ feature: 'Notas de voz + etiquetas', free: false, pro: true, proPlus: true },
{ feature: 'Cadena multi-LLM', free: false, pro: true, proPlus: true },
{ feature: 'Comandos de voz', free: false, pro: true, proPlus: true },
{ feature: 'Exportar historial', free: false, pro: true, proPlus: true },
{ feature: 'Transcripcion de archivos', free: false, pro: false, proPlus: true },
{ feature: 'Conversacion por voz', free: false, pro: false, proPlus: true },
{ feature: 'Resumen de reuniones', free: false, pro: false, proPlus: true },
{ feature: 'RAG local', free: false, pro: false, proPlus: true },
{ feature: 'Automatizacion del SO', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Preguntas frecuentes.',
items: [
{ q: 'Necesito instalar Ollama y Whisper por separado?', a: 'Whisper (faster-whisper) viene incluido con la app, sin instalacion adicional. Ollama solo se requiere para funciones de pulido/traduccion con IA y se instala facilmente desde la app. El dictado basico funciona sin Ollama.' },
{ q: 'Que GPU necesito?', a: 'No se requiere GPU, funciona solo con CPU. Una GPU NVIDIA (CUDA) acelera la transcripcion 5-10x. Con el modelo base, la transcripcion en tiempo real por CPU es posible.' },
{ q: 'Funciona completamente offline?', a: 'Si. Una vez descargados los modelos de Whisper y Ollama, todo funciona sin internet. La verificacion de licencia es online solo para la activacion inicial, luego 30 dias de gracia offline.' },
{ q: 'Que tan preciso es el reconocimiento de voz?', a: 'Whisper large-v3 ofrece excelente precision para mas de 99 idiomas. La funcion de diccionario personalizado mejora aun mas la precision para terminologia especializada.' },
{ q: 'Es una suscripcion?', a: 'No. Pro y Pro+ son compras unicas. Paga una vez, usa para siempre. Actualizaciones principales incluidas. Sin costos de servidor en la nube, no necesitamos modelo de suscripcion.' },
{ q: 'Y macOS y Linux?', a: 'Actualmente solo Windows. Construido con Electron, el soporte para macOS/Linux es tecnicamente factible y esta planeado segun la demanda.' },
],
},
cta: {
title1: 'Habla.',
title2: 'La IA escribe.',
subtitle1: 'Sin nube. Sin suscripcion. Sin preocupaciones de privacidad.',
subtitle2: 'Empieza ahora.',
downloadBtn: 'Descargar para Windows',
systemReq: 'Windows 10/11 \u00b7 64-bit \u00b7 ~200MB \u00b7 Listo en segundos',
},
footer: {
description: 'Asistente de voz IA completamente local. Potenciado por Whisper y Ollama. Tu voz, tu equipo, tus datos.',
copyright: '\u00a9 {year} D3RO Voice. Todos los derechos reservados.',
builtWith: 'Construido con Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/fr.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const fr: Translations = {
nav: {
features: 'FONCTIONS',
pipeline: 'PIPELINE',
privacy: 'VIE PRIVEE',
pricing: 'TARIFS',
faq: 'FAQ',
download: 'Telecharger',
},
hero: {
badge: '100% LOCAL \u00b7 ZERO CLOUD',
title1: 'IA LOCALE',
title2: 'ASSISTANT',
title3: 'VOCAL.',
subtitle: 'Pipeline voix-vers-texte avec Whisper + Ollama fonctionnant entierement sur votre machine. Dictee, correction IA, sous-titres en direct, conversations vocales \u2014 aucun internet requis.',
downloadBtn: 'Telecharger pour Windows',
viewFeatures: 'Voir les fonctions',
dataProcessing: 'Traitement',
dataCloudTraffic: 'Trafic cloud',
dataLatency: 'Latence STT',
dataPrivacy: 'Score vie privee',
systemStatus: 'ETAT SYSTEME : OPERATIONNEL',
protocol: 'PROTOCOLE : 2025.04',
},
features: {
index: '01 / FONCTIONS',
title: 'Intelligence vocale complete.',
subtitle: 'De la dictee a la conversation IA. Tout fonctionne sur votre materiel, hors ligne.',
items: [
{ title: 'Dictee vocale', description: 'Maintenez une touche, parlez, relachez. Whisper transcrit et insere le texte dans votre application active instantanement.' },
{ title: 'Correction IA', description: 'Ollama LLM affine votre texte transcrit en prose propre et grammaticalement correcte. Formel ou decontracte.' },
{ title: 'Traduction instantanee', description: 'Parlez dans une langue, obtenez le texte dans une autre. Detection automatique de la source, traduction sur l\'appareil.' },
{ title: 'Sous-titres en direct', description: 'Sous-titres en temps reel superposes a votre ecran. Reunions, cours, videos. Export automatique des notes.' },
{ title: 'Conversation vocale', description: 'Mode vocal ChatGPT local. Boucle complete STT-LLM-TTS pour des conversations IA naturelles, entierement hors ligne.' },
{ title: 'Transcription de fichiers', description: 'Glissez-deposez des fichiers audio ou video. Whisper transcrit l\'integralite du contenu avec horodatage.' },
{ title: 'Chaine multi-LLM', description: 'Enchainez plusieurs commandes IA : transcrire, traduire, puis resumer en une seule pression.' },
{ title: 'Contexte d\'ecran', description: 'Capture automatique de l\'app active et du texte selectionne. Dites "explique ce code" et l\'IA voit ce que vous voyez.' },
{ title: 'Memo vocal', description: 'Notes vocales auto-organisees avec #tags. Exportez en markdown. Recherchez, filtrez, classez.' },
],
},
pipeline: {
index: '02 / PIPELINE',
title: 'Quatre etapes. Deux secondes.',
subtitle: 'Une pression de touche et votre parole devient du texte soigne.',
steps: [
{ label: 'ENTREE', title: 'Appuyez sur la touche', description: 'Maintenez Right Alt (ou votre touche personnalisee) pour enregistrer. Double appui pour le mode IA. Basculez pour mains libres.', detail: 'Maintenir / Basculer / Double appui' },
{ label: 'TRANSCRIRE', title: 'Whisper STT', description: 'Le moteur local faster-whisper convertit l\'audio PCM 16kHz en texte en temps reel. Acceleration GPU supportee.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'TRAITER', title: 'Ollama LLM', description: 'Le LLM local corrige la grammaire, ajuste le ton, traduit ou resume. Instructions personnalisees supportees.', detail: 'qwen3 / llama3 / gemma3 / personnalise' },
{ label: 'SORTIE', title: 'Insertion automatique', description: 'Le texte corrige est colle a la position du curseur dans n\'importe quelle app. Bloc-notes, VS Code, Chrome, Slack, partout.', detail: 'Presse-papiers + Ctrl+V / 100ms latence' },
],
panelTitle: 'D3RO Voice Pipeline',
panelActive: 'Actif',
panelLatency: 'LATENCE : 1.2s',
sttReady: 'STT Pret',
llmConnected: 'LLM Connecte',
transcription: 'Transcription',
aiPolish: 'Correction IA',
sampleInput: 'Veuillez resumer les notes de reunion d\'aujourd\'hui...',
sampleOutput: 'Veuillez resumer les notes de la reunion d\'aujourd\'hui.',
},
privacy: {
index: '03 / VIE PRIVEE',
title: 'Votre voix ne sort jamais.',
subtitle: 'Chaque octet audio, chaque transcription, chaque interaction IA reste sur votre machine.',
monitorTitle: 'Moniteur de confidentialite',
allClear: 'TOUT OK',
metrics: [
{ label: 'TRAFIC CLOUD', value: '0 OCTETS' },
{ label: 'CHIFFREMENT', value: 'SQLite LOCAL' },
{ label: 'TELEMETRIE', value: 'DESACTIVEE' },
{ label: 'RESEAU REQUIS', value: 'NON' },
{ label: 'STOCKAGE AUDIO', value: 'LOCAL UNIQUEMENT' },
{ label: 'OPEN SOURCE', value: 'OUI' },
],
guarantees: [
'Aucun internet requis apres le telechargement initial du modele',
'Enregistrements vocaux stockes uniquement dans SQLite local',
'Supprimez toutes les donnees a tout moment en un clic',
'Open source - inspectez chaque ligne de code',
'Pas de compte, pas d\'inscription, pas de pistage',
'Whisper et Ollama fonctionnent tous deux sur votre materiel',
],
},
pricing: {
index: '04 / TARIFS',
title: 'Pas d\'abonnement. Jamais.',
subtitle: 'Pas de cloud signifie pas de factures mensuelles. Achat unique, utilisation a vie.',
featureLabel: 'Fonction',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'gratuit a vie',
oneTime: 'paiement unique',
popular: 'Populaire',
downloadFree: 'Telecharger gratuit',
getPro: 'Obtenir Pro',
getProPlus: 'Obtenir Pro+',
taxNote: 'Tous les prix hors taxes. Paiement securise via LemonSqueezy.',
rows: [
{ feature: 'Dictee vocale', free: '15/jour', pro: true, proPlus: true },
{ feature: 'Correction IA', free: '3/jour', pro: true, proPlus: true },
{ feature: 'Conservation historique', free: '3 jours', pro: true, proPlus: true },
{ feature: 'Instructions personnalisees', free: 'Predefinis', pro: true, proPlus: true },
{ feature: 'Sous-titres en direct', free: false, pro: true, proPlus: true },
{ feature: 'Contexte d\'ecran', free: false, pro: true, proPlus: true },
{ feature: 'Memo vocal + tags', free: false, pro: true, proPlus: true },
{ feature: 'Chaine multi-LLM', free: false, pro: true, proPlus: true },
{ feature: 'Commandes vocales', free: false, pro: true, proPlus: true },
{ feature: 'Export historique', free: false, pro: true, proPlus: true },
{ feature: 'Transcription de fichiers', free: false, pro: false, proPlus: true },
{ feature: 'Conversation vocale', free: false, pro: false, proPlus: true },
{ feature: 'Resume de reunion', free: false, pro: false, proPlus: true },
{ feature: 'RAG local', free: false, pro: false, proPlus: true },
{ feature: 'Automatisation OS', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Questions frequentes.',
items: [
{ q: 'Dois-je installer Ollama et Whisper separement ?', a: 'Whisper (faster-whisper) est integre a l\'application - aucune installation separee requise. Ollama n\'est necessaire que pour les fonctions de correction/traduction IA et s\'installe facilement via le guide integre. La dictee basique fonctionne sans Ollama.' },
{ q: 'Quel GPU me faut-il ?', a: 'Aucun GPU requis - ca fonctionne uniquement sur CPU. Un GPU NVIDIA (CUDA) accelere la transcription 5-10x. Avec le modele base, la transcription en temps reel sur CPU est possible.' },
{ q: 'Ca fonctionne completement hors ligne ?', a: 'Oui. Une fois les modeles Whisper et Ollama telecharges, tout fonctionne sans internet. La verification de licence est en ligne uniquement pour l\'activation initiale, puis 30 jours de grace hors ligne.' },
{ q: 'Quelle est la precision de la reconnaissance vocale ?', a: 'Whisper large-v3 offre une excellente precision pour plus de 99 langues. La fonction de dictionnaire personnalise ameliore encore la precision pour la terminologie specialisee.' },
{ q: 'C\'est un abonnement ?', a: 'Non. Pro et Pro+ sont des achats uniques. Payez une fois, utilisez pour toujours. Mises a jour majeures incluses. Sans couts de serveur cloud, nous n\'avons pas besoin de modele d\'abonnement.' },
{ q: 'Et macOS et Linux ?', a: 'Actuellement Windows uniquement. Construit avec Electron, le support macOS/Linux est techniquement faisable et prevu selon la demande.' },
],
},
cta: {
title1: 'Parlez.',
title2: 'L\'IA ecrit.',
subtitle1: 'Pas de cloud. Pas d\'abonnement. Aucun souci de vie privee.',
subtitle2: 'Commencez maintenant.',
downloadBtn: 'Telecharger pour Windows',
systemReq: 'Windows 10/11 \u00b7 64-bit \u00b7 ~200 Mo \u00b7 Pret en secondes',
},
footer: {
description: 'Assistant vocal IA entierement local. Propulse par Whisper et Ollama. Votre voix, votre machine, vos donnees.',
copyright: '\u00a9 {year} D3RO Voice. Tous droits reserves.',
builtWith: 'Construit avec Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/ja.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const ja: Translations = {
nav: {
features: '機能',
pipeline: 'パイプライン',
privacy: 'プライバシー',
pricing: '料金',
faq: 'FAQ',
download: 'ダウンロード',
},
hero: {
badge: '100% ローカル \u00b7 クラウドゼロ',
title1: 'ローカルAI',
title2: '音声',
title3: 'アシスタント.',
subtitle: 'Whisper + Ollama搭載の音声テキスト変換パイプラインがあなたのマシン上で完全に動作。ディクテーション、AI校正、リアルタイム字幕、音声会話 \u2014 インターネット不要。',
downloadBtn: 'Windows版をダウンロード',
viewFeatures: '機能を見る',
dataProcessing: '処理',
dataCloudTraffic: 'クラウド通信',
dataLatency: 'STTレイテンシ',
dataPrivacy: 'プライバシースコア',
systemStatus: 'システム状態: 稼働中',
protocol: 'プロトコル: 2025.04',
},
features: {
index: '01 / 機能',
title: '完全な音声インテリジェンス.',
subtitle: 'ディクテーションからAI会話まで。すべてがオフラインであなたのハードウェア上で実行されます。',
items: [
{ title: '音声ディクテーション', description: 'ホットキーを押して話し、離す。Whisperが即座に音声をテキストに変換し、アクティブなアプリに挿入します。' },
{ title: 'AIテキスト校正', description: 'Ollama LLMが文字起こしテキストを文法的に正確で読みやすい文章に校正。フォーマルからカジュアルまで。' },
{ title: '即時翻訳', description: '一つの言語で話し、別の言語でテキストを取得。ソース言語を自動検出し、デバイス上で翻訳。' },
{ title: 'リアルタイム字幕', description: '画面上にリアルタイム字幕オーバーレイ。会議、講義、動画視聴に。議事録の自動エクスポート。' },
{ title: '音声会話', description: 'ローカルChatGPT音声モード。STT-LLM-TTSの完全ループで自然なAI会話を完全オフラインで。' },
{ title: 'ファイル文字起こし', description: 'オーディオまたはビデオファイルをドラッグ&ドロップ。Whisperがタイムスタンプ付きで全内容を文字起こし。' },
{ title: 'マルチLLMチェーン', description: '複数のAIコマンドをパイプライン化文字起こし、翻訳、要約をホットキー一押しで実行。' },
{ title: 'スクリーンコンテキスト', description: 'アクティブアプリと選択テキストを自動キャプチャ。「このコードを説明して」と言えばAIがあなたの見ているものを認識。' },
{ title: '音声メモ', description: '#タグで自動整理される音声ノート。マークダウンでエクスポート。検索、フィルター、分類。' },
],
},
pipeline: {
index: '02 / パイプライン',
title: '4ステップ、2秒。',
subtitle: 'ホットキー一押しで音声が洗練されたテキストに。',
steps: [
{ label: '入力', title: 'ホットキー押下', description: 'Right Altまたはカスタムキーを長押しで録音開始。ダブルタップでAIモード。トグルでハンズフリー。', detail: '長押し / トグル / ダブルプレス' },
{ label: '文字起こし', title: 'Whisper STT', description: 'ローカルfaster-whisperエンジンが16kHz PCMオーディオをリアルタイムでテキストに変換。GPU加速対応。', detail: 'faster-whisper / base ~ large-v3' },
{ label: '処理', title: 'Ollama LLM', description: 'ローカルLLMが文法を校正し、トーンを調整し、翻訳または要約。カスタム指示に対応。', detail: 'qwen3 / llama3 / gemma3 / カスタム' },
{ label: '出力', title: '自動挿入', description: '校正されたテキストが任意のアプリのカーソル位置に自動貼り付け。メモ帳、VS Code、Chrome、Slackなど。', detail: 'クリップボード + Ctrl+V / 100msレイテンシ' },
],
panelTitle: 'D3RO Voice パイプライン',
panelActive: 'アクティブ',
panelLatency: 'レイテンシ: 1.2秒',
sttReady: 'STT準備完了',
llmConnected: 'LLM接続済み',
transcription: '文字起こし',
aiPolish: 'AI校正',
sampleInput: '今日の会議メモをまとめてください...',
sampleOutput: '本日の会議メモをまとめてください。',
},
privacy: {
index: '03 / プライバシー',
title: 'あなたの声は外に出ません.',
subtitle: 'オーディオのすべてのバイト、すべての文字起こし、すべてのAIインタラクションがあなたのマシンに留まります。',
monitorTitle: 'プライバシーモニター',
allClear: '異常なし',
metrics: [
{ label: 'クラウド通信', value: '0バイト' },
{ label: 'データ暗号化', value: 'ローカルSQLite' },
{ label: 'テレメトリ', value: '無効' },
{ label: 'ネットワーク必要', value: 'いいえ' },
{ label: 'オーディオ保存', value: 'ローカルのみ' },
{ label: 'オープンソース', value: 'はい' },
],
guarantees: [
'初回モデルダウンロード後はインターネット不要',
'音声録音はローカルSQLiteにのみ保存',
'ワンクリックでいつでもすべてのデータを削除',
'オープンソース - すべてのコードを確認可能',
'アカウント不要、サインアップ不要、トラッキング不要',
'WhisperとOllamaの両方があなたのハードウェアで実行',
],
},
pricing: {
index: '04 / 料金',
title: 'サブスクリプションなし、永久に。',
subtitle: 'クラウドなしだから月額料金もなし。一度の購入で永久使用。',
featureLabel: '機能',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: '永久無料',
oneTime: '買い切り',
popular: '人気',
downloadFree: '無料ダウンロード',
getPro: 'Proを購入',
getProPlus: 'Pro+を購入',
taxNote: '表示価格は税抜きです。LemonSqueezyによる安全な決済。',
rows: [
{ feature: '音声ディクテーション', free: '15回/日', pro: true, proPlus: true },
{ feature: 'AIテキスト校正', free: '3回/日', pro: true, proPlus: true },
{ feature: '履歴保持', free: '3日間', pro: true, proPlus: true },
{ feature: 'カスタム指示', free: 'プリセット', pro: true, proPlus: true },
{ feature: 'リアルタイム字幕', free: false, pro: true, proPlus: true },
{ feature: 'スクリーンコンテキスト', free: false, pro: true, proPlus: true },
{ feature: '音声メモ + タグ', free: false, pro: true, proPlus: true },
{ feature: 'マルチLLMチェーン', free: false, pro: true, proPlus: true },
{ feature: '音声コマンド', free: false, pro: true, proPlus: true },
{ feature: '履歴エクスポート', free: false, pro: true, proPlus: true },
{ feature: 'ファイル文字起こし', free: false, pro: false, proPlus: true },
{ feature: '音声会話', free: false, pro: false, proPlus: true },
{ feature: '議事録要約', free: false, pro: false, proPlus: true },
{ feature: 'ローカルRAG', free: false, pro: false, proPlus: true },
{ feature: 'OS自動化', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'よくある質問.',
items: [
{ q: 'OllamaとWhisperを別途インストールする必要がありますか', a: 'Whisperfaster-whisperはアプリにバンドルされており、別途インストールは不要です。Ollamaは AI校正/翻訳機能にのみ必要で、アプリ内ガイドで簡単にインストールできます。基本ディクテーションはOllamaなしで動作します。' },
{ q: 'どんなGPUが必要ですか', a: 'GPUは不要 - CPUだけで動作します。NVIDIA GPUCUDAがあれば文字起こしが5-10倍高速化。baseモデルならCPUでリアルタイム文字起こしが可能です。' },
{ q: '完全にオフラインで動作しますか?', a: 'はい。WhisperとOllamaのモデルをダウンロードすれば、すべてがインターネットなしで動作します。ライセンス認証は初回アクティベーション時のみオンラインが必要で、その後30日間のオフライン猶予期間があります。' },
{ q: '音声認識の精度はどうですか?', a: 'Whisper large-v3は99以上の言語で優れた精度を提供します。カスタム辞書機能により、専門用語の認識精度をさらに向上できます。' },
{ q: 'サブスクリプションですか?', a: 'いいえ。ProとPro+は買い切りです。一度購入すれば永久使用。メジャーアップデート込み。クラウドサーバーのコストがないため、サブスクリプションモデルは不要です。' },
{ q: 'macOSとLinuxには対応していますか', a: '現在はWindows専用です。ElectronベースなのでmacOS/Linuxサポートは技術的に可能で、需要に応じて対応予定です。' },
],
},
cta: {
title1: '話す。',
title2: 'AIが書く。',
subtitle1: 'クラウドなし。サブスクなし。プライバシーの心配なし。',
subtitle2: '今すぐ始めましょう。',
downloadBtn: 'Windows版をダウンロード',
systemReq: 'Windows 10/11 \u00b7 64ビット \u00b7 約200MB \u00b7 数秒で準備完了',
},
footer: {
description: '完全ローカルAI音声アシスタント。WhisperとOllama搭載。あなたの声、あなたのマシン、あなたのデータ。',
copyright: '\u00a9 {year} D3RO Voice. All rights reserved.',
builtWith: 'Electron + React + TypeScriptで構築',
},
}

144
site/src/i18n/locales/ko.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const ko: Translations = {
nav: {
features: '기능',
pipeline: '파이프라인',
privacy: '프라이버시',
pricing: '가격',
faq: 'FAQ',
download: '다운로드',
},
hero: {
badge: '100% 로컬 \u00b7 클라우드 제로',
title1: '로컬 AI',
title2: '음성',
title3: '어시스턴트.',
subtitle: 'Whisper + Ollama 기반 음성-텍스트 파이프라인이 당신의 컴퓨터에서 완전히 작동합니다. 받아쓰기, AI 다듬기, 실시간 자막, 음성 대화 \u2014 인터넷이 필요 없습니다.',
downloadBtn: 'Windows용 다운로드',
viewFeatures: '기능 보기',
dataProcessing: '처리 방식',
dataCloudTraffic: '클라우드 트래픽',
dataLatency: 'STT 지연시간',
dataPrivacy: '프라이버시 점수',
systemStatus: '시스템 상태: 정상 가동',
protocol: '프로토콜: 2025.04',
},
features: {
index: '01 / 기능',
title: '완전한 음성 인텔리전스.',
subtitle: '받아쓰기부터 AI 대화까지. 모든 것이 오프라인으로 당신의 하드웨어에서 실행됩니다.',
items: [
{ title: '음성 받아쓰기', description: '핫키를 누르고, 말하고, 놓으세요. Whisper가 즉시 음성을 텍스트로 변환하여 활성 앱에 삽입합니다.' },
{ title: 'AI 텍스트 다듬기', description: 'Ollama LLM이 전사된 텍스트를 깔끔하고 문법적으로 정확한 문장으로 다듬어줍니다. 격식체와 구어체 모두 지원.' },
{ title: '즉시 번역', description: '한 언어로 말하면 다른 언어로 텍스트를 받으세요. 소스 언어 자동 감지, 기기에서 직접 번역.' },
{ title: '실시간 자막', description: '화면 위에 실시간 자막 오버레이. 회의, 강의, 영상 시청에 활용. 회의록 자동 내보내기.' },
{ title: '음성 대화', description: '로컬 ChatGPT 음성 모드. STT-LLM-TTS 완전 루프로 자연스러운 AI 대화를 완전 오프라인으로.' },
{ title: '파일 전사', description: '오디오 또는 비디오 파일을 드래그 앤 드롭. Whisper가 타임스탬프와 함께 전체 내용을 전사합니다.' },
{ title: '멀티 LLM 체인', description: '여러 AI 명령어를 파이프라인으로: 전사, 번역, 요약을 핫키 한 번으로 실행.' },
{ title: '스크린 컨텍스트', description: '활성 앱과 선택된 텍스트를 자동 캡처. "이 코드 설명해줘"라고 말하면 AI가 당신이 보는 것을 봅니다.' },
{ title: '음성 메모', description: '#태그로 자동 정리되는 음성 노트. 마크다운으로 내보내기. 검색, 필터, 분류.' },
],
},
pipeline: {
index: '02 / 파이프라인',
title: '4단계. 2초.',
subtitle: '핫키 한 번이면 음성이 다듬어진 텍스트가 됩니다.',
steps: [
{ label: '입력', title: '핫키 누르기', description: 'Right Alt(또는 설정한 키)를 길게 눌러 녹음을 시작. 더블탭으로 AI 모드. 토글로 핸즈프리.', detail: '길게 누르기 / 토글 / 더블프레스' },
{ label: '전사', title: 'Whisper STT', description: '로컬 faster-whisper 엔진이 16kHz PCM 오디오를 실시간으로 텍스트로 변환. GPU 가속 지원.', detail: 'faster-whisper / base ~ large-v3' },
{ label: '처리', title: 'Ollama LLM', description: '로컬 LLM이 문법을 다듬고, 톤을 조절하고, 번역하거나 요약합니다. 커스텀 명령어 지원.', detail: 'qwen3 / llama3 / gemma3 / 커스텀' },
{ label: '출력', title: '자동 삽입', description: '다듬어진 텍스트가 어떤 앱에서든 커서 위치에 자동 붙여넣기. 메모장, VS Code, Chrome, Slack, 어디서나.', detail: '클립보드 + Ctrl+V / 100ms 지연' },
],
panelTitle: 'D3RO Voice 파이프라인',
panelActive: '활성',
panelLatency: '지연시간: 1.2초',
sttReady: 'STT 준비 완료',
llmConnected: 'LLM 연결됨',
transcription: '전사',
aiPolish: 'AI 다듬기',
sampleInput: '오늘 회의 노트 정리해줘...',
sampleOutput: '오늘 회의록을 정리해 주세요.',
},
privacy: {
index: '03 / 프라이버시',
title: '음성은 절대 외부로 나가지 않습니다.',
subtitle: '오디오의 모든 바이트, 모든 전사, 모든 AI 상호작용이 당신의 컴퓨터에 머무릅니다.',
monitorTitle: '프라이버시 모니터',
allClear: '이상 없음',
metrics: [
{ label: '클라우드 트래픽', value: '0 바이트' },
{ label: '데이터 암호화', value: '로컬 SQLite' },
{ label: '텔레메트리', value: '비활성화' },
{ label: '네트워크 필요', value: '아니오' },
{ label: '오디오 저장', value: '로컬 전용' },
{ label: '오픈 소스', value: '예' },
],
guarantees: [
'초기 모델 다운로드 이후 인터넷 불필요',
'음성 녹음은 로컬 SQLite에만 저장',
'클릭 한 번으로 언제든 모든 데이터 삭제',
'오픈 소스 - 모든 코드를 직접 확인 가능',
'계정 없음, 가입 없음, 추적 없음',
'Whisper와 Ollama 모두 당신의 하드웨어에서 실행',
],
},
pricing: {
index: '04 / 가격',
title: '구독 없음. 영원히.',
subtitle: '클라우드가 없으니 월 요금도 없습니다. 한 번 구매, 평생 사용.',
featureLabel: '기능',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: '영구 무료',
oneTime: '1회 결제',
popular: '인기',
downloadFree: '무료 다운로드',
getPro: 'Pro 구매',
getProPlus: 'Pro+ 구매',
taxNote: '모든 가격은 세금 별도입니다. LemonSqueezy를 통한 안전한 결제.',
rows: [
{ feature: '음성 받아쓰기', free: '15회/일', pro: true, proPlus: true },
{ feature: 'AI 텍스트 다듬기', free: '3회/일', pro: true, proPlus: true },
{ feature: '히스토리 보존', free: '3일', pro: true, proPlus: true },
{ feature: '커스텀 명령어', free: '프리셋', pro: true, proPlus: true },
{ feature: '실시간 자막', free: false, pro: true, proPlus: true },
{ feature: '스크린 컨텍스트', free: false, pro: true, proPlus: true },
{ feature: '음성 메모 + 태그', free: false, pro: true, proPlus: true },
{ feature: '멀티 LLM 체인', free: false, pro: true, proPlus: true },
{ feature: '음성 단축키', free: false, pro: true, proPlus: true },
{ feature: '히스토리 내보내기', free: false, pro: true, proPlus: true },
{ feature: '파일 전사', free: false, pro: false, proPlus: true },
{ feature: '음성 대화', free: false, pro: false, proPlus: true },
{ feature: '회의록 요약', free: false, pro: false, proPlus: true },
{ feature: '로컬 RAG', free: false, pro: false, proPlus: true },
{ feature: 'OS 자동화', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: '자주 묻는 질문.',
items: [
{ q: 'Ollama와 Whisper를 따로 설치해야 하나요?', a: 'Whisper(faster-whisper)는 앱에 내장되어 있어 별도 설치가 필요 없습니다. Ollama는 AI 다듬기/번역 기능에만 필요하며, 인앱 가이드를 통해 쉽게 설치할 수 있습니다. 기본 받아쓰기는 Ollama 없이도 작동합니다.' },
{ q: '어떤 GPU가 필요한가요?', a: 'GPU가 없어도 CPU만으로 작동합니다. NVIDIA GPU(CUDA)가 있으면 전사 속도가 5-10배 빨라집니다. base 모델 기준 CPU 실시간 전사가 가능합니다.' },
{ q: '완전히 오프라인으로 작동하나요?', a: '네. Whisper와 Ollama 모델을 다운로드하면 인터넷 없이 모든 것이 작동합니다. 라이선스 검증은 최초 활성화 시에만 온라인이 필요하며, 이후 30일 오프라인 유예 기간이 제공됩니다.' },
{ q: '음성 인식 정확도는 어떤가요?', a: 'Whisper large-v3는 99개 이상의 언어에서 뛰어난 정확도를 제공합니다. 커스텀 사전 기능으로 전문 용어의 인식률을 더욱 높일 수 있습니다.' },
{ q: '구독 모델인가요?', a: '아닙니다. Pro와 Pro+는 1회 결제입니다. 한 번 구매하면 영구 사용. 주요 업데이트 포함. 클라우드 서버 비용이 없기 때문에 구독 모델이 필요 없습니다.' },
{ q: 'macOS와 Linux는 지원하나요?', a: '현재는 Windows 전용입니다. Electron 기반이므로 macOS/Linux 지원이 기술적으로 가능하며, 수요에 따라 지원할 예정입니다.' },
],
},
cta: {
title1: '말하세요.',
title2: 'AI가 씁니다.',
subtitle1: '클라우드 없음. 구독 없음. 프라이버시 걱정 없음.',
subtitle2: '지금 시작하세요.',
downloadBtn: 'Windows용 다운로드',
systemReq: 'Windows 10/11 \u00b7 64비트 \u00b7 ~200MB \u00b7 몇 초면 준비 완료',
},
footer: {
description: '완전 로컬 AI 음성 어시스턴트. Whisper와 Ollama 기반. 당신의 음성, 당신의 컴퓨터, 당신의 데이터.',
copyright: '\u00a9 {year} D3RO Voice. All rights reserved.',
builtWith: 'Electron + React + TypeScript로 제작',
},
}

144
site/src/i18n/locales/pt.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const pt: Translations = {
nav: {
features: 'RECURSOS',
pipeline: 'PIPELINE',
privacy: 'PRIVACIDADE',
pricing: 'PRECOS',
faq: 'FAQ',
download: 'Download',
},
hero: {
badge: '100% LOCAL \u00b7 ZERO NUVEM',
title1: 'IA LOCAL',
title2: 'ASSISTENTE',
title3: 'DE VOZ.',
subtitle: 'Pipeline de voz para texto com Whisper + Ollama rodando inteiramente na sua maquina. Ditado, polimento com IA, legendas em tempo real, conversas por voz \u2014 sem internet.',
downloadBtn: 'Baixar para Windows',
viewFeatures: 'Ver recursos',
dataProcessing: 'Processamento',
dataCloudTraffic: 'Trafego na nuvem',
dataLatency: 'Latencia STT',
dataPrivacy: 'Score de privacidade',
systemStatus: 'STATUS DO SISTEMA: OPERACIONAL',
protocol: 'PROTOCOLO: 2025.04',
},
features: {
index: '01 / RECURSOS',
title: 'Inteligencia de voz completa.',
subtitle: 'Do ditado a conversa com IA. Tudo roda no seu hardware, offline.',
items: [
{ title: 'Ditado por voz', description: 'Segure uma tecla, fale, solte. Whisper transcreve e insere texto no seu app ativo instantaneamente.' },
{ title: 'Polimento com IA', description: 'Ollama LLM refina seu texto transcrito em prosa limpa e gramaticalmente correta. Formal ou casual.' },
{ title: 'Traducao instantanea', description: 'Fale em um idioma, receba texto em outro. Deteccao automatica da origem, traducao no dispositivo.' },
{ title: 'Legendas ao vivo', description: 'Sobreposicao de legendas em tempo real na sua tela. Reunioes, aulas, videos. Exportacao automatica de notas.' },
{ title: 'Conversa por voz', description: 'Modo de voz ChatGPT local. Loop completo STT-LLM-TTS para conversas naturais com IA, totalmente offline.' },
{ title: 'Transcricao de arquivos', description: 'Arraste e solte arquivos de audio ou video. Whisper transcreve todo o conteudo com marcacoes de tempo.' },
{ title: 'Cadeia multi-LLM', description: 'Encadeie multiplos comandos de IA: transcrever, traduzir, depois resumir com um unico atalho.' },
{ title: 'Contexto de tela', description: 'Captura automatica do app ativo e texto selecionado. Diga "explique este codigo" e a IA ve o que voce ve.' },
{ title: 'Memo de voz', description: 'Notas de voz auto-organizadas com #tags. Exporte como markdown. Pesquise, filtre, categorize.' },
],
},
pipeline: {
index: '02 / PIPELINE',
title: 'Quatro passos. Dois segundos.',
subtitle: 'Um atalho e sua fala se torna texto polido.',
steps: [
{ label: 'ENTRADA', title: 'Pressione a tecla', description: 'Segure Right Alt (ou sua tecla personalizada) para gravar. Toque duplo para modo IA. Alternar para viva-voz.', detail: 'Segurar / Alternar / Toque duplo' },
{ label: 'TRANSCREVER', title: 'Whisper STT', description: 'Motor local faster-whisper converte audio PCM 16kHz em texto em tempo real. Aceleracao GPU suportada.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'PROCESSAR', title: 'Ollama LLM', description: 'LLM local corrige gramatica, ajusta tom, traduz ou resume. Instrucoes personalizadas suportadas.', detail: 'qwen3 / llama3 / gemma3 / personalizado' },
{ label: 'SAIDA', title: 'Insercao automatica', description: 'Texto polido e colado na posicao do cursor em qualquer app. Bloco de notas, VS Code, Chrome, Slack, em qualquer lugar.', detail: 'Area de transferencia + Ctrl+V / 100ms latencia' },
],
panelTitle: 'D3RO Voice Pipeline',
panelActive: 'Ativo',
panelLatency: 'LATENCIA: 1.2s',
sttReady: 'STT Pronto',
llmConnected: 'LLM Conectado',
transcription: 'Transcricao',
aiPolish: 'Polimento IA',
sampleInput: 'Por favor, resuma as notas da reuniao de hoje...',
sampleOutput: 'Por favor, resuma as notas da reuniao de hoje.',
},
privacy: {
index: '03 / PRIVACIDADE',
title: 'Sua voz nunca sai.',
subtitle: 'Cada byte de audio, cada transcricao, cada interacao com IA permanece na sua maquina.',
monitorTitle: 'Monitor de privacidade',
allClear: 'TUDO OK',
metrics: [
{ label: 'TRAFEGO NA NUVEM', value: '0 BYTES' },
{ label: 'CRIPTOGRAFIA', value: 'SQLite LOCAL' },
{ label: 'TELEMETRIA', value: 'DESATIVADA' },
{ label: 'REDE NECESSARIA', value: 'NAO' },
{ label: 'ARMAZENAMENTO DE AUDIO', value: 'APENAS LOCAL' },
{ label: 'CODIGO ABERTO', value: 'SIM' },
],
guarantees: [
'Sem internet apos o download inicial do modelo',
'Gravacoes de voz armazenadas apenas no SQLite local',
'Exclua todos os dados a qualquer momento com um clique',
'Codigo aberto - inspecione cada linha de codigo',
'Sem contas, sem cadastros, sem rastreamento',
'Whisper e Ollama rodam no seu hardware',
],
},
pricing: {
index: '04 / PRECOS',
title: 'Sem assinatura. Nunca.',
subtitle: 'Sem nuvem significa sem contas mensais. Compra unica, uso vitalicio.',
featureLabel: 'Recurso',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'gratis para sempre',
oneTime: 'pagamento unico',
popular: 'Popular',
downloadFree: 'Baixar gratis',
getPro: 'Obter Pro',
getProPlus: 'Obter Pro+',
taxNote: 'Todos os precos excluem impostos. Pagamento seguro via LemonSqueezy.',
rows: [
{ feature: 'Ditado por voz', free: '15/dia', pro: true, proPlus: true },
{ feature: 'Polimento com IA', free: '3/dia', pro: true, proPlus: true },
{ feature: 'Retencao de historico', free: '3 dias', pro: true, proPlus: true },
{ feature: 'Instrucoes personalizadas', free: 'Presets', pro: true, proPlus: true },
{ feature: 'Legendas ao vivo', free: false, pro: true, proPlus: true },
{ feature: 'Contexto de tela', free: false, pro: true, proPlus: true },
{ feature: 'Memo de voz + tags', free: false, pro: true, proPlus: true },
{ feature: 'Cadeia multi-LLM', free: false, pro: true, proPlus: true },
{ feature: 'Comandos de voz', free: false, pro: true, proPlus: true },
{ feature: 'Exportar historico', free: false, pro: true, proPlus: true },
{ feature: 'Transcricao de arquivos', free: false, pro: false, proPlus: true },
{ feature: 'Conversa por voz', free: false, pro: false, proPlus: true },
{ feature: 'Resumo de reuniao', free: false, pro: false, proPlus: true },
{ feature: 'RAG local', free: false, pro: false, proPlus: true },
{ feature: 'Automacao do SO', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Perguntas frequentes.',
items: [
{ q: 'Preciso instalar Ollama e Whisper separadamente?', a: 'Whisper (faster-whisper) ja vem com o app - sem instalacao separada. Ollama e necessario apenas para recursos de polimento/traducao com IA e pode ser instalado facilmente pelo guia do app. O ditado basico funciona sem Ollama.' },
{ q: 'Qual GPU preciso?', a: 'Nenhuma GPU necessaria - funciona apenas com CPU. Uma GPU NVIDIA (CUDA) acelera a transcricao 5-10x. Com o modelo base, transcricao em tempo real por CPU e possivel.' },
{ q: 'Funciona completamente offline?', a: 'Sim. Apos baixar os modelos Whisper e Ollama, tudo funciona sem internet. A verificacao de licenca e online apenas na ativacao inicial, depois 30 dias de carencia offline.' },
{ q: 'Qual a precisao do reconhecimento de voz?', a: 'Whisper large-v3 oferece excelente precisao para mais de 99 idiomas. O recurso de dicionario personalizado melhora ainda mais a precisao para terminologia especializada.' },
{ q: 'E uma assinatura?', a: 'Nao. Pro e Pro+ sao compras unicas. Pague uma vez, use para sempre. Atualizacoes principais incluidas. Sem custos de servidor na nuvem, nao precisamos de modelo de assinatura.' },
{ q: 'E o macOS e Linux?', a: 'Atualmente apenas Windows. Construido com Electron, o suporte macOS/Linux e tecnicamente viavel e planejado conforme a demanda.' },
],
},
cta: {
title1: 'Fale.',
title2: 'A IA escreve.',
subtitle1: 'Sem nuvem. Sem assinatura. Sem preocupacoes com privacidade.',
subtitle2: 'Comece agora.',
downloadBtn: 'Baixar para Windows',
systemReq: 'Windows 10/11 \u00b7 64-bit \u00b7 ~200MB \u00b7 Pronto em segundos',
},
footer: {
description: 'Assistente de voz IA totalmente local. Alimentado por Whisper e Ollama. Sua voz, sua maquina, seus dados.',
copyright: '\u00a9 {year} D3RO Voice. Todos os direitos reservados.',
builtWith: 'Construido com Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/ru.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const ru: Translations = {
nav: {
features: 'ФУНКЦИИ',
pipeline: 'КОНВЕЙЕР',
privacy: 'ПРИВАТНОСТЬ',
pricing: 'ЦЕНЫ',
faq: 'FAQ',
download: 'Скачать',
},
hero: {
badge: '100% ЛОКАЛЬНО \u00b7 БЕЗ ОБЛАКА',
title1: 'ЛОКАЛЬНЫЙ ИИ',
title2: 'ГОЛОСОВОЙ',
title3: 'АССИСТЕНТ.',
subtitle: 'Конвейер преобразования речи в текст на Whisper + Ollama, полностью работающий на вашем компьютере. Диктовка, ИИ-корректировка, субтитры в реальном времени, голосовые разговоры \u2014 интернет не нужен.',
downloadBtn: 'Скачать для Windows',
viewFeatures: 'Смотреть функции',
dataProcessing: 'Обработка',
dataCloudTraffic: 'Облачный трафик',
dataLatency: 'Задержка STT',
dataPrivacy: 'Оценка приватности',
systemStatus: 'СТАТУС СИСТЕМЫ: РАБОТАЕТ',
protocol: 'ПРОТОКОЛ: 2025.04',
},
features: {
index: '01 / ФУНКЦИИ',
title: 'Полный голосовой интеллект.',
subtitle: 'От диктовки до ИИ-разговора. Все работает на вашем оборудовании, офлайн.',
items: [
{ title: 'Голосовая диктовка', description: 'Удерживайте горячую клавишу, говорите, отпустите. Whisper мгновенно транскрибирует и вставляет текст в активное приложение.' },
{ title: 'ИИ-корректировка текста', description: 'Ollama LLM превращает транскрибированный текст в чистую, грамматически правильную прозу. Формально или неформально.' },
{ title: 'Мгновенный перевод', description: 'Говорите на одном языке, получайте текст на другом. Автоматическое определение языка, перевод на устройстве.' },
{ title: 'Субтитры в реальном времени', description: 'Наложение субтитров в реальном времени на экран. Совещания, лекции, видео. Автоматический экспорт заметок.' },
{ title: 'Голосовой разговор', description: 'Локальный голосовой режим ChatGPT. Полный цикл STT-LLM-TTS для естественных ИИ-разговоров, полностью офлайн.' },
{ title: 'Транскрипция файлов', description: 'Перетащите аудио- или видеофайлы. Whisper транскрибирует весь контент с временными метками.' },
{ title: 'Мульти-LLM цепочка', description: 'Цепочка из нескольких ИИ-команд: транскрибировать, перевести, затем обобщить одним нажатием клавиши.' },
{ title: 'Контекст экрана', description: 'Автоматический захват активного приложения и выделенного текста. Скажите "объясни этот код" и ИИ увидит то же, что и вы.' },
{ title: 'Голосовые заметки', description: 'Автоматически организованные голосовые заметки с #тегами. Экспорт в markdown. Поиск, фильтрация, категоризация.' },
],
},
pipeline: {
index: '02 / КОНВЕЙЕР',
title: 'Четыре шага. Две секунды.',
subtitle: 'Одно нажатие клавиши \u2014 и ваша речь становится отредактированным текстом.',
steps: [
{ label: 'ВВОД', title: 'Нажмите горячую клавишу', description: 'Удерживайте Right Alt (или вашу клавишу) для записи. Двойное нажатие для ИИ-режима. Переключение для свободных рук.', detail: 'Удержание / Переключение / Двойное нажатие' },
{ label: 'ТРАНСКРИПЦИЯ', title: 'Whisper STT', description: 'Локальный движок faster-whisper преобразует 16кГц PCM аудио в текст в реальном времени. Поддержка GPU-ускорения.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'ОБРАБОТКА', title: 'Ollama LLM', description: 'Локальная LLM корректирует грамматику, настраивает тон, переводит или обобщает. Пользовательские инструкции поддерживаются.', detail: 'qwen3 / llama3 / gemma3 / пользовательский' },
{ label: 'ВЫВОД', title: 'Автовставка', description: 'Отредактированный текст вставляется в позицию курсора в любом приложении. Блокнот, VS Code, Chrome, Slack, где угодно.', detail: 'Буфер обмена + Ctrl+V / 100мс задержка' },
],
panelTitle: 'D3RO Voice Конвейер',
panelActive: 'Активен',
panelLatency: 'ЗАДЕРЖКА: 1.2с',
sttReady: 'STT Готов',
llmConnected: 'LLM Подключен',
transcription: 'Транскрипция',
aiPolish: 'ИИ-корректировка',
sampleInput: 'Пожалуйста, обобщите заметки с сегодняшнего совещания...',
sampleOutput: 'Пожалуйста, обобщите заметки с сегодняшнего совещания.',
},
privacy: {
index: '03 / ПРИВАТНОСТЬ',
title: 'Ваш голос никогда не покидает компьютер.',
subtitle: 'Каждый байт аудио, каждая транскрипция, каждое взаимодействие с ИИ остается на вашем устройстве.',
monitorTitle: 'Монитор приватности',
allClear: 'ВСЕ В ПОРЯДКЕ',
metrics: [
{ label: 'ОБЛАЧНЫЙ ТРАФИК', value: '0 БАЙТ' },
{ label: 'ШИФРОВАНИЕ ДАННЫХ', value: 'ЛОКАЛЬНЫЙ SQLite' },
{ label: 'ТЕЛЕМЕТРИЯ', value: 'ОТКЛЮЧЕНА' },
{ label: 'СЕТЬ ТРЕБУЕТСЯ', value: 'НЕТ' },
{ label: 'ХРАНЕНИЕ АУДИО', value: 'ТОЛЬКО ЛОКАЛЬНО' },
{ label: 'ОТКРЫТЫЙ КОД', value: 'ДА' },
],
guarantees: [
'Интернет не нужен после первоначальной загрузки модели',
'Голосовые записи хранятся только в локальном SQLite',
'Удалите все данные в любой момент одним кликом',
'Открытый исходный код \u2014 проверьте каждую строку',
'Без аккаунтов, без регистрации, без отслеживания',
'Whisper и Ollama работают на вашем оборудовании',
],
},
pricing: {
index: '04 / ЦЕНЫ',
title: 'Без подписки. Навсегда.',
subtitle: 'Нет облака \u2014 нет ежемесячных платежей. Одноразовая покупка, пожизненное использование.',
featureLabel: 'Функция',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'навсегда бесплатно',
oneTime: 'разовый платеж',
popular: 'Популярно',
downloadFree: 'Скачать бесплатно',
getPro: 'Получить Pro',
getProPlus: 'Получить Pro+',
taxNote: 'Все цены без учета налогов. Безопасная оплата через LemonSqueezy.',
rows: [
{ feature: 'Голосовая диктовка', free: '15/день', pro: true, proPlus: true },
{ feature: 'ИИ-корректировка текста', free: '3/день', pro: true, proPlus: true },
{ feature: 'Хранение истории', free: '3 дня', pro: true, proPlus: true },
{ feature: 'Пользовательские инструкции', free: 'Пресеты', pro: true, proPlus: true },
{ feature: 'Субтитры в реальном времени', free: false, pro: true, proPlus: true },
{ feature: 'Контекст экрана', free: false, pro: true, proPlus: true },
{ feature: 'Голосовые заметки + теги', free: false, pro: true, proPlus: true },
{ feature: 'Мульти-LLM цепочка', free: false, pro: true, proPlus: true },
{ feature: 'Голосовые команды', free: false, pro: true, proPlus: true },
{ feature: 'Экспорт истории', free: false, pro: true, proPlus: true },
{ feature: 'Транскрипция файлов', free: false, pro: false, proPlus: true },
{ feature: 'Голосовой разговор', free: false, pro: false, proPlus: true },
{ feature: 'Резюме совещания', free: false, pro: false, proPlus: true },
{ feature: 'Локальный RAG', free: false, pro: false, proPlus: true },
{ feature: 'Автоматизация ОС', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Частые вопросы.',
items: [
{ q: 'Нужно ли устанавливать Ollama и Whisper отдельно?', a: 'Whisper (faster-whisper) встроен в приложение \u2014 отдельная установка не нужна. Ollama требуется только для функций ИИ-корректировки/перевода и легко устанавливается через встроенное руководство. Базовая диктовка работает без Ollama.' },
{ q: 'Какая GPU нужна?', a: 'GPU не требуется \u2014 работает только на CPU. NVIDIA GPU (CUDA) ускоряет транскрипцию в 5-10 раз. С моделью base транскрипция в реальном времени на CPU возможна.' },
{ q: 'Работает ли полностью офлайн?', a: 'Да. После загрузки моделей Whisper и Ollama все работает без интернета. Проверка лицензии онлайн только при первой активации, затем 30 дней офлайн-льготного периода.' },
{ q: 'Насколько точно распознавание речи?', a: 'Whisper large-v3 обеспечивает отличную точность для более чем 99 языков. Функция пользовательского словаря дополнительно повышает точность для специализированной терминологии.' },
{ q: 'Это подписка?', a: 'Нет. Pro и Pro+ \u2014 разовые покупки. Заплатите один раз, пользуйтесь навсегда. Крупные обновления включены. Без расходов на облачные серверы нам не нужна модель подписки.' },
{ q: 'А macOS и Linux?', a: 'Пока только Windows. Построено на Electron, поддержка macOS/Linux технически возможна и планируется в зависимости от спроса.' },
],
},
cta: {
title1: 'Говорите.',
title2: 'ИИ пишет.',
subtitle1: 'Без облака. Без подписки. Без проблем с приватностью.',
subtitle2: 'Начните сейчас.',
downloadBtn: 'Скачать для Windows',
systemReq: 'Windows 10/11 \u00b7 64-бит \u00b7 ~200МБ \u00b7 Готово за секунды',
},
footer: {
description: 'Полностью локальный ИИ-голосовой ассистент. На базе Whisper и Ollama. Ваш голос, ваш компьютер, ваши данные.',
copyright: '\u00a9 {year} D3RO Voice. Все права защищены.',
builtWith: 'Создано с Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/vi.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const vi: Translations = {
nav: {
features: 'TINH NANG',
pipeline: 'QUY TRINH',
privacy: 'RIENG TU',
pricing: 'GIA CA',
faq: 'FAQ',
download: 'Tai xuong',
},
hero: {
badge: '100% CUC BO \u00b7 KHONG DAM MAY',
title1: 'TRO LY',
title2: 'GIONG NOI',
title3: 'AI CUC BO.',
subtitle: 'Duong ong chuyen giong noi thanh van ban voi Whisper + Ollama chay hoan toan tren may tinh cua ban. Chinh ta, tinh chinh AI, phu de truc tiep, hoi thoai giong noi \u2014 khong can internet.',
downloadBtn: 'Tai xuong cho Windows',
viewFeatures: 'Xem tinh nang',
dataProcessing: 'Xu ly',
dataCloudTraffic: 'Luu luong dam may',
dataLatency: 'Do tre STT',
dataPrivacy: 'Diem rieng tu',
systemStatus: 'TRANG THAI HE THONG: HOAT DONG',
protocol: 'GIAO THUC: 2025.04',
},
features: {
index: '01 / TINH NANG',
title: 'Tri tue giong noi toan dien.',
subtitle: 'Tu chinh ta den hoi thoai AI. Tat ca chay tren phan cung cua ban, ngoai tuyen.',
items: [
{ title: 'Chinh ta giong noi', description: 'Giu phim nong, noi, tha. Whisper phien am va chen van ban vao ung dung dang hoat dong ngay lap tuc.' },
{ title: 'Tinh chinh van ban AI', description: 'Ollama LLM tinh chinh van ban phien am thanh van xuoi sach, dung ngu phap. Trang trong hoac binh thuong.' },
{ title: 'Dich tuc thi', description: 'Noi bang mot ngon ngu, nhan van ban bang ngon ngu khac. Tu dong nhan dien nguon, dich tren thiet bi.' },
{ title: 'Phu de truc tiep', description: 'Lop phu de thoi gian thuc tren man hinh. Cuoc hop, bai giang, video. Tu dong xuat ghi chu cuoc hop.' },
{ title: 'Hoi thoai giong noi', description: 'Che do giong noi ChatGPT cuc bo. Vong lap STT-LLM-TTS day du cho hoi thoai AI tu nhien, hoan toan ngoai tuyen.' },
{ title: 'Phien am tap tin', description: 'Keo va tha tap tin am thanh hoac video. Whisper phien am toan bo noi dung voi moc thoi gian.' },
{ title: 'Chuoi da LLM', description: 'Ket noi nhieu lenh AI: phien am, dich, roi tom tat chi voi mot lan nhan phim.' },
{ title: 'Ngu canh man hinh', description: 'Tu dong chup ung dung dang hoat dong va van ban duoc chon. Noi "giai thich doan ma nay" va AI thay nhung gi ban thay.' },
{ title: 'Ghi chu giong noi', description: 'Ghi chu giong noi tu dong sap xep voi #the. Xuat ra markdown. Tim kiem, loc, phan loai.' },
],
},
pipeline: {
index: '02 / QUY TRINH',
title: 'Bon buoc. Hai giay.',
subtitle: 'Mot lan nhan phim nong va loi noi cua ban tro thanh van ban hoan chinh.',
steps: [
{ label: 'DAU VAO', title: 'Nhan phim nong', description: 'Giu Right Alt (hoac phim tuy chinh) de ghi am. Nhan doi cho che do AI. Chuyen doi cho che do ranh tay.', detail: 'Giu / Chuyen doi / Nhan doi' },
{ label: 'PHIEN AM', title: 'Whisper STT', description: 'Bo may faster-whisper cuc bo chuyen doi am thanh PCM 16kHz thanh van ban thoi gian thuc. Ho tro tang toc GPU.', detail: 'faster-whisper / base ~ large-v3' },
{ label: 'XU LY', title: 'Ollama LLM', description: 'LLM cuc bo sua ngu phap, dieu chinh giong dieu, dich hoac tom tat. Ho tro chi dan tuy chinh.', detail: 'qwen3 / llama3 / gemma3 / tuy chinh' },
{ label: 'DAU RA', title: 'Tu dong chen', description: 'Van ban da tinh chinh duoc dan vao vi tri con tro trong bat ky ung dung nao. Notepad, VS Code, Chrome, Slack, bat cu dau.', detail: 'Clipboard + Ctrl+V / 100ms do tre' },
],
panelTitle: 'D3RO Voice Pipeline',
panelActive: 'Hoat dong',
panelLatency: 'DO TRE: 1.2s',
sttReady: 'STT San sang',
llmConnected: 'LLM Da ket noi',
transcription: 'Phien am',
aiPolish: 'Tinh chinh AI',
sampleInput: 'Vui long tom tat ghi chu cuoc hop hom nay...',
sampleOutput: 'Vui long tom tat ghi chu cuoc hop hom nay.',
},
privacy: {
index: '03 / RIENG TU',
title: 'Giong noi cua ban khong bao gio roi di.',
subtitle: 'Moi byte am thanh, moi phien am, moi tuong tac AI deu o tren may tinh cua ban.',
monitorTitle: 'Giam sat rieng tu',
allClear: 'AN TOAN',
metrics: [
{ label: 'LUU LUONG DAM MAY', value: '0 BYTES' },
{ label: 'MA HOA DU LIEU', value: 'SQLite CUC BO' },
{ label: 'DO LUONG TU XA', value: 'TAT' },
{ label: 'YEU CAU MANG', value: 'KHONG' },
{ label: 'LUU TRU AM THANH', value: 'CHI CUC BO' },
{ label: 'MA NGUON MO', value: 'CO' },
],
guarantees: [
'Khong can internet sau khi tai mo hinh lan dau',
'Ban ghi giong noi chi luu trong SQLite cuc bo',
'Xoa tat ca du lieu bat ky luc nao chi voi mot click',
'Ma nguon mo - kiem tra tung dong ma',
'Khong tai khoan, khong dang ky, khong theo doi',
'Whisper va Ollama deu chay tren phan cung cua ban',
],
},
pricing: {
index: '04 / GIA CA',
title: 'Khong dang ky. Mai mai.',
subtitle: 'Khong dam may nghia la khong hoa don hang thang. Mua mot lan, dung ca doi.',
featureLabel: 'Tinh nang',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: 'mien phi mai mai',
oneTime: 'mot lan',
popular: 'Pho bien',
downloadFree: 'Tai mien phi',
getPro: 'Mua Pro',
getProPlus: 'Mua Pro+',
taxNote: 'Tat ca gia chua bao gom thue. Thanh toan an toan qua LemonSqueezy.',
rows: [
{ feature: 'Chinh ta giong noi', free: '15/ngay', pro: true, proPlus: true },
{ feature: 'Tinh chinh van ban AI', free: '3/ngay', pro: true, proPlus: true },
{ feature: 'Luu tru lich su', free: '3 ngay', pro: true, proPlus: true },
{ feature: 'Chi dan tuy chinh', free: 'Mac dinh', pro: true, proPlus: true },
{ feature: 'Phu de truc tiep', free: false, pro: true, proPlus: true },
{ feature: 'Ngu canh man hinh', free: false, pro: true, proPlus: true },
{ feature: 'Ghi chu giong noi + the', free: false, pro: true, proPlus: true },
{ feature: 'Chuoi da LLM', free: false, pro: true, proPlus: true },
{ feature: 'Lenh giong noi', free: false, pro: true, proPlus: true },
{ feature: 'Xuat lich su', free: false, pro: true, proPlus: true },
{ feature: 'Phien am tap tin', free: false, pro: false, proPlus: true },
{ feature: 'Hoi thoai giong noi', free: false, pro: false, proPlus: true },
{ feature: 'Tom tat cuoc hop', free: false, pro: false, proPlus: true },
{ feature: 'RAG cuc bo', free: false, pro: false, proPlus: true },
{ feature: 'Tu dong hoa OS', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / FAQ',
title: 'Cau hoi thuong gap.',
items: [
{ q: 'Toi co can cai dat Ollama va Whisper rieng khong?', a: 'Whisper (faster-whisper) da duoc tich hop trong ung dung - khong can cai dat rieng. Ollama chi can thiet cho tinh nang tinh chinh/dich AI va co the de dang cai dat qua huong dan trong ung dung. Chinh ta co ban hoat dong khong can Ollama.' },
{ q: 'Toi can GPU nao?', a: 'Khong can GPU - hoat dong chi voi CPU. GPU NVIDIA (CUDA) tang toc phien am 5-10 lan. Voi mo hinh base, phien am thoi gian thuc tren CPU la kha thi.' },
{ q: 'Co hoat dong hoan toan ngoai tuyen khong?', a: 'Co. Sau khi tai cac mo hinh Whisper va Ollama, moi thu hoat dong khong can internet. Xac minh giay phep chi truc tuyen khi kich hoat lan dau, sau do 30 ngay an han ngoai tuyen.' },
{ q: 'Do chinh xac nhan dien giong noi the nao?', a: 'Whisper large-v3 cung cap do chinh xac tuyet voi cho hon 99 ngon ngu. Tinh nang tu dien tuy chinh cai thien them do chinh xac cho thuat ngu chuyen nganh.' },
{ q: 'Day co phai dang ky khong?', a: 'Khong. Pro va Pro+ la mua mot lan. Tra mot lan, dung mai mai. Bao gom cac ban cap nhat lon. Khong co chi phi may chu dam may, chung toi khong can mo hinh dang ky.' },
{ q: 'Con macOS va Linux thi sao?', a: 'Hien tai chi ho tro Windows. Duoc xay dung tren Electron nen ho tro macOS/Linux la kha thi ve mat ky thuat va duoc len ke hoach theo nhu cau.' },
],
},
cta: {
title1: 'Noi.',
title2: 'AI viet.',
subtitle1: 'Khong dam may. Khong dang ky. Khong lo ngai ve quyen rieng tu.',
subtitle2: 'Bat dau ngay.',
downloadBtn: 'Tai xuong cho Windows',
systemReq: 'Windows 10/11 \u00b7 64-bit \u00b7 ~200MB \u00b7 San sang trong vai giay',
},
footer: {
description: 'Tro ly giong noi AI hoan toan cuc bo. Duoc ho tro boi Whisper va Ollama. Giong noi cua ban, may tinh cua ban, du lieu cua ban.',
copyright: '\u00a9 {year} D3RO Voice. Moi quyen duoc bao luu.',
builtWith: 'Duoc xay dung voi Electron + React + TypeScript',
},
}

144
site/src/i18n/locales/zh.ts Normal file
View file

@ -0,0 +1,144 @@
import type { Translations } from '../index'
export const zh: Translations = {
nav: {
features: '功能',
pipeline: '流程',
privacy: '隐私',
pricing: '价格',
faq: '常见问题',
download: '下载',
},
hero: {
badge: '100% 本地 \u00b7 零云端',
title1: '本地AI',
title2: '语音',
title3: '助手.',
subtitle: 'Whisper + Ollama 驱动的语音转文字流程完全在您的设备上运行。听写、AI润色、实时字幕、语音对话 \u2014 无需互联网。',
downloadBtn: '下载 Windows 版',
viewFeatures: '查看功能',
dataProcessing: '处理方式',
dataCloudTraffic: '云端流量',
dataLatency: 'STT 延迟',
dataPrivacy: '隐私评分',
systemStatus: '系统状态: 正常运行',
protocol: '协议: 2025.04',
},
features: {
index: '01 / 功能',
title: '完整的语音智能.',
subtitle: '从听写到AI对话一切都在您的硬件上离线运行。',
items: [
{ title: '语音听写', description: '按住快捷键说话松开。Whisper 即时转录并将文字插入到当前活动应用中。' },
{ title: 'AI文本润色', description: 'Ollama LLM 将转录文本润色为干净、语法正确的文字。支持正式和非正式风格。' },
{ title: '即时翻译', description: '用一种语言说话,获取另一种语言的文本。自动检测源语言,设备端翻译。' },
{ title: '实时字幕', description: '屏幕上的实时字幕叠加。适用于会议、讲座、视频。自动导出会议记录。' },
{ title: '语音对话', description: '本地 ChatGPT 语音模式。完整的 STT-LLM-TTS 循环完全离线的自然AI对话。' },
{ title: '文件转录', description: '拖放音频或视频文件。Whisper 将带时间戳转录全部内容。' },
{ title: '多LLM链', description: '串联多个AI命令转录、翻译、然后摘要一个快捷键完成。' },
{ title: '屏幕上下文', description: '自动捕获活动应用和选中文本。说"解释这段代码"AI就能看到您所看到的。' },
{ title: '语音备忘录', description: '带 #标签 的自动整理语音笔记。导出为 Markdown。搜索、筛选、分类。' },
],
},
pipeline: {
index: '02 / 流程',
title: '四步,两秒。',
subtitle: '按一下快捷键,语音即变为精炼文字。',
steps: [
{ label: '输入', title: '按下快捷键', description: '长按 Right Alt或自定义按键开始录音。双击进入AI模式。切换免提模式。', detail: '长按 / 切换 / 双击' },
{ label: '转录', title: 'Whisper STT', description: '本地 faster-whisper 引擎将 16kHz PCM 音频实时转换为文本。支持GPU加速。', detail: 'faster-whisper / base ~ large-v3' },
{ label: '处理', title: 'Ollama LLM', description: '本地 LLM 润色语法、调整语气、翻译或摘要。支持自定义指令。', detail: 'qwen3 / llama3 / gemma3 / 自定义' },
{ label: '输出', title: '自动插入', description: '润色后的文本自动粘贴到任何应用的光标位置。记事本、VS Code、Chrome、Slack任何地方。', detail: '剪贴板 + Ctrl+V / 100ms延迟' },
],
panelTitle: 'D3RO Voice 流程',
panelActive: '运行中',
panelLatency: '延迟: 1.2秒',
sttReady: 'STT 就绪',
llmConnected: 'LLM 已连接',
transcription: '转录',
aiPolish: 'AI润色',
sampleInput: '请帮我整理今天的会议记录...',
sampleOutput: '请整理今天的会议记录。',
},
privacy: {
index: '03 / 隐私',
title: '您的声音永远不会外泄.',
subtitle: '每一个字节的音频、每一次转录、每一次AI交互都留在您的设备上。',
monitorTitle: '隐私监控',
allClear: '全部正常',
metrics: [
{ label: '云端流量', value: '0 字节' },
{ label: '数据加密', value: '本地 SQLite' },
{ label: '遥测', value: '已禁用' },
{ label: '需要网络', value: '否' },
{ label: '音频存储', value: '仅本地' },
{ label: '开源', value: '是' },
],
guarantees: [
'初次模型下载后无需互联网',
'语音录制仅存储在本地 SQLite',
'一键即可随时删除所有数据',
'开源 - 可检查每一行代码',
'无需账号、无需注册、无跟踪',
'Whisper 和 Ollama 均在您的硬件上运行',
],
},
pricing: {
index: '04 / 价格',
title: '永不订阅.',
subtitle: '没有云端意味着没有月费。一次购买,终身使用。',
featureLabel: '功能',
free: 'Free',
pro: 'Pro',
proPlus: 'Pro+',
forever: '永久免费',
oneTime: '一次性',
popular: '热门',
downloadFree: '免费下载',
getPro: '获取 Pro',
getProPlus: '获取 Pro+',
taxNote: '所有价格不含税。通过 LemonSqueezy 安全支付。',
rows: [
{ feature: '语音听写', free: '15次/天', pro: true, proPlus: true },
{ feature: 'AI文本润色', free: '3次/天', pro: true, proPlus: true },
{ feature: '历史保留', free: '3天', pro: true, proPlus: true },
{ feature: '自定义指令', free: '预设', pro: true, proPlus: true },
{ feature: '实时字幕', free: false, pro: true, proPlus: true },
{ feature: '屏幕上下文', free: false, pro: true, proPlus: true },
{ feature: '语音备忘录 + 标签', free: false, pro: true, proPlus: true },
{ feature: '多LLM链', free: false, pro: true, proPlus: true },
{ feature: '语音命令', free: false, pro: true, proPlus: true },
{ feature: '历史导出', free: false, pro: true, proPlus: true },
{ feature: '文件转录', free: false, pro: false, proPlus: true },
{ feature: '语音对话', free: false, pro: false, proPlus: true },
{ feature: '会议摘要', free: false, pro: false, proPlus: true },
{ feature: '本地 RAG', free: false, pro: false, proPlus: true },
{ feature: 'OS 自动化', free: false, pro: false, proPlus: true },
],
},
faq: {
index: '05 / 常见问题',
title: '常见问题.',
items: [
{ q: '需要单独安装 Ollama 和 Whisper 吗?', a: 'Whisperfaster-whisper已内置于应用中无需单独安装。Ollama 仅用于 AI 润色/翻译功能,可通过应用内引导轻松安装。基础听写无需 Ollama 即可使用。' },
{ q: '需要什么 GPU', a: '无需 GPU - 仅用 CPU 即可运行。NVIDIA GPUCUDA可将转录速度提升 5-10 倍。使用 base 模型时CPU 实时转录完全可行。' },
{ q: '能完全离线工作吗?', a: '是的。下载 Whisper 和 Ollama 模型后,一切都可以在没有互联网的情况下运行。许可证验证仅在首次激活时需要在线,之后有 30 天的离线宽限期。' },
{ q: '语音识别准确率如何?', a: 'Whisper large-v3 支持 99 种以上语言,准确率极高。自定义词典功能可进一步提升专业术语的识别精度。' },
{ q: '这是订阅制吗?', a: '不是。Pro 和 Pro+ 为一次性购买。买一次,终身使用。包含重大更新。由于没有云服务器成本,我们不需要订阅模式。' },
{ q: '支持 macOS 和 Linux 吗?', a: '目前仅支持 Windows。基于 Electron 构建macOS/Linux 支持在技术上可行,将根据需求推出。' },
],
},
cta: {
title1: '开口说。',
title2: 'AI来写。',
subtitle1: '无云端。无订阅。无隐私顾虑。',
subtitle2: '立即开始。',
downloadBtn: '下载 Windows 版',
systemReq: 'Windows 10/11 \u00b7 64位 \u00b7 约200MB \u00b7 几秒即可就绪',
},
footer: {
description: '完全本地的 AI 语音助手。由 Whisper 和 Ollama 驱动。您的声音,您的设备,您的数据。',
copyright: '\u00a9 {year} D3RO Voice. All rights reserved.',
builtWith: '使用 Electron + React + TypeScript 构建',
},
}

207
site/src/index.css Normal file
View file

@ -0,0 +1,207 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* ── Base Reset & Globals ──────────────────────────────── */
@layer base {
html {
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
::selection {
background-color: rgba(242, 91, 41, 0.3);
color: #fafafa;
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: #0d0d0f;
}
::-webkit-scrollbar-thumb {
background: #333338;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #4a4b50;
}
body {
overflow-x: hidden;
}
}
/* ── Grid Background Pattern ──────────────────────────── */
.bg-grid {
background-image:
linear-gradient(rgba(242, 91, 41, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(242, 91, 41, 0.03) 1px, transparent 1px);
background-size: 60px 60px;
}
.bg-grid-dense {
background-image:
linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
background-size: 20px 20px;
}
/* ── CRT Screen Effect (CSS only) ─────────────────────── */
.crt-screen {
position: relative;
overflow: hidden;
background: linear-gradient(180deg, #050605 0%, #0a0b0a 100%);
border: 1px solid rgba(242, 91, 41, 0.1);
box-shadow:
inset 0 2px 8px rgba(0, 0, 0, 0.8),
0 0 30px rgba(242, 91, 41, 0.05);
}
.crt-screen::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.15) 2px,
rgba(0, 0, 0, 0.15) 4px
);
pointer-events: none;
z-index: 2;
}
.crt-screen::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
180deg,
rgba(242, 91, 41, 0.02) 0%,
transparent 50%,
rgba(242, 91, 41, 0.01) 100%
);
animation: scan 8s linear infinite;
pointer-events: none;
z-index: 3;
}
@keyframes scan {
0% { transform: translateY(-100%); }
100% { transform: translateY(100%); }
}
/* ── Crosshair Decorations ─────────────────────────────── */
.crosshair-box {
--ch-size: 16px;
--ch-color: rgba(242, 91, 41, 0.35);
position: relative;
}
.crosshair-box::before {
content: '';
position: absolute;
top: -1px;
left: -1px;
width: var(--ch-size);
height: var(--ch-size);
border-top: 1px solid var(--ch-color);
border-left: 1px solid var(--ch-color);
pointer-events: none;
}
.crosshair-box::after {
content: '';
position: absolute;
bottom: -1px;
right: -1px;
width: var(--ch-size);
height: var(--ch-size);
border-bottom: 1px solid var(--ch-color);
border-right: 1px solid var(--ch-color);
pointer-events: none;
}
/* ── Instrument Noise Texture ──────────────────────────── */
.noise-texture {
position: relative;
}
.noise-texture::before {
content: '';
position: absolute;
inset: 0;
opacity: 0.025;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 256px 256px;
pointer-events: none;
border-radius: inherit;
}
/* ── Glow Button ───────────────────────────────────────── */
.glow-btn {
position: relative;
overflow: hidden;
transition: all 250ms cubic-bezier(0.16, 1, 0.3, 1);
}
.glow-btn::before {
content: '';
position: absolute;
inset: -2px;
background: linear-gradient(135deg, rgba(242, 91, 41, 0.4), rgba(242, 91, 41, 0) 60%);
border-radius: inherit;
opacity: 0;
transition: opacity 250ms;
z-index: 0;
}
.glow-btn:hover::before {
opacity: 1;
}
.glow-btn:hover {
box-shadow: 0 0 20px rgba(242, 91, 41, 0.3), 0 0 40px rgba(242, 91, 41, 0.1);
transform: translateY(-1px);
}
.glow-btn:active {
transform: translateY(0);
}
/* ── Accordion ─────────────────────────────────────────── */
.accordion-content {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 300ms ease;
}
.accordion-content.open {
grid-template-rows: 1fr;
}
.accordion-content > div {
overflow: hidden;
}
/* ── Reveal Animation ──────────────────────────────────── */
.reveal {
opacity: 0;
transform: translateY(20px);
}
.reveal.visible {
animation: fade-in-up 0.6s ease-out forwards;
}
@keyframes fade-in-up {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); }
}
/* ── Utilities ─────────────────────────────────────────── */
@layer utilities {
.text-balance {
text-wrap: balance;
}
.border-hairline {
border-color: rgba(255, 255, 255, 0.06);
}
}

10
site/src/main.tsx Normal file
View file

@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { App } from './App'
import './index.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)

40
site/src/sections/CTA.tsx Normal file
View file

@ -0,0 +1,40 @@
import { Container } from '../components/Container'
import { Crosshair } from '../components/Crosshair'
import { WaveBars } from '../components/WaveBars'
import { GlowButton } from '../components/GlowButton'
import { useI18n } from '../i18n'
export function CTA() {
const { t } = useI18n()
return (
<section className="relative py-24 md:py-32">
{/* Background glow */}
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[400px] bg-brand-amber/[0.03] rounded-full blur-[120px] pointer-events-none" />
<Container className="relative text-center">
<Crosshair className="inline-block mb-8">
<WaveBars className="h-8 px-2" />
</Crosshair>
<h2 className="font-display text-display font-bold text-neutral-50 mb-6 max-w-3xl mx-auto">
{t.cta.title1} <span className="text-brand-amber">{t.cta.title2}</span>
</h2>
<p className="text-base md:text-lg text-neutral-400 max-w-xl mx-auto mb-10 leading-relaxed">
{t.cta.subtitle1}
<br />
{t.cta.subtitle2}
</p>
<GlowButton href="https://github.com/user/D3ROVoice/releases" variant="primary" size="lg">
{t.cta.downloadBtn}
</GlowButton>
<p className="font-mono text-nano text-neutral-600 mt-8 uppercase tracking-widest">
{t.cta.systemReq}
</p>
</Container>
</section>
)
}

68
site/src/sections/FAQ.tsx Normal file
View file

@ -0,0 +1,68 @@
import { useState } from 'react'
import { SectionHeader } from '../components/SectionHeader'
import { Container } from '../components/Container'
import { useI18n } from '../i18n'
export function FAQ() {
const { t } = useI18n()
const [openIndex, setOpenIndex] = useState<number | null>(null)
return (
<section id="faq" className="relative py-24 md:py-32">
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-surface-800/30 to-transparent pointer-events-none" />
<Container className="relative max-w-3xl">
<SectionHeader
index={t.faq.index}
title={t.faq.title}
/>
<div className="space-y-px">
{t.faq.items.map((faq, i) => {
const isOpen = openIndex === i
return (
<div
key={i}
className="border-b border-white/[0.04]"
>
<button
onClick={() => setOpenIndex(isOpen ? null : i)}
className="w-full flex items-start justify-between gap-4 py-5 text-left group"
>
<div className="flex items-start gap-4">
<span className="font-mono text-nano text-neutral-600 mt-1 flex-shrink-0">
{String(i + 1).padStart(2, '0')}
</span>
<span className="text-sm font-medium text-neutral-200 group-hover:text-white transition-colors">
{faq.q}
</span>
</div>
<svg
className={`w-4 h-4 text-neutral-500 flex-shrink-0 mt-1 transition-transform duration-200 ${
isOpen ? 'rotate-45' : ''
}`}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
>
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
</button>
<div className={`accordion-content ${isOpen ? 'open' : ''}`}>
<div>
<p className="pl-10 pb-5 text-sm text-neutral-400 leading-relaxed">
{faq.a}
</p>
</div>
</div>
</div>
)
})}
</div>
</Container>
</section>
)
}

View file

@ -0,0 +1,166 @@
import type { ReactNode } from 'react'
import { SectionHeader } from '../components/SectionHeader'
import { InstrumentCard } from '../components/InstrumentCard'
import { Container } from '../components/Container'
import { useI18n } from '../i18n'
interface FeatureMeta {
icon: ReactNode
tag: 'FREE' | 'PRO' | 'PRO+'
}
const featureMeta: FeatureMeta[] = [
{ icon: <MicIcon />, tag: 'FREE' },
{ icon: <SparklesIcon />, tag: 'FREE' },
{ icon: <LanguageIcon />, tag: 'FREE' },
{ icon: <CaptionIcon />, tag: 'PRO' },
{ icon: <ConversationIcon />, tag: 'PRO+' },
{ icon: <FileIcon />, tag: 'PRO+' },
{ icon: <ChainIcon />, tag: 'PRO' },
{ icon: <ContextIcon />, tag: 'PRO' },
{ icon: <MemoIcon />, tag: 'PRO' },
]
const tagStyles = {
FREE: 'text-emerald-400 bg-emerald-500/10 border-emerald-500/20',
PRO: 'text-brand-amber bg-brand-amber/10 border-brand-amber/20',
'PRO+': 'text-violet-400 bg-violet-500/10 border-violet-500/20',
} as const
export function Features() {
const { t } = useI18n()
return (
<section id="features" className="relative py-24 md:py-32">
<Container>
<SectionHeader
index={t.features.index}
title={t.features.title}
subtitle={t.features.subtitle}
/>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{t.features.items.map((item, i) => {
const meta = featureMeta[i]
return (
<InstrumentCard key={i}>
{/* Top row: icon + tag */}
<div className="flex items-start justify-between mb-6">
<div className="w-10 h-10 rounded-card bg-surface-400 border border-white/[0.06] flex items-center justify-center text-brand-amber">
{meta.icon}
</div>
<span className={`text-nano font-mono font-semibold tracking-widest uppercase px-2 py-0.5 border rounded-sm ${tagStyles[meta.tag]}`}>
{meta.tag}
</span>
</div>
{/* Content */}
<h3 className="font-display text-lg font-semibold text-neutral-100 mb-2">
{item.title}
</h3>
<p className="text-sm text-neutral-400 leading-relaxed">
{item.description}
</p>
{/* Bottom arrow */}
<div className="mt-5 flex justify-end">
<div className="w-7 h-7 rounded-full border border-white/[0.06] flex items-center justify-center text-neutral-500 group-hover:text-brand-amber group-hover:border-brand-amber/20 transition-colors">
<svg className="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="7" y1="17" x2="17" y2="7" />
<polyline points="7 7 17 7 17 17" />
</svg>
</div>
</div>
</InstrumentCard>
)
})}
</div>
</Container>
</section>
)
}
/* ── Inline SVG Icons ─────────────────────────────────── */
function MicIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect x="9" y="2" width="6" height="11" rx="3" />
<path d="M5 10a7 7 0 0 0 14 0" />
<line x1="12" y1="17" x2="12" y2="21" />
</svg>
)
}
function SparklesIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 2l2.4 7.2L22 12l-7.6 2.8L12 22l-2.4-7.2L2 12l7.6-2.8z" />
</svg>
)
}
function LanguageIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M5 8l6 6" /><path d="M4 14l6-6 2-3" /><path d="M2 5h12" /><path d="M7 2h1" />
<path d="M22 22l-5-10-5 10" /><path d="M14 18h6" />
</svg>
)
}
function CaptionIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect x="2" y="4" width="20" height="16" rx="2" />
<path d="M7 15h4" /><path d="M13 15h4" /><path d="M7 11h10" />
</svg>
)
}
function ConversationIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
</svg>
)
}
function FileIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
)
}
function ChainIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
</svg>
)
}
function ContextIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2" />
<line x1="8" y1="21" x2="16" y2="21" />
<line x1="12" y1="17" x2="12" y2="21" />
</svg>
)
}
function MemoIcon() {
return (
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
<line x1="16" y1="13" x2="8" y2="13" />
<line x1="16" y1="17" x2="8" y2="17" />
</svg>
)
}

View file

@ -0,0 +1,80 @@
import { Container } from '../components/Container'
import { Led } from '../components/Led'
import { useI18n } from '../i18n'
const techStack = [
'Electron', 'React 19', 'faster-whisper', 'Ollama',
'better-sqlite3', 'TypeScript', 'uiohook-napi',
]
export function Footer() {
const { t } = useI18n()
return (
<footer className="border-t border-white/[0.04] py-12 md:py-16">
<Container>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12">
{/* Left: brand */}
<div>
<div className="flex items-center gap-2 mb-3">
<Led color="amber" size="sm" />
<span className="font-mono text-sm font-semibold tracking-tight text-neutral-300">
D3RO&middot;VOICE
</span>
</div>
<p className="text-sm text-neutral-500 leading-relaxed max-w-sm">
{t.footer.description}
</p>
</div>
{/* Right: links */}
<div className="flex flex-wrap gap-x-8 gap-y-3 md:justify-end">
<a href="https://github.com/user/D3ROVoice" className="font-mono text-nano uppercase tracking-widest text-neutral-500 hover:text-neutral-300 transition-colors flex items-center gap-1.5">
<GithubIcon />
GitHub
</a>
<a href="#features" className="font-mono text-nano uppercase tracking-widest text-neutral-500 hover:text-neutral-300 transition-colors">
{t.nav.features}
</a>
<a href="#pricing" className="font-mono text-nano uppercase tracking-widest text-neutral-500 hover:text-neutral-300 transition-colors">
{t.nav.pricing}
</a>
<a href="#faq" className="font-mono text-nano uppercase tracking-widest text-neutral-500 hover:text-neutral-300 transition-colors">
{t.nav.faq}
</a>
</div>
</div>
{/* Tech stack bar */}
<div className="flex flex-wrap items-center gap-2 mb-8">
{techStack.map((tech) => (
<span
key={tech}
className="font-mono text-nano uppercase tracking-widest text-neutral-600 bg-surface-700/50 px-2.5 py-1 rounded-sm border border-white/[0.03]"
>
{tech}
</span>
))}
</div>
{/* Bottom bar */}
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 pt-6 border-t border-white/[0.04]">
<span className="font-mono text-nano text-neutral-600 uppercase tracking-widest">
{t.footer.copyright.replace('{year}', String(new Date().getFullYear()))}
</span>
<span className="font-mono text-nano text-neutral-600 uppercase tracking-widest">
{t.footer.builtWith}
</span>
</div>
</Container>
</footer>
)
}
function GithubIcon() {
return (
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
)
}

View file

@ -0,0 +1,96 @@
import { useState, useEffect } from 'react'
import { Led } from '../components/Led'
import { LanguageSwitcher } from '../components/LanguageSwitcher'
import { navItems } from '../tokens'
import { useI18n } from '../i18n'
export function Header() {
const { t } = useI18n()
const [scrolled, setScrolled] = useState(false)
const [mobileOpen, setMobileOpen] = useState(false)
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 40)
window.addEventListener('scroll', onScroll, { passive: true })
return () => window.removeEventListener('scroll', onScroll)
}, [])
return (
<header
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 mix-blend-difference ${
scrolled ? 'backdrop-blur-xl' : ''
}`}
>
<div className="mx-auto max-w-7xl px-5 md:px-8 lg:px-12 h-16 flex items-center justify-between">
{/* Logo */}
<a href="#" className="flex items-center gap-2 group">
<Led color="amber" pulse size="md" />
<span className="font-mono text-sm font-semibold tracking-tight text-white">
D3RO<span className="text-neutral-400">&middot;</span>VOICE
</span>
</a>
{/* Desktop Nav */}
<nav className="hidden md:flex items-center gap-8">
{navItems.map((link) => (
<a
key={link.href}
href={link.href}
className="font-mono text-nano uppercase tracking-widest text-neutral-400 hover:text-white transition-colors"
>
{t.nav[link.key]}
</a>
))}
</nav>
{/* Right side: language + CTA */}
<div className="hidden md:flex items-center gap-3">
<LanguageSwitcher />
<a
href="https://github.com/user/D3ROVoice/releases"
className="inline-flex items-center gap-2 px-4 py-2 font-mono text-xs uppercase tracking-wider text-white bg-brand-amber/90 rounded-panel hover:bg-brand-amber transition-colors"
>
{t.nav.download}
</a>
</div>
{/* Mobile menu button */}
<button
onClick={() => setMobileOpen(!mobileOpen)}
className="md:hidden w-9 h-9 flex items-center justify-center"
aria-label="Menu"
>
<div className="space-y-1.5">
<span className={`block w-5 h-px bg-white transition-all ${mobileOpen ? 'rotate-45 translate-y-[3.5px]' : ''}`} />
<span className={`block w-5 h-px bg-white transition-all ${mobileOpen ? '-rotate-45 -translate-y-[3.5px]' : ''}`} />
</div>
</button>
</div>
{/* Mobile Nav */}
{mobileOpen && (
<div className="md:hidden bg-surface-900/95 backdrop-blur-xl border-t border-white/[0.06] px-5 py-6 space-y-1">
{navItems.map((link) => (
<a
key={link.href}
href={link.href}
onClick={() => setMobileOpen(false)}
className="block font-mono text-xs uppercase tracking-widest text-neutral-400 hover:text-brand-amber py-3 border-b border-white/[0.03]"
>
{t.nav[link.key]}
</a>
))}
<div className="flex items-center justify-between mt-4 gap-3">
<LanguageSwitcher />
<a
href="https://github.com/user/D3ROVoice/releases"
className="flex-1 text-center px-5 py-2.5 font-mono text-xs uppercase tracking-wider text-white bg-brand-amber rounded-panel"
>
{t.nav.download}
</a>
</div>
</div>
)}
</header>
)
}

100
site/src/sections/Hero.tsx Normal file
View file

@ -0,0 +1,100 @@
import { Badge } from '../components/Badge'
import { Crosshair } from '../components/Crosshair'
import { DataPoint } from '../components/DataPoint'
import { Container } from '../components/Container'
import { useI18n } from '../i18n'
const CJK_LOCALES = new Set(['ko', 'ja', 'zh'])
export function Hero() {
const { t, locale } = useI18n()
const isCJK = CJK_LOCALES.has(locale)
return (
<section className="relative min-h-screen flex flex-col justify-center overflow-hidden bg-grid pt-16 pb-12">
{/* Background effects */}
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/3 left-1/2 -translate-x-1/2 w-[700px] h-[700px] rounded-full bg-brand-amber/[0.025] blur-[140px]" />
<div className="absolute bottom-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-brand-amber/15 to-transparent" />
</div>
<Container className="relative flex-1 flex flex-col justify-center">
{/* Meta corners */}
<div className="hidden lg:block absolute top-8 left-5 md:left-8 lg:left-12">
<Badge led ledColor="green">{t.hero.systemStatus}</Badge>
</div>
<div className="hidden lg:block absolute top-8 right-5 md:right-8 lg:right-12 font-mono text-nano uppercase tracking-widest text-neutral-500">
{t.hero.protocol}
</div>
{/* Main hero content */}
<div className="max-w-5xl pt-12 md:pt-0">
<Crosshair className="inline-block mb-8">
<Badge led>{t.hero.badge}</Badge>
</Crosshair>
<h1
className="font-display text-hero font-bold text-neutral-50 mb-6 max-w-4xl"
style={isCJK ? { lineHeight: 1.15 } : undefined}
>
<span className="block">{t.hero.title1}</span>
<span className="block">{t.hero.title2}</span>
<span className="block text-brand-amber">{t.hero.title3}</span>
</h1>
<p className="max-w-xl text-base md:text-lg text-neutral-400 leading-relaxed mb-10">
{t.hero.subtitle}
</p>
<div className="flex flex-col sm:flex-row items-start gap-4 mb-16">
<a
href="https://github.com/user/D3ROVoice/releases"
className="glow-btn inline-flex items-center gap-2 px-8 py-4 font-mono text-sm font-medium uppercase tracking-wider text-white bg-brand-amber rounded-panel"
>
<span className="relative z-10 flex items-center gap-2">
<DownloadIcon />
{t.hero.downloadBtn}
</span>
</a>
<a
href="#features"
className="inline-flex items-center gap-2 px-8 py-4 font-mono text-sm uppercase tracking-wider text-neutral-400 border border-white/[0.08] rounded-panel hover:border-white/[0.15] hover:text-neutral-200 transition-all"
>
{t.hero.viewFeatures}
<ArrowIcon />
</a>
</div>
</div>
{/* Data strip */}
<div className="border-t border-white/[0.06] pt-8 mt-auto">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
<DataPoint label={t.hero.dataProcessing} value="100%" unit="local" />
<DataPoint label={t.hero.dataCloudTraffic} value="0" unit="bytes" />
<DataPoint label={t.hero.dataLatency} value="<2s" />
<DataPoint label={t.hero.dataPrivacy} value="10/10" />
</div>
</div>
</Container>
</section>
)
}
function DownloadIcon() {
return (
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" />
</svg>
)
}
function ArrowIcon() {
return (
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="7" y1="17" x2="17" y2="7" />
<polyline points="7 7 17 7 17 17" />
</svg>
)
}

View file

@ -0,0 +1,112 @@
import { SectionHeader } from '../components/SectionHeader'
import { Crosshair } from '../components/Crosshair'
import { Container } from '../components/Container'
import { Led } from '../components/Led'
import { WaveBars } from '../components/WaveBars'
import { useI18n } from '../i18n'
export function HowItWorks() {
const { t } = useI18n()
return (
<section id="pipeline" className="relative py-24 md:py-32">
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-surface-800/40 to-transparent pointer-events-none" />
<Container className="relative">
<SectionHeader
index={t.pipeline.index}
title={t.pipeline.title}
subtitle={t.pipeline.subtitle}
/>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 lg:gap-16 items-start">
{/* Left: visual panel */}
<Crosshair className="order-2 lg:order-1">
<div className="crt-screen rounded-card p-6 md:p-8 aspect-[4/3] flex flex-col justify-between">
<div className="relative z-10 flex items-center justify-between mb-6">
<span className="font-mono text-nano uppercase tracking-widest text-brand-amber/60">
{t.pipeline.panelTitle}
</span>
<div className="flex items-center gap-2">
<Led color="green" />
<span className="font-mono text-nano uppercase tracking-widest text-neutral-500">{t.pipeline.panelActive}</span>
</div>
</div>
<div className="relative z-10 flex-1 flex flex-col justify-center space-y-4">
{/* Simulated terminal output */}
<div className="font-mono text-xs text-neutral-500 leading-relaxed space-y-2">
<div className="flex items-center gap-2">
<Led color="green" size="sm" />
<span className="text-emerald-400/70">{t.pipeline.sttReady}</span>
<span className="text-neutral-600">faster-whisper base</span>
</div>
<div className="flex items-center gap-2">
<Led color="green" size="sm" />
<span className="text-emerald-400/70">{t.pipeline.llmConnected}</span>
<span className="text-neutral-600">qwen3:4b @ localhost:11434</span>
</div>
<div className="h-px bg-white/[0.04] my-3" />
<div className="flex items-start gap-2">
<Led color="amber" size="sm" pulse className="mt-1" />
<div>
<span className="text-brand-amber/50 block mb-1">{t.pipeline.transcription}</span>
<span className="text-neutral-300">&quot;{t.pipeline.sampleInput}&quot;</span>
</div>
</div>
<div className="flex items-start gap-2">
<Led color="green" size="sm" className="mt-1" />
<div>
<span className="text-emerald-400/50 block mb-1">{t.pipeline.aiPolish}</span>
<span className="text-neutral-300">&quot;{t.pipeline.sampleOutput}&quot;</span>
</div>
</div>
</div>
</div>
<div className="relative z-10 flex items-center justify-between pt-4 border-t border-white/[0.04]">
<WaveBars className="h-6" />
<span className="font-mono text-nano text-neutral-600">{t.pipeline.panelLatency}</span>
</div>
</div>
</Crosshair>
{/* Right: numbered steps */}
<div className="order-1 lg:order-2 space-y-1">
{t.pipeline.steps.map((step, i) => (
<div
key={i}
className="group relative flex gap-5 p-5 rounded-card border border-transparent hover:border-white/[0.04] hover:bg-surface-700/30 transition-all"
>
{/* Number */}
<div className="flex-shrink-0 w-12 h-12 rounded-card bg-surface-600 border border-white/[0.06] flex items-center justify-center">
<span className="font-mono text-lg font-bold text-brand-amber">{String(i + 1).padStart(2, '0')}</span>
</div>
<div className="flex-1 min-w-0">
<span className="font-mono text-nano uppercase tracking-widest text-brand-amber/60 block mb-1">
{step.label}
</span>
<h3 className="font-display text-lg font-semibold text-neutral-100 mb-1.5">
{step.title}
</h3>
<p className="text-sm text-neutral-400 leading-relaxed mb-2">
{step.description}
</p>
<span className="inline-block font-mono text-nano text-neutral-600 bg-surface-600/60 px-2.5 py-1 rounded-sm border border-white/[0.03]">
{step.detail}
</span>
</div>
{/* Connector */}
{i < t.pipeline.steps.length - 1 && (
<div className="absolute left-[42px] top-[72px] w-px h-5 bg-gradient-to-b from-surface-300 to-transparent hidden lg:block" />
)}
</div>
))}
</div>
</div>
</Container>
</section>
)
}

View file

@ -0,0 +1,120 @@
import { SectionHeader } from '../components/SectionHeader'
import { Container } from '../components/Container'
import { GlowButton } from '../components/GlowButton'
import { useI18n } from '../i18n'
function CellValue({ value }: { value: string | boolean }) {
if (value === true) {
return (
<span className="flex items-center justify-center">
<span className="w-2 h-2 rounded-full bg-emerald-400 shadow-[0_0_4px_rgba(52,211,153,0.6)]" />
</span>
)
}
if (value === false) {
return (
<span className="flex items-center justify-center">
<span className="w-2 h-2 rounded-full bg-neutral-600" />
</span>
)
}
return <span className="font-mono text-xs text-neutral-300">{value}</span>
}
export function Pricing() {
const { t } = useI18n()
return (
<section id="pricing" className="relative py-24 md:py-32">
<Container>
<SectionHeader
index={t.pricing.index}
title={t.pricing.title}
subtitle={t.pricing.subtitle}
/>
{/* Pricing table */}
<div className="overflow-x-auto -mx-5 md:mx-0">
<table className="w-full min-w-[640px] border-collapse">
{/* Header */}
<thead>
<tr className="border-b border-white/[0.08]">
<th className="text-left py-4 px-4 font-mono text-nano uppercase tracking-widest text-neutral-500 w-[40%]">
{t.pricing.featureLabel}
</th>
<th className="text-center py-4 px-4 w-[20%]">
<div className="font-mono text-nano uppercase tracking-widest text-neutral-500 mb-1">{t.pricing.free}</div>
<div className="font-display text-xl font-bold text-neutral-300">$0</div>
<div className="font-mono text-nano text-neutral-600">{t.pricing.forever}</div>
</th>
<th className="text-center py-4 px-4 w-[20%] relative">
<div className="absolute inset-x-0 -top-3 flex justify-center">
<span className="px-3 py-0.5 rounded-full bg-brand-amber text-white text-nano font-mono font-semibold uppercase tracking-widest">
{t.pricing.popular}
</span>
</div>
<div className="font-mono text-nano uppercase tracking-widest text-brand-amber mt-4 mb-1">{t.pricing.pro}</div>
<div className="font-display text-xl font-bold text-neutral-100">$29</div>
<div className="font-mono text-nano text-neutral-600">{t.pricing.oneTime}</div>
</th>
<th className="text-center py-4 px-4 w-[20%]">
<div className="font-mono text-nano uppercase tracking-widest text-neutral-500 mb-1">{t.pricing.proPlus}</div>
<div className="font-display text-xl font-bold text-neutral-300">$49</div>
<div className="font-mono text-nano text-neutral-600">{t.pricing.oneTime}</div>
</th>
</tr>
</thead>
{/* Body */}
<tbody>
{t.pricing.rows.map((row, i) => (
<tr
key={i}
className={`border-b border-white/[0.03] hover:bg-surface-700/30 transition-colors ${
i % 2 === 0 ? 'bg-transparent' : 'bg-surface-800/20'
}`}
>
<td className="py-3 px-4 font-mono text-xs text-neutral-400">
{row.feature}
</td>
<td className="py-3 px-4 text-center">
<CellValue value={row.free} />
</td>
<td className="py-3 px-4 text-center bg-brand-amber-muted/30">
<CellValue value={row.pro} />
</td>
<td className="py-3 px-4 text-center">
<CellValue value={row.proPlus} />
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* CTA row */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-8">
<div className="flex justify-center">
<GlowButton href="https://github.com/user/D3ROVoice/releases" variant="secondary" size="md">
{t.pricing.downloadFree}
</GlowButton>
</div>
<div className="flex justify-center">
<GlowButton href="#" variant="primary" size="md">
{t.pricing.getPro}
</GlowButton>
</div>
<div className="flex justify-center">
<GlowButton href="#" variant="secondary" size="md">
{t.pricing.getProPlus}
</GlowButton>
</div>
</div>
<p className="text-center font-mono text-nano text-neutral-600 mt-6 uppercase tracking-widest">
{t.pricing.taxNote}
</p>
</Container>
</section>
)
}

View file

@ -0,0 +1,76 @@
import { SectionHeader } from '../components/SectionHeader'
import { Container } from '../components/Container'
import { Led } from '../components/Led'
import { useI18n } from '../i18n'
const ledColors: Array<'amber' | 'green' | 'red'> = [
'green', 'green', 'green', 'green', 'green', 'green',
]
export function Privacy() {
const { t } = useI18n()
return (
<section id="privacy" className="relative py-24 md:py-32 overflow-hidden">
<Container>
<SectionHeader
index={t.privacy.index}
title={t.privacy.title}
subtitle={t.privacy.subtitle}
/>
{/* CRT instrument panel */}
<div className="crt-screen rounded-card p-6 md:p-10 noise-texture mb-12">
<div className="relative z-10">
{/* Panel header */}
<div className="flex items-center justify-between mb-8 pb-4 border-b border-white/[0.04]">
<span className="font-mono text-nano uppercase tracking-widest text-brand-amber/60">
{t.privacy.monitorTitle}
</span>
<div className="flex items-center gap-2">
<Led color="green" pulse />
<span className="font-mono text-nano uppercase tracking-widest text-emerald-400/60">
{t.privacy.allClear}
</span>
</div>
</div>
{/* Metric grid */}
<div className="grid grid-cols-2 md:grid-cols-3 gap-6 md:gap-8">
{t.privacy.metrics.map((metric, i) => (
<div key={i} className="flex flex-col gap-2">
<span className="font-mono text-nano uppercase tracking-widest text-neutral-500">
{metric.label}
</span>
<div className="flex items-center gap-2">
<Led color={ledColors[i]} size="sm" />
<span className="font-mono text-sm font-semibold text-neutral-200 tracking-wide">
{metric.value}
</span>
</div>
</div>
))}
</div>
</div>
</div>
{/* Guarantees list */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{t.privacy.guarantees.map((item, i) => (
<div
key={i}
className="flex items-start gap-3 p-4 rounded-card bg-surface-700/30 border border-white/[0.03]"
>
<div className="w-5 h-5 rounded-full bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center flex-shrink-0 mt-0.5">
<svg className="w-3 h-3 text-emerald-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
</div>
<span className="text-sm text-neutral-300 leading-relaxed">{item}</span>
</div>
))}
</div>
</Container>
</section>
)
}

109
site/src/tokens.ts Normal file
View file

@ -0,0 +1,109 @@
/**
* D3RO Voice Landing Page - Centralized Design Tokens
*
* All visual constants live here. Components reference these tokens
* instead of hardcoding colors, spacing, or typography values.
*
* Tailwind classes map to these same values via tailwind.config.js.
* Use tokens when building inline styles or JS-driven visuals.
*/
// ── Colors ──────────────────────────────────────────────
export const color = {
brand: {
amber: '#f25b29',
amberLight: '#ff7a4d',
amberDark: '#c44a22',
amberGlow: 'rgba(242,91,41,0.6)',
amberDim: 'rgba(242,91,41,0.15)',
amberMuted: 'rgba(242,91,41,0.08)',
},
surface: {
950: '#0a0a0c',
900: '#0d0d0f',
800: '#131315',
700: '#19191b',
600: '#1e1f21',
500: '#242427',
400: '#2a2a2d',
300: '#333338',
200: '#3a3b3f',
100: '#4a4b50',
},
neutral: {
50: '#fafafa',
100: '#f0f0f1',
200: '#d4d4d8',
300: '#a1a1aa',
400: '#71717a',
500: '#52525b',
},
semantic: {
success: '#22c55e',
warning: '#eab308',
error: '#ef4444',
},
} as const
// ── Typography ──────────────────────────────────────────
export const font = {
display: '"Space Grotesk", sans-serif',
sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
mono: '"JetBrains Mono", "Fira Code", monospace',
} as const
// ── Spacing (px) ────────────────────────────────────────
export const space = {
section: { y: 120, yMobile: 80 },
grid: { gap: 16, gapLg: 24 },
container: { maxWidth: 1280, px: 24, pxLg: 48 },
} as const
// ── Shadows ─────────────────────────────────────────────
export const shadow = {
insetPanel: 'inset 0 2px 6px rgba(0,0,0,0.6), 0 1px 1px rgba(255,255,255,0.04)',
chassis: '0 1px 3px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.04)',
glowSm: '0 0 10px rgba(242,91,41,0.3)',
glowMd: '0 0 20px rgba(242,91,41,0.25), 0 0 40px rgba(242,91,41,0.1)',
glowLg: '0 0 30px rgba(242,91,41,0.3), 0 0 60px rgba(242,91,41,0.15), 0 0 90px rgba(242,91,41,0.05)',
} as const
// ── Radii ───────────────────────────────────────────────
export const radius = {
instrument: '2px',
panel: '6px',
card: '12px',
pill: '999px',
} as const
// ── Z-Index ─────────────────────────────────────────────
export const zIndex = {
header: 50,
overlay: 40,
modal: 60,
} as const
// ── Timing ──────────────────────────────────────────────
export const timing = {
fast: '150ms',
normal: '250ms',
slow: '400ms',
easeOut: 'cubic-bezier(0.16, 1, 0.3, 1)',
} as const
// ── Feature Labels ──────────────────────────────────────
export const tierLabel = {
free: 'FREE',
pro: 'PRO',
proPlus: 'PRO+',
} as const
// ── Nav Items ───────────────────────────────────────────
// Labels come from i18n (t.nav.*). Only hrefs and keys are defined here.
export const navItems = [
{ key: 'features' as const, href: '#features' },
{ key: 'pipeline' as const, href: '#pipeline' },
{ key: 'privacy' as const, href: '#privacy' },
{ key: 'pricing' as const, href: '#pricing' },
{ key: 'faq' as const, href: '#faq' },
] as const

1
site/src/vite-env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />