From 8b5b5a2cb2a8e68762218e778600e593c07d7bd1 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 01:38:26 +0000 Subject: [PATCH 1/3] feat(web): add SEO-ready open source landing page - Add comprehensive meta tags for SEO (title, description, og:*, twitter:*) - Add hero section with clear value proposition - Add 'Why open source matters' section with key benefits - Integrate GitHubOpenSource component for community showcase - Add transparency section highlighting auditable codebase - Add tech stack section showcasing Rust, Tauri, React, Whisper, LLMs - Add community contribution section with links to GitHub, Discord, Twitter - Add CTA section with download and learn more links - Follow existing design patterns from other product pages Co-Authored-By: john@hyprnote.com --- .../src/routes/_view/product/opensource.tsx | 490 +++++++++++++++++- 1 file changed, 486 insertions(+), 4 deletions(-) diff --git a/apps/web/src/routes/_view/product/opensource.tsx b/apps/web/src/routes/_view/product/opensource.tsx index 3ecd49f8fb..299dca5f41 100644 --- a/apps/web/src/routes/_view/product/opensource.tsx +++ b/apps/web/src/routes/_view/product/opensource.tsx @@ -1,9 +1,491 @@ -import { createFileRoute } from "@tanstack/react-router"; +import { Icon } from "@iconify-icon/react"; +import { createFileRoute, Link } from "@tanstack/react-router"; + +import { cn } from "@hypr/utils"; + +import { GitHubOpenSource } from "@/components/github-open-source"; +import { SlashSeparator } from "@/components/slash-separator"; export const Route = createFileRoute("/_view/product/opensource")({ - component: RouteComponent, + component: Component, + head: () => ({ + meta: [ + { title: "Open Source - Hyprnote" }, + { + name: "description", + content: + "Hyprnote is fully open source under GPL-3.0. Inspect every line of code, contribute to development, and build on a transparent foundation. No black boxes, no hidden data collection.", + }, + { property: "og:title", content: "Open Source - Hyprnote" }, + { + property: "og:description", + content: + "AI-powered meeting notes built in the open. Fully auditable codebase, community-driven development, and complete transparency. Join thousands of developers building the future of private meeting notes.", + }, + { property: "og:type", content: "website" }, + { + property: "og:url", + content: "https://hyprnote.com/product/opensource", + }, + { name: "twitter:card", content: "summary_large_image" }, + { name: "twitter:title", content: "Open Source - Hyprnote" }, + { + name: "twitter:description", + content: + "AI-powered meeting notes built in the open. Fully auditable codebase and community-driven development.", + }, + { + name: "keywords", + content: + "open source, meeting notes, AI transcription, privacy, GPL-3.0, Rust, Tauri, local AI, whisper, llm", + }, + ], + }), }); -function RouteComponent() { - return
Hello "/_view/product/opensource"!
; +function Component() { + return ( +
+
+ + + + + + + + + + + + + +
+
+ ); +} + +function HeroSection() { + return ( +
+
+
+

+ Built in the open, +
+ for everyone +

+

+ Hyprnote is fully open source under GPL-3.0. Every line of code is + auditable, every decision is transparent, and every user has the + freedom to inspect, modify, and contribute. +

+
+ + + View on GitHub + + + Download for free + +
+
+
+
+ ); +} + +function WhyOpenSourceSection() { + return ( +
+

+ Why open source matters +

+
+
+ +

+ Verifiable privacy +

+

+ Don't just trust our privacy claims—verify them yourself. Every data + flow, every API call, every storage operation is visible in the + source code. +

+
+
+ +

+ Community driven +

+

+ Features are shaped by real users, not just product managers. Report + bugs, suggest improvements, or contribute code directly to make + Hyprnote better for everyone. +

+
+
+ +

+ No vendor lock-in +

+

+ Your data, your rules. Fork the project, self-host it, or modify it + to fit your exact needs. You're never trapped in a proprietary + ecosystem. +

+
+
+ +

+ Long-term sustainability +

+

+ Open source projects outlive companies. Even if Hyprnote the company + disappears, the software lives on through the community. +

+
+
+
+ ); +} + +function TransparencySection() { + return ( +
+

+ Complete transparency +

+
+
+
+ +

+ Auditable codebase +

+

+ Every function, every algorithm, every data handler is open for + inspection. Security researchers and privacy advocates can verify + our claims. +

+
+
+ +

+ Public development +

+

+ All development happens in the open. Watch features being built, + see how bugs are fixed, and understand the reasoning behind every + change. +

+
+
+ +

Clear licensing

+

+ GPL-3.0 ensures the code stays open. Any modifications must also + be open source, protecting the community's investment. +

+
+
+ +
+
+ +
+

+ No hidden data collection +

+

+ Unlike closed-source alternatives, you can verify exactly what + data Hyprnote collects and where it goes. Our telemetry is + opt-in, minimal, and fully documented in the source code. +

+ + + View analytics implementation + + +
+
+
+
+
+ ); +} + +function TechStackSection() { + return ( +
+

+ Built with modern technology +

+

+ Hyprnote combines the best of systems programming and web technologies + to deliver a fast, secure, and cross-platform experience. +

+ +
+
+
+ +

Rust

+
+

+ Memory-safe systems programming for the core audio processing, + transcription pipeline, and local AI inference. +

+
+
+
+ +

Tauri

+
+

+ Lightweight desktop framework that combines Rust backend with web + frontend for native performance. +

+
+
+
+ +

React

+
+

+ Modern UI framework powering the desktop app interface with TanStack + Router for navigation. +

+
+
+
+ +

Whisper

+
+

+ OpenAI's speech recognition model running locally for private, + accurate transcription in 100+ languages. +

+
+
+
+ +

Local LLMs

+
+

+ On-device language models for summarization and insights without + sending data to external servers. +

+
+
+
+ +

SQLite

+
+

+ Local-first database via libsql for fast, reliable storage with + optional cloud sync. +

+
+
+ +
+ + + Explore the full architecture on GitHub + + +
+
+ ); +} + +function ContributeSection() { + return ( +
+

+ Join the community +

+ +
+
+
+ +

+ Contribute code +

+

+ Whether it's fixing a bug, adding a feature, or improving + documentation, every contribution makes Hyprnote better. +

+ + Read contributing guide + + +
+
+ +

+ Report issues +

+

+ Found a bug or have a feature request? Open an issue on GitHub and + help us prioritize what matters most to users. +

+ + View open issues + + +
+
+ +
+ + +
+

GitHub

+

Star & fork

+
+
+ + +
+

Discord

+

Join the chat

+
+
+ + +
+

Twitter

+

Follow updates

+
+
+
+
+
+ ); +} + +function CTASection() { + return ( +
+
+

+ Privacy you can verify +

+

+ Join thousands of users who trust Hyprnote because they can see + exactly how it works. Download the app or explore the source code + today. +

+
+ + Download for free + + + Learn about Local AI + +
+
+
+ ); } From 2e34b8ec5fcccc29ef40b80b10df1f5ae4fe339a Mon Sep 17 00:00:00 2001 From: ComputelessComputer Date: Sun, 30 Nov 2025 14:14:45 +0900 Subject: [PATCH 2/3] feat: Update footer with icons and styling improvements --- apps/web/src/components/footer.tsx | 69 +++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx index 93cc5d2d11..1623730c41 100644 --- a/apps/web/src/components/footer.tsx +++ b/apps/web/src/components/footer.tsx @@ -1,4 +1,5 @@ import { Link, useRouterState } from "@tanstack/react-router"; +import { ExternalLinkIcon, MailIcon } from "lucide-react"; function getMaxWidthClass(pathname: string): string { const isBlogOrDocs = @@ -58,7 +59,7 @@ export function Footer() {
-

+

Product

    @@ -99,16 +100,17 @@ export function Footer() { href="https://github.com/fastrepl/hyprnote" target="_blank" rel="noopener noreferrer" - className="text-sm text-neutral-600 hover:text-stone-600 transition-colors" + className="text-sm text-neutral-600 hover:text-stone-600 transition-colors inline-flex items-center gap-1" > GitHub +
-

+

Resources

    @@ -123,9 +125,10 @@ export function Footer() {
  • Support +
  • @@ -133,9 +136,10 @@ export function Footer() { href="https://github.com/fastrepl/hyprnote/discussions" target="_blank" rel="noopener noreferrer" - className="text-sm text-neutral-600 hover:text-stone-600 transition-colors" + className="text-sm text-neutral-600 hover:text-stone-600 transition-colors inline-flex items-center gap-1" > Discussions +
  • @@ -146,14 +150,6 @@ export function Footer() { Pricing
  • -
  • - - Press Kit - -
  • -

    +

    Company

      @@ -196,17 +192,25 @@ export function Footer() {
    • + Press Kit + +
    • +
    • + - Enterprise + Open Source
    -

    +

    Social

      @@ -215,9 +219,32 @@ export function Footer() { href="/x" target="_blank" rel="noopener noreferrer" - className="text-sm text-neutral-600 hover:text-stone-600 transition-colors" + className="text-sm text-neutral-600 hover:text-stone-600 transition-colors inline-flex items-center gap-1" > Twitter + + + +
    • + + Bluesky + + +
    • +
    • + + Reddit +
    • @@ -225,9 +252,10 @@ export function Footer() { href="/discord" target="_blank" rel="noopener noreferrer" - className="text-sm text-neutral-600 hover:text-stone-600 transition-colors" + className="text-sm text-neutral-600 hover:text-stone-600 transition-colors inline-flex items-center gap-1" > Discord +
    • @@ -235,9 +263,10 @@ export function Footer() { href="/youtube" target="_blank" rel="noopener noreferrer" - className="text-sm text-neutral-600 hover:text-stone-600 transition-colors" + className="text-sm text-neutral-600 hover:text-stone-600 transition-colors inline-flex items-center gap-1" > YouTube +
    From d434cca9a1a05c5971c6ec44b48dbd9d109fac79 Mon Sep 17 00:00:00 2001 From: ComputelessComputer Date: Sun, 30 Nov 2025 14:15:10 +0900 Subject: [PATCH 3/3] refactor: remove product/opensource route and add new /opensource route --- apps/web/src/routeTree.gen.ts | 42 +++++++++---------- .../routes/_view/{product => }/opensource.tsx | 4 +- 2 files changed, 23 insertions(+), 23 deletions(-) rename apps/web/src/routes/_view/{product => }/opensource.tsx (99%) diff --git a/apps/web/src/routeTree.gen.ts b/apps/web/src/routeTree.gen.ts index c666662293..dc2b071676 100644 --- a/apps/web/src/routeTree.gen.ts +++ b/apps/web/src/routeTree.gen.ts @@ -26,6 +26,7 @@ import { Route as ApiTemplatesRouteImport } from './routes/api/templates' import { Route as ViewSecurityRouteImport } from './routes/_view/security' import { Route as ViewPricingRouteImport } from './routes/_view/pricing' import { Route as ViewPressKitRouteImport } from './routes/_view/press-kit' +import { Route as ViewOpensourceRouteImport } from './routes/_view/opensource' import { Route as ViewFreeRouteImport } from './routes/_view/free' import { Route as ViewFileTranscriptionRouteImport } from './routes/_view/file-transcription' import { Route as ViewFaqRouteImport } from './routes/_view/faq' @@ -63,7 +64,6 @@ import { Route as ViewShortcutsSlugRouteImport } from './routes/_view/shortcuts/ import { Route as ViewRoadmapSlugRouteImport } from './routes/_view/roadmap/$slug' import { Route as ViewProductWorkflowsRouteImport } from './routes/_view/product/workflows' import { Route as ViewProductSelfHostingRouteImport } from './routes/_view/product/self-hosting' -import { Route as ViewProductOpensourceRouteImport } from './routes/_view/product/opensource' import { Route as ViewProductNotepadRouteImport } from './routes/_view/product/notepad' import { Route as ViewProductMiniAppsRouteImport } from './routes/_view/product/mini-apps' import { Route as ViewProductMemoryRouteImport } from './routes/_view/product/memory' @@ -172,6 +172,11 @@ const ViewPressKitRoute = ViewPressKitRouteImport.update({ path: '/press-kit', getParentRoute: () => ViewRouteRoute, } as any) +const ViewOpensourceRoute = ViewOpensourceRouteImport.update({ + id: '/opensource', + path: '/opensource', + getParentRoute: () => ViewRouteRoute, +} as any) const ViewFreeRoute = ViewFreeRouteImport.update({ id: '/free', path: '/free', @@ -362,11 +367,6 @@ const ViewProductSelfHostingRoute = ViewProductSelfHostingRouteImport.update({ path: '/product/self-hosting', getParentRoute: () => ViewRouteRoute, } as any) -const ViewProductOpensourceRoute = ViewProductOpensourceRouteImport.update({ - id: '/product/opensource', - path: '/product/opensource', - getParentRoute: () => ViewRouteRoute, -} as any) const ViewProductNotepadRoute = ViewProductNotepadRouteImport.update({ id: '/product/notepad', path: '/product/notepad', @@ -505,6 +505,7 @@ export interface FileRoutesByFullPath { '/faq': typeof ViewFaqRoute '/file-transcription': typeof ViewFileTranscriptionRoute '/free': typeof ViewFreeRoute + '/opensource': typeof ViewOpensourceRoute '/press-kit': typeof ViewPressKitRouteWithChildren '/pricing': typeof ViewPricingRoute '/security': typeof ViewSecurityRoute @@ -534,7 +535,6 @@ export interface FileRoutesByFullPath { '/product/memory': typeof ViewProductMemoryRoute '/product/mini-apps': typeof ViewProductMiniAppsRoute '/product/notepad': typeof ViewProductNotepadRoute - '/product/opensource': typeof ViewProductOpensourceRoute '/product/self-hosting': typeof ViewProductSelfHostingRoute '/product/workflows': typeof ViewProductWorkflowsRoute '/roadmap/$slug': typeof ViewRoadmapSlugRoute @@ -581,6 +581,7 @@ export interface FileRoutesByTo { '/faq': typeof ViewFaqRoute '/file-transcription': typeof ViewFileTranscriptionRoute '/free': typeof ViewFreeRoute + '/opensource': typeof ViewOpensourceRoute '/press-kit': typeof ViewPressKitRouteWithChildren '/pricing': typeof ViewPricingRoute '/security': typeof ViewSecurityRoute @@ -610,7 +611,6 @@ export interface FileRoutesByTo { '/product/memory': typeof ViewProductMemoryRoute '/product/mini-apps': typeof ViewProductMiniAppsRoute '/product/notepad': typeof ViewProductNotepadRoute - '/product/opensource': typeof ViewProductOpensourceRoute '/product/self-hosting': typeof ViewProductSelfHostingRoute '/product/workflows': typeof ViewProductWorkflowsRoute '/roadmap/$slug': typeof ViewRoadmapSlugRoute @@ -662,6 +662,7 @@ export interface FileRoutesById { '/_view/faq': typeof ViewFaqRoute '/_view/file-transcription': typeof ViewFileTranscriptionRoute '/_view/free': typeof ViewFreeRoute + '/_view/opensource': typeof ViewOpensourceRoute '/_view/press-kit': typeof ViewPressKitRouteWithChildren '/_view/pricing': typeof ViewPricingRoute '/_view/security': typeof ViewSecurityRoute @@ -691,7 +692,6 @@ export interface FileRoutesById { '/_view/product/memory': typeof ViewProductMemoryRoute '/_view/product/mini-apps': typeof ViewProductMiniAppsRoute '/_view/product/notepad': typeof ViewProductNotepadRoute - '/_view/product/opensource': typeof ViewProductOpensourceRoute '/_view/product/self-hosting': typeof ViewProductSelfHostingRoute '/_view/product/workflows': typeof ViewProductWorkflowsRoute '/_view/roadmap/$slug': typeof ViewRoadmapSlugRoute @@ -743,6 +743,7 @@ export interface FileRouteTypes { | '/faq' | '/file-transcription' | '/free' + | '/opensource' | '/press-kit' | '/pricing' | '/security' @@ -772,7 +773,6 @@ export interface FileRouteTypes { | '/product/memory' | '/product/mini-apps' | '/product/notepad' - | '/product/opensource' | '/product/self-hosting' | '/product/workflows' | '/roadmap/$slug' @@ -819,6 +819,7 @@ export interface FileRouteTypes { | '/faq' | '/file-transcription' | '/free' + | '/opensource' | '/press-kit' | '/pricing' | '/security' @@ -848,7 +849,6 @@ export interface FileRouteTypes { | '/product/memory' | '/product/mini-apps' | '/product/notepad' - | '/product/opensource' | '/product/self-hosting' | '/product/workflows' | '/roadmap/$slug' @@ -899,6 +899,7 @@ export interface FileRouteTypes { | '/_view/faq' | '/_view/file-transcription' | '/_view/free' + | '/_view/opensource' | '/_view/press-kit' | '/_view/pricing' | '/_view/security' @@ -928,7 +929,6 @@ export interface FileRouteTypes { | '/_view/product/memory' | '/_view/product/mini-apps' | '/_view/product/notepad' - | '/_view/product/opensource' | '/_view/product/self-hosting' | '/_view/product/workflows' | '/_view/roadmap/$slug' @@ -1099,6 +1099,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ViewPressKitRouteImport parentRoute: typeof ViewRouteRoute } + '/_view/opensource': { + id: '/_view/opensource' + path: '/opensource' + fullPath: '/opensource' + preLoaderRoute: typeof ViewOpensourceRouteImport + parentRoute: typeof ViewRouteRoute + } '/_view/free': { id: '/_view/free' path: '/free' @@ -1358,13 +1365,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ViewProductSelfHostingRouteImport parentRoute: typeof ViewRouteRoute } - '/_view/product/opensource': { - id: '/_view/product/opensource' - path: '/product/opensource' - fullPath: '/product/opensource' - preLoaderRoute: typeof ViewProductOpensourceRouteImport - parentRoute: typeof ViewRouteRoute - } '/_view/product/notepad': { id: '/_view/product/notepad' path: '/product/notepad' @@ -1601,6 +1601,7 @@ interface ViewRouteRouteChildren { ViewFaqRoute: typeof ViewFaqRoute ViewFileTranscriptionRoute: typeof ViewFileTranscriptionRoute ViewFreeRoute: typeof ViewFreeRoute + ViewOpensourceRoute: typeof ViewOpensourceRoute ViewPressKitRoute: typeof ViewPressKitRouteWithChildren ViewPricingRoute: typeof ViewPricingRoute ViewSecurityRoute: typeof ViewSecurityRoute @@ -1620,7 +1621,6 @@ interface ViewRouteRouteChildren { ViewProductMemoryRoute: typeof ViewProductMemoryRoute ViewProductMiniAppsRoute: typeof ViewProductMiniAppsRoute ViewProductNotepadRoute: typeof ViewProductNotepadRoute - ViewProductOpensourceRoute: typeof ViewProductOpensourceRoute ViewProductSelfHostingRoute: typeof ViewProductSelfHostingRoute ViewProductWorkflowsRoute: typeof ViewProductWorkflowsRoute ViewRoadmapSlugRoute: typeof ViewRoadmapSlugRoute @@ -1657,6 +1657,7 @@ const ViewRouteRouteChildren: ViewRouteRouteChildren = { ViewFaqRoute: ViewFaqRoute, ViewFileTranscriptionRoute: ViewFileTranscriptionRoute, ViewFreeRoute: ViewFreeRoute, + ViewOpensourceRoute: ViewOpensourceRoute, ViewPressKitRoute: ViewPressKitRouteWithChildren, ViewPricingRoute: ViewPricingRoute, ViewSecurityRoute: ViewSecurityRoute, @@ -1676,7 +1677,6 @@ const ViewRouteRouteChildren: ViewRouteRouteChildren = { ViewProductMemoryRoute: ViewProductMemoryRoute, ViewProductMiniAppsRoute: ViewProductMiniAppsRoute, ViewProductNotepadRoute: ViewProductNotepadRoute, - ViewProductOpensourceRoute: ViewProductOpensourceRoute, ViewProductSelfHostingRoute: ViewProductSelfHostingRoute, ViewProductWorkflowsRoute: ViewProductWorkflowsRoute, ViewRoadmapSlugRoute: ViewRoadmapSlugRoute, diff --git a/apps/web/src/routes/_view/product/opensource.tsx b/apps/web/src/routes/_view/opensource.tsx similarity index 99% rename from apps/web/src/routes/_view/product/opensource.tsx rename to apps/web/src/routes/_view/opensource.tsx index 299dca5f41..36741c6a63 100644 --- a/apps/web/src/routes/_view/product/opensource.tsx +++ b/apps/web/src/routes/_view/opensource.tsx @@ -6,7 +6,7 @@ import { cn } from "@hypr/utils"; import { GitHubOpenSource } from "@/components/github-open-source"; import { SlashSeparator } from "@/components/slash-separator"; -export const Route = createFileRoute("/_view/product/opensource")({ +export const Route = createFileRoute("/_view/opensource")({ component: Component, head: () => ({ meta: [ @@ -25,7 +25,7 @@ export const Route = createFileRoute("/_view/product/opensource")({ { property: "og:type", content: "website" }, { property: "og:url", - content: "https://hyprnote.com/product/opensource", + content: "https://hyprnote.com/opensource", }, { name: "twitter:card", content: "summary_large_image" }, { name: "twitter:title", content: "Open Source - Hyprnote" },