+
+
+
+ {/* Desktop Navigation */}
+
+
+ {/* Mobile Download Button and Hamburger */}
+
+
+
+ {/* Mobile Menu - Modal Card */}
+ {isMobileMenuOpen && (
+ <>
+ {/* Backdrop */}
+
setIsMobileMenuOpen(false)}
+ />
+
+ {/* Modal Card */}
+
+
+ {/* Header with close button */}
+
+
Jan
+
+
+
+ {/* Menu Items */}
+
+
+ {/* Social Icons */}
+
+
+ {/* Action Buttons */}
+
+
+
+ >
+ )}
+
+ )
+}
+
+export default Navbar
diff --git a/docs/src/components/TweetSection.tsx b/docs/src/components/TweetSection.tsx
new file mode 100644
index 000000000..ef39f5ad7
--- /dev/null
+++ b/docs/src/components/TweetSection.tsx
@@ -0,0 +1,135 @@
+import { ClientTweetCard } from '@/components/ui/tweet-card'
+import { useEffect } from 'react'
+
+const Tweets = [
+ { id: '1959360209970700621' },
+ { id: '1959018716219277654' },
+ { id: '1959410685093523580' },
+ { id: '1959003819196785143' },
+ { id: '1956547833999560863' },
+ { id: '1956616098885079434' },
+ { id: '1955283174340128809' },
+ { id: '1955680680261652896' },
+ { id: '1955624616560566446' },
+ { id: '1955633387038966112' },
+ { id: '1955326315160043918' },
+ { id: '1952305678497747137' },
+]
+
+export default function TweetSection() {
+ useEffect(() => {
+ const buttons = document.querySelectorAll('.tweet-nav-btn')
+
+ const handleClick = (event: Event) => {
+ const button = event.currentTarget as HTMLButtonElement
+ const direction = button.dataset.direction
+ const container = document.querySelector('.tweet-marquee-container')
+
+ if (direction === 'left') {
+ container?.scrollBy({ left: -300, behavior: 'smooth' })
+ } else {
+ container?.scrollBy({ left: 300, behavior: 'smooth' })
+ }
+ }
+
+ buttons.forEach((button) => {
+ button.addEventListener('click', handleClick)
+ })
+
+ return () => {
+ buttons.forEach((button) => {
+ button.removeEventListener('click', handleClick)
+ })
+ }
+ }, [])
+
+ return (
+
+ {/* Scrollable marquee container */}
+
+
+ {/* Multiple copies for infinite scroll */}
+ {[...Tweets, ...Tweets, ...Tweets].map((tweet, index) => (
+
+
+
+ ))}
+
+
+
+ {/* Navigation arrows at bottom - will need client-side JS */}
+
+
+
+
+ )
+}
diff --git a/docs/src/components/ui/button.tsx b/docs/src/components/ui/button.tsx
new file mode 100644
index 000000000..ae58a6332
--- /dev/null
+++ b/docs/src/components/ui/button.tsx
@@ -0,0 +1,67 @@
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/lib/utils";
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-pointer",
+ {
+ variants: {
+ variant: {
+ "playful-green":
+ "bg-[#7EF19D] hover:bg-[#6BD689] hover:shadow-[0px_0px_0px_0px_rgba(0,0,0,1)] hover:translate-y-[2px] active:shadow-[0px_2px_0px_0px_rgba(0,0,0,1)] active:translate-y-[2px] text-black shadow-[0px_4px_0px_0px_rgba(0,0,0,1)] border border-black !rounded-2xl",
+ "playful-white":
+ "bg-white text-black hover:bg-gray-200 hover:shadow-[0px_0px_0px_0px_rgba(0,0,0,1)] hover:translate-y-[2px] active:shadow-[0px_2px_0px_0px_rgba(0,0,0,1)] active:translate-y-[2px] shadow-[0px_4px_0px_0px_rgba(0,0,0,1)] border border-black !rounded-2xl",
+ playful:
+ "text-black hover:shadow-[0px_0px_0px_0px_rgba(0,0,0,1)] hover:translate-y-[2px] active:shadow-[0px_2px_0px_0px_rgba(0,0,0,1)] active:translate-y-[2px] shadow-[0px_4px_0px_0px_rgba(0,0,0,1)] border border-black !rounded-2xl",
+ default:
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ outline:
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ secondary:
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
+ ghost:
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
+ xl: "h-12 rounded-md px-6 has-[>svg]:px-4 text-lg",
+ xxl: "h-16 !rounded-[20px] px-6 has-[>svg]:px-4 text-xl -tracking-[0.2px]",
+ icon: "size-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+);
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<"button"> &
+ VariantProps
& {
+ asChild?: boolean;
+ }) {
+ const Comp = asChild ? Slot : "button";
+
+ return (
+
+ );
+}
+
+export { Button, buttonVariants };
diff --git a/docs/src/components/ui/dropdown-button.tsx b/docs/src/components/ui/dropdown-button.tsx
new file mode 100644
index 000000000..4b2e5a808
--- /dev/null
+++ b/docs/src/components/ui/dropdown-button.tsx
@@ -0,0 +1,255 @@
+import * as React from 'react'
+import { Button } from './button'
+import { cn } from '@/lib/utils'
+import { FaApple, FaWindows, FaLinux } from 'react-icons/fa'
+import { formatFileSize } from '@/utils/format'
+
+interface DownloadOption {
+ id: string
+ name: string
+ icon: React.ReactNode
+ size: string
+ href: string
+ isActive?: boolean
+}
+
+const downloadOptionsTemplate: DownloadOption[] = [
+ {
+ id: 'mac',
+ name: 'Download for Mac',
+ icon: ,
+ size: '',
+ href: '#',
+ isActive: true,
+ },
+ {
+ id: 'windows',
+ name: 'Download for Windows',
+ icon: ,
+ size: '',
+ href: '#',
+ },
+ {
+ id: 'linux-appimage',
+ name: 'Download for Linux (AppImage)',
+ icon: ,
+ size: '',
+ href: '#',
+ },
+ {
+ id: 'linux-deb',
+ name: 'Download for Linux (Deb)',
+ icon: ,
+ size: '',
+ href: '#',
+ },
+]
+
+const fileFormatMap: { [key: string]: string } = {
+ 'mac': 'Jan_{tag}_universal.dmg',
+ 'windows': 'Jan_{tag}_x64-setup.exe',
+ 'linux-appimage': 'Jan_{tag}_amd64.AppImage',
+ 'linux-deb': 'Jan_{tag}_amd64.deb',
+}
+
+interface DropdownButtonProps {
+ size?: 'default' | 'sm' | 'lg' | 'xl' | 'icon' | 'xxl'
+ className?: string
+ classNameButton?: string
+ lastRelease?: any
+}
+
+export function DropdownButton({
+ size = 'xl',
+ className,
+ classNameButton,
+ lastRelease,
+}: DropdownButtonProps) {
+ const [isOpen, setIsOpen] = React.useState(false)
+ const [downloadOptions, setDownloadOptions] = React.useState(
+ downloadOptionsTemplate
+ )
+ const [currentOption, setCurrentOption] = React.useState(
+ downloadOptions.find((opt) => opt.isActive) || downloadOptions[0]
+ )
+ const dropdownRef = React.useRef(null)
+
+ const toggleDropdown = () => setIsOpen(!isOpen)
+
+ const selectOption = (option: DownloadOption) => {
+ setCurrentOption(option)
+ setIsOpen(false)
+ }
+
+ const changeDefaultSystem = React.useCallback((systems: DownloadOption[]) => {
+ const userAgent = navigator.userAgent
+ if (userAgent.includes('Windows')) {
+ // windows user
+ const windowsOption = systems.find((opt) => opt.id === 'windows')
+ if (windowsOption) setCurrentOption(windowsOption)
+ } else if (userAgent.includes('Linux')) {
+ // linux user - prefer deb package
+ const linuxOption = systems.find((opt) => opt.id === 'linux-deb')
+ if (linuxOption) setCurrentOption(linuxOption)
+ } else if (userAgent.includes('Mac OS')) {
+ // mac user - always use universal build
+ const macOption = systems.find((opt) => opt.id === 'mac')
+ if (macOption) setCurrentOption(macOption)
+ } else {
+ // fallback to windows
+ const windowsOption = systems.find((opt) => opt.id === 'windows')
+ if (windowsOption) setCurrentOption(windowsOption)
+ }
+ }, [])
+
+ React.useEffect(() => {
+ if (lastRelease) {
+ try {
+ const tag = lastRelease.tag_name.startsWith('v')
+ ? lastRelease.tag_name.substring(1)
+ : lastRelease.tag_name
+
+ const updatedOptions = downloadOptionsTemplate.map((option) => {
+ const fileFormat = fileFormatMap[option.id]
+ const fileName = fileFormat.replace('{tag}', tag)
+
+ // Find the corresponding asset to get the file size
+ const asset = lastRelease.assets.find(
+ (asset: any) => asset.name === fileName
+ )
+
+ return {
+ ...option,
+ href: `https://github.com/menloresearch/jan/releases/download/${lastRelease.tag_name}/${fileName}`,
+ size: asset ? formatFileSize(asset.size) : 'N/A',
+ }
+ })
+
+ setDownloadOptions(updatedOptions)
+ changeDefaultSystem(updatedOptions)
+ } catch (error) {
+ console.error('Failed to update download links:', error)
+ }
+ }
+ }, [lastRelease, changeDefaultSystem])
+
+ React.useEffect(() => {
+ const handleEscapeKey = (event: KeyboardEvent) => {
+ if (event.key === 'Escape' && isOpen) {
+ setIsOpen(false)
+ }
+ }
+
+ const handleClickOutside = (event: MouseEvent) => {
+ if (
+ dropdownRef.current &&
+ !dropdownRef.current.contains(event.target as Node)
+ ) {
+ setIsOpen(false)
+ }
+ }
+
+ if (isOpen) {
+ document.addEventListener('keydown', handleEscapeKey)
+ document.addEventListener('mousedown', handleClickOutside)
+ }
+
+ return () => {
+ document.removeEventListener('keydown', handleEscapeKey)
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+ }, [isOpen])
+
+ return (
+
+
+
+ {/* Dropdown Menu */}
+ {isOpen && (
+
+ )}
+
+ )
+}
diff --git a/docs/src/components/ui/tweet-card.tsx b/docs/src/components/ui/tweet-card.tsx
new file mode 100644
index 000000000..358a787e4
--- /dev/null
+++ b/docs/src/components/ui/tweet-card.tsx
@@ -0,0 +1,293 @@
+/* eslint-disable @next/next/no-img-element */
+import { Suspense } from 'react'
+import { FaXTwitter } from 'react-icons/fa6'
+
+import {
+ enrichTweet,
+ useTweet,
+ type EnrichedTweet,
+ type TweetProps,
+ type TwitterComponents,
+} from 'react-tweet'
+import { getTweet, type Tweet } from 'react-tweet/api'
+
+import { cn } from '@/lib/utils'
+
+interface TwitterIconProps {
+ className?: string
+ [key: string]: unknown
+}
+const Twitter = ({ className, ...props }: TwitterIconProps) => (
+
+)
+
+const Verified = ({ className, ...props }: TwitterIconProps) => (
+
+)
+
+export const truncate = (str: string | null, length: number) => {
+ if (!str || str.length <= length) return str
+ return `${str.slice(0, length - 3)}...`
+}
+
+const Skeleton = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => {
+ return (
+
+ )
+}
+
+export const TweetSkeleton = ({
+ className,
+ ...props
+}: {
+ className?: string
+ [key: string]: unknown
+}) => (
+
+)
+
+export const TweetNotFound = ({
+ className,
+ ...props
+}: {
+ className?: string
+ [key: string]: unknown
+}) => (
+
+
Tweet not found
+
+)
+
+export const TweetHeader = ({ tweet }: { tweet: EnrichedTweet }) => (
+
+)
+
+export const TweetBody = ({ tweet }: { tweet: EnrichedTweet }) => (
+
+ {tweet.entities.map((entity, idx) => {
+ switch (entity.type) {
+ case 'url':
+ case 'symbol':
+ case 'hashtag':
+ case 'mention':
+ return (
+
+ {entity.text}
+
+ )
+ case 'text':
+ return (
+
+ )
+ }
+ })}
+
+)
+
+export const TweetMedia = ({ tweet }: { tweet: EnrichedTweet }) => {
+ if (!tweet.video && !tweet.photos) return null
+ return (
+
+ {tweet.video && (
+
+ )}
+ {tweet.photos && (
+
+
+ {tweet.photos.map((photo) => (
+

+ ))}
+
+
+ )}
+ {!tweet.video &&
+ !tweet.photos &&
+ // @ts-ignore
+ tweet?.card?.binding_values?.thumbnail_image_large?.image_value.url && (
+

+ )}
+
+ )
+}
+
+export const MagicTweet = ({
+ tweet,
+ components,
+ className,
+ ...props
+}: {
+ tweet: Tweet
+ components?: TwitterComponents
+ className?: string
+}) => {
+ const enrichedTweet = enrichTweet(tweet)
+ return (
+
+
+
+ {/* */}
+
+ )
+}
+
+/**
+ * TweetCard (Server Side Only)
+ */
+export const TweetCard = async ({
+ id,
+ components,
+ fallback = ,
+ onError,
+ ...props
+}: TweetProps & {
+ className?: string
+}) => {
+ const tweet = id
+ ? await getTweet(id).catch((err) => {
+ if (onError) {
+ onError(err)
+ } else {
+ console.error(err)
+ }
+ })
+ : undefined
+
+ if (!tweet) {
+ const NotFound = components?.TweetNotFound || TweetNotFound
+ return
+ }
+
+ return (
+
+
+
+ )
+}
+
+export const ClientTweetCard = ({
+ id,
+ apiUrl,
+ fallback = ,
+ components,
+ fetchOptions,
+ onError,
+ ...props
+}: TweetProps & { className?: string }) => {
+ const { data, error, isLoading } = useTweet(id, apiUrl, fetchOptions)
+ if (isLoading) return fallback
+ if (error || !data) {
+ const NotFound = components?.TweetNotFound || TweetNotFound
+ return
+ }
+ return
+}
diff --git a/docs/src/lib/utils.ts b/docs/src/lib/utils.ts
new file mode 100644
index 000000000..fed2fe91e
--- /dev/null
+++ b/docs/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from 'clsx'
+import { twMerge } from 'tailwind-merge'
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/docs/src/pages/_meta.json b/docs/src/pages/_meta.json
index bcecee260..f96b1bc81 100644
--- a/docs/src/pages/_meta.json
+++ b/docs/src/pages/_meta.json
@@ -1,62 +1,67 @@
{
- "index": {
- "type": "page",
- "title": "Homepage",
- "display": "hidden",
- "theme": {
- "layout": "raw"
- }
- },
- "docs": {
- "type": "page",
- "title": "Docs"
- },
- "platforms": {
- "type": "page",
- "title": "Platforms",
- "display": "hidden"
- },
- "integrations": {
- "type": "page",
- "title": "Integrations",
- "display": "hidden"
- },
- "api-reference": {
- "type": "page",
- "title": "API reference",
- "display": "hidden"
- },
- "changelog": {
- "type": "page",
- "title": "Changelog",
- "theme": {
- "layout": "raw"
- }
- },
- "blog": {
- "type": "page",
- "title": "Blog",
- "theme": {
- "layout": "raw"
- }
- },
- "post": {
- "type": "page",
- "title": "Post Categories",
- "display": "hidden"
- },
- "download": {
- "type": "page",
- "theme": {
- "layout": "raw"
- }
- },
- "privacy": {
- "title": "Privacy",
- "display": "hidden"
- },
- "support": {
- "title": "Support",
- "display": "hidden"
- }
+ "index": {
+ "type": "page",
+ "title": "Homepage",
+ "display": "hidden",
+ "theme": {
+ "layout": "raw"
+ }
+ },
+ "docs": {
+ "type": "page",
+ "title": "Docs"
+ },
+ "platforms": {
+ "type": "page",
+ "title": "Platforms",
+ "display": "hidden"
+ },
+ "integrations": {
+ "type": "page",
+ "title": "Integrations",
+ "display": "hidden"
+ },
+ "api-reference": {
+ "type": "page",
+ "title": "API reference",
+ "display": "hidden"
+ },
+ "handbook": {
+ "type": "page",
+ "title": "API reference",
+ "display": "hidden"
+ },
+ "changelog": {
+ "type": "page",
+ "title": "Changelog",
+ "theme": {
+ "layout": "raw"
+ }
+ },
+ "blog": {
+ "type": "page",
+ "title": "Blog",
+ "theme": {
+ "layout": "raw"
+ }
+ },
+ "post": {
+ "type": "page",
+ "title": "Post Categories",
+ "display": "hidden"
+ },
+ "download": {
+ "type": "page",
+ "theme": {
+ "layout": "raw"
+ }
+ },
+ "privacy": {
+ "title": "Privacy",
+ "display": "hidden"
+ },
+ "support": {
+ "title": "Support",
+ "display": "hidden"
+ }
}
diff --git a/docs/src/pages/handbook/_meta.json b/docs/src/pages/handbook/_meta.json
new file mode 100644
index 000000000..ca0a2a6cb
--- /dev/null
+++ b/docs/src/pages/handbook/_meta.json
@@ -0,0 +1,3 @@
+{
+ "index": "Overview"
+}
diff --git a/docs/src/pages/handbook/growth.mdx b/docs/src/pages/handbook/growth.mdx
new file mode 100644
index 000000000..02cc6e40d
--- /dev/null
+++ b/docs/src/pages/handbook/growth.mdx
@@ -0,0 +1,35 @@
+---
+title: "How we grow"
+description: "How Jan is growing"
+---
+
+# How we grow
+
+> People care less about what you are and more about what they can get until you invite them into a purpose they share.
+
+Jan averages 7,000 downloads per day and gets millions of impressions on social media. 150+ people join [our community](https://discord.gg/Exe46xPMbK) each week. All with $0 spent on ads.
+
+We grow because the product is useful today and the purpose is bigger than the product. Jan takes the best of open-source AI and packages it into an easy-to-use product, with a long game: [Open Superintelligence](/handbook/why) that can run on a $1,000 laptop.
+
+Growth happens when the right thing matches the right people with the right emotions. So it starts with the product, and the work is to make something genuinely useful, show how it works, and let others build with us. When the product helps today and can be explored tomorrow, word of mouth does most of the lifting.
+
+## Attention is all you need
+*Really, even for growth.*
+
+Modern life is a contest for attention. We show up where attention lives; docs, code, short posts, meetups, and we show up often.
+
+A useful lens for how we communicate comes from philosopher [Ted Cohen](https://en.wikipedia.org/wiki/Ted_Cohen_(philosopher))'s view of jokes: they land when teller and audience share background that stays unstated, and recognition clicks mid-story.
+
+Product communication works the same way. We start from problems people already know, make a small, concrete move, and let the recognition carry the message. The best punchline is a message or visual that evokes and connects something in viewers' minds.
+
+That's our approach to growing on the path to Open Superintelligence.
+
+Follow/join us (at) where we're:
+- [Discord](https://discord.gg/Exe46xPMb)
+- [X (Twitter)](https://x.com/jandotai)
+- [Threads](http://threads.net/@jandotai)
+- [YouTube](https://www.youtube.com/@jandotai)
+- [LinkedIn](https://www.linkedin.com/company/opensuperintelligence)
+- [Bluesky](https://bsky.app/profile/jandotai.bsky.social)
+- [Instagram](https://www.instagram.com/jandotai)
+- [TikTok](http://tiktok.com/@jandotai1)
\ No newline at end of file
diff --git a/docs/src/pages/handbook/happy.mdx b/docs/src/pages/handbook/happy.mdx
new file mode 100644
index 000000000..740267f2a
--- /dev/null
+++ b/docs/src/pages/handbook/happy.mdx
@@ -0,0 +1,6 @@
+---
+title: "How we make users happy"
+description: "Our approach to user success and satisfaction."
+---
+
+# How we make users happy
diff --git a/docs/src/pages/handbook/history.mdx b/docs/src/pages/handbook/history.mdx
new file mode 100644
index 000000000..7d49709e0
--- /dev/null
+++ b/docs/src/pages/handbook/history.mdx
@@ -0,0 +1,6 @@
+---
+title: "How we got here"
+description: "The journey that led us to building Jan."
+---
+
+# How we got here
\ No newline at end of file
diff --git a/docs/src/pages/handbook/index.mdx b/docs/src/pages/handbook/index.mdx
new file mode 100644
index 000000000..31e34036f
--- /dev/null
+++ b/docs/src/pages/handbook/index.mdx
@@ -0,0 +1,66 @@
+---
+title: "Jan Team Handbook"
+description: "Building superintelligence that you can own and run anywhere."
+---
+
+# Jan Handbook
+
+> Jan's Handbook is inspired by [Posthog](https://posthog.com/handbook) and [Gitlab](https://handbook.gitlab.com/).
+> Thank you for showing us the way.
+
+## Welcome
+
+This handbook explains how [Jan](https://jan.ai) works, and is public.
+
+We're building superintelligence that you can self-host and use locally. Not as a limitation, but as a feature. Your AI should work wherever you need it - on your laptop during a flight, on your company's servers for compliance, or in the cloud for scale.
+
+Jan's Handbook is a [living document](https://en.wikipedia.org/wiki/Living_document), constantly evolving as we build the future of AI ownership.
+
+## The Jan Handbook
+
+### [Why Jan exists](/handbook/why)
+The fundamental problem we're solving and why it matters.
+
+### [How we got here](/handbook/history)
+The journey that led us to building Jan.
+
+### [How we grow](/handbook/growth)
+Our approach to sustainable growth and community building.
+
+### [Who we're building for](/handbook/users)
+Understanding our users and their needs.
+
+### [How we make users happy](/handbook/happy)
+Our approach to user success and satisfaction.
+
+### [How we make money](/handbook/money)
+Our business model and approach to sustainable revenue.
+
+### [How we stay wide with small teams](/handbook/teams)
+Our approach to scaling impact without scaling bureaucracy.
+
+### [How we build a world-class team](/handbook/talent)
+Our approach to attracting, developing, and retaining exceptional talent.
+
+---
+
+## Quick Links
+
+- **For new team members**: Start with [How we build a world-class team](/handbook/talent)
+- **For contributors**: Check out our [GitHub](https://github.com/menloresearch/jan) and [Discord](https://discord.gg/FTk2MvZwJH)
+- **For the curious**: Read about [Why Jan exists](/handbook/why)
+
+## Our North Star
+
+We're building superintelligence that:
+
+- **Works anywhere**: From your laptop to your data center
+- **Belongs to you**: Download it, own it, modify it
+- **Scales infinitely**: One person or ten thousand, same platform
+- **Improves constantly**: Community-driven development
+
+This isn't just about making AI accessible. It's about ensuring the most transformative technology in human history can be owned by those who use it.
+
+---
+
+_"The future of AI isn't about choosing between local or cloud. It's about having both, and everything in between, working perfectly together."_
diff --git a/docs/src/pages/handbook/money.mdx b/docs/src/pages/handbook/money.mdx
new file mode 100644
index 000000000..a337a00ca
--- /dev/null
+++ b/docs/src/pages/handbook/money.mdx
@@ -0,0 +1,4 @@
+---
+title: "How we make money"
+description: "Our business model and approach to sustainable revenue."
+---
diff --git a/docs/src/pages/handbook/talent.mdx b/docs/src/pages/handbook/talent.mdx
new file mode 100644
index 000000000..51e3cb831
--- /dev/null
+++ b/docs/src/pages/handbook/talent.mdx
@@ -0,0 +1,4 @@
+---
+title: "How we build a world-class team"
+description: "Our approach to attracting, developing, and retaining exceptional talent."
+---
\ No newline at end of file
diff --git a/docs/src/pages/handbook/teams.mdx b/docs/src/pages/handbook/teams.mdx
new file mode 100644
index 000000000..b5c63300f
--- /dev/null
+++ b/docs/src/pages/handbook/teams.mdx
@@ -0,0 +1,4 @@
+---
+title: "How we stay wide with small teams"
+description: "Our approach to scaling impact without scaling bureaucracy."
+---
\ No newline at end of file
diff --git a/docs/src/pages/handbook/users.mdx b/docs/src/pages/handbook/users.mdx
new file mode 100644
index 000000000..e7cfc0912
--- /dev/null
+++ b/docs/src/pages/handbook/users.mdx
@@ -0,0 +1,4 @@
+---
+title: "Who we're building for"
+description: "Understanding our users and their needs."
+---
\ No newline at end of file
diff --git a/docs/src/pages/handbook/why.mdx b/docs/src/pages/handbook/why.mdx
new file mode 100644
index 000000000..71db21f87
--- /dev/null
+++ b/docs/src/pages/handbook/why.mdx
@@ -0,0 +1,74 @@
+---
+title: "Why Jan exists"
+description: "Short answer: Open Superintelligence."
+---
+
+# Why does Jan exist?
+
+> Short answer: Open Superintelligence.
+
+[Superintelligence](https://en.wikipedia.org/wiki/Superintelligence) will change how we live. Jan exists to build Open Superintelligence that can run on a $1,000 laptop.
+
+## The big shiny object: Superintelligence
+Everyone in this field is chasing Superintelligence. It's obviously a civilizational tool in the making, and we're about to write new defaults.
+
+Given how far-reaching this could be, we should agree it must remain open to everyone. It has to be a common effort that anyone can use and improve.
+
+Jan is part of that effort: we build [Open Superintelligence people can run on a laptop](https://x.com/jandotai/status/1961096883410989293), a home server, or the web, and we do the work in public so others can copy, critique, and contribute.
+
+## What history teaches
+
+> The world is made, and can be remade.
+
+Every industrial wave redefined critical aspects of our daily lives:
+- Time & labor: factories introduced shift clocks and wage rhythms
+- Scale & power: steam gave way to electricity and standardized parts
+- Coordination: rail, telegraph, and later networks changed how decisions travel
+- Institutions: each wave pulled new bargains into being skills, schools, safety nets, labor law
+
+So the question is who is going to write the new defaults and share in the gains.
+
+From guilds to standards bodies to open protocols, big leaps happen when people pool methods and maintain commons. If intelligence is built together, its defaults can reflect human needs.
+
+## Intelligence as utility
+Great tools start rare and awkward, then become ordinary:
+- [Printing](https://en.wikipedia.org/wiki/Printing) nudged literacy into daily life
+- [Containerization](https://en.wikipedia.org/wiki/Containerization) made trade boring (in the best way)
+- [TCP/IP](https://en.wikipedia.org/wiki/Internet_protocol_suite) let every network speak
+- [Electricity](https://en.wikipedia.org/wiki/Electricity) disappeared into the walls while improving everything it touched
+
+That's when people stop noticing the tech and only notice the outcome.
+
+### Power and Progress
+We believe tech doesn't choose its path, people do. The ones who lead the progress is the ones who own engines power progress.
+
+Progress tilts toward whoever designs, deploys, and profits from the system.
+- If intelligence is closed and centralized, the gains concentrate
+- If it is open, local, and participatory, the gains spread
+
+We believe in the second one, because history repeats the same lesson:
+- Factories lifted owners until schooling and labor law spread gains
+- Electrification stayed in cities until co-ops and interconnection standards pushed power outward
+- The internet scaled because open protocols beat gated networks
+
+So our take is: closed, centralized systems concentrate value, while open & tinkerable systems spread it. Superintelligence has to follow the same logic.
+
+The pattern is constant: shared rules + falling cost = broad access. Intelligence will follow the same path, and it must be open.
+
+## What we're making at Jan
+Jan is one product that bundles models, tools, guardrails, and connectors in a way everybody can run on a laptop, a home server, or the web.
+
+So Jan is:
+- Open, so everyone can study, reproduce, improve
+- Together, so progress compounds in public
+- For everyone, so it runs where people work, under their control
+
+### Co-operation > competition
+
+We believe progress is cooperative before it is competitive. People grow by working together.
+
+We've chosen [to stand on open shoulders](https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_giants). We use, contribute to, and fund open-source projects. When something exists and works, we don't reinvent the wheel to commercialize it - we upstream fixes, write docs, and make it easier to run.
+
+Open superintelligence is how we make that true at the scale of intelligence.
+
+Happy to see you in this journey. Join our [community](https://discord.gg/Exe46xPMbK).
\ No newline at end of file
diff --git a/docs/src/pages/index.mdx b/docs/src/pages/index.mdx
index f830aaf03..8c7ae4db7 100644
--- a/docs/src/pages/index.mdx
+++ b/docs/src/pages/index.mdx
@@ -1,6 +1,6 @@
---
-title: "Jan: Open source ChatGPT-alternative that runs 100% offline"
-description: "Chat with AI without privacy concerns. Jan is an open-source ChatGPT-alternative, running AI models locally on your device."
+title: "Jan - Open-source ChatGPT alternative that runs 100% offline"
+description: "Jan takes the best of open-source AI and packages it into an easy-to-use product. We exist to build Open Superintelligence that runs on a $1,000 laptop."
keywords:
[
Jan,
diff --git a/docs/src/styles/animations.css b/docs/src/styles/animations.css
new file mode 100644
index 000000000..a1ca86de2
--- /dev/null
+++ b/docs/src/styles/animations.css
@@ -0,0 +1,232 @@
+/* Keyframe animations */
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes wave {
+ 0%, 100% {
+ transform: rotate(0deg);
+ }
+ 25% {
+ transform: rotate(-10deg);
+ }
+ 75% {
+ transform: rotate(10deg);
+ }
+}
+
+@keyframes float {
+ 0%, 100% {
+ transform: translateY(0px);
+ }
+ 50% {
+ transform: translateY(8px);
+ }
+}
+
+@keyframes slideInLeft {
+ from {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes slideInRight {
+ from {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes scaleIn {
+ from {
+ opacity: 0;
+ transform: scale(0.9);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+/* Animation classes */
+.animate-fade-in-up {
+ animation: fadeInUp 0.8s ease-out forwards;
+}
+
+.animate-fade-in {
+ animation: fadeIn 0.6s ease-out forwards;
+}
+
+.animate-wave {
+ animation: wave 2s ease-in-out infinite;
+ transform-origin: 70% 70%;
+}
+
+.animate-float {
+ animation: float 3s ease-in-out infinite;
+}
+
+.animate-slide-in-left {
+ animation: slideInLeft 0.8s ease-out forwards;
+}
+
+.animate-slide-in-right {
+ animation: slideInRight 0.8s ease-out forwards;
+}
+
+.animate-scale-in {
+ animation: scaleIn 0.6s ease-out forwards;
+}
+
+/* Delay classes for staggered animations */
+.delay-100 {
+ animation-delay: 0.1s;
+}
+
+.delay-200 {
+ animation-delay: 0.2s;
+}
+
+.delay-300 {
+ animation-delay: 0.3s;
+}
+
+.delay-400 {
+ animation-delay: 0.4s;
+}
+
+.delay-500 {
+ animation-delay: 0.5s;
+}
+
+.delay-600 {
+ animation-delay: 0.6s;
+}
+
+/* Initial state for animated elements */
+.animate-fade-in-up,
+.animate-fade-in,
+.animate-slide-in-left,
+.animate-slide-in-right,
+.animate-scale-in {
+ opacity: 0;
+}
+
+/* Viewport-triggered animations */
+.animate-on-scroll {
+ opacity: 0;
+ transform: translateY(30px);
+ transition: opacity 0.8s ease-out, transform 0.8s ease-out;
+}
+
+.animate-on-scroll.animate-in-view {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.animate-on-scroll-left {
+ opacity: 0;
+ transform: translateX(-50px);
+ transition: opacity 0.8s ease-out, transform 0.8s ease-out;
+}
+
+.animate-on-scroll-left.animate-in-view {
+ opacity: 1;
+ transform: translateX(0);
+}
+
+.animate-on-scroll-right {
+ opacity: 0;
+ transform: translateX(50px);
+ transition: opacity 0.8s ease-out, transform 0.8s ease-out;
+}
+
+.animate-on-scroll-right.animate-in-view {
+ opacity: 1;
+ transform: translateX(0);
+}
+
+.animate-on-scroll-scale {
+ opacity: 0;
+ transform: scale(0.9);
+ transition: opacity 0.6s ease-out, transform 0.6s ease-out;
+}
+
+.animate-on-scroll-scale.animate-in-view {
+ opacity: 1;
+ transform: scale(1);
+}
+
+.animate-slide-up {
+ opacity: 0;
+ transform: translateY(100px);
+ transition: opacity 1s ease-out, transform 1s ease-out;
+}
+
+.animate-slide-up.animate-in-view {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.parallax-element {
+ will-change: transform;
+}
+
+/* Alternative: Simple CSS-based parallax using transform3d for better performance */
+@media (prefers-reduced-motion: no-preference) {
+ .parallax-slow {
+ transform: translateZ(0);
+ animation: parallaxFloat 20s ease-in-out infinite;
+ }
+}
+
+@keyframes parallaxFloat {
+ 0% {
+ transform: translateY(0px);
+ }
+ 50% {
+ transform: translateY(-30px);
+ }
+ 100% {
+ transform: translateY(0px);
+ }
+}
+
+/* Simple test animation */
+.test-animation {
+ animation: testPulse 2s ease-in-out infinite;
+}
+
+@keyframes testPulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.1);
+ }
+}
\ No newline at end of file
diff --git a/docs/src/styles/fonts.scss b/docs/src/styles/fonts.scss
index c7e7db47c..4ea22523e 100644
--- a/docs/src/styles/fonts.scss
+++ b/docs/src/styles/fonts.scss
@@ -44,3 +44,66 @@
font-weight: 300;
font-style: italic;
}
+
+/* Studio Feixen Sans - Ultralight */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Ultralight.otf')
+ format('opentype');
+ font-weight: 200;
+}
+
+/* Studio Feixen Sans - Light */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Light.otf')
+ format('opentype');
+ font-weight: 300;
+}
+
+/* Studio Feixen Sans - Book */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Book.otf')
+ format('opentype');
+ font-weight: 350;
+}
+
+/* Studio Feixen Sans - Regular */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Regular.otf')
+ format('opentype');
+ font-weight: 400;
+}
+
+/* Studio Feixen Sans - Medium */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Medium.otf')
+ format('opentype');
+ font-weight: 500;
+}
+
+/* Studio Feixen Sans - Semibold */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Semibold.otf')
+ format('opentype');
+ font-weight: 600;
+}
+
+/* Studio Feixen Sans - Bold */
+@font-face {
+ font-family: 'StudioFeixenSans';
+ font-display: swap;
+ src: url('../../public/assets/fonts/StudioFeixenSans-Bold.otf')
+ format('opentype');
+ font-weight: 700;
+}
diff --git a/docs/src/styles/main.scss b/docs/src/styles/main.scss
index 591b04102..8ac34ebb0 100644
--- a/docs/src/styles/main.scss
+++ b/docs/src/styles/main.scss
@@ -6,3 +6,4 @@
@import './changelog.scss';
@import './fonts.scss';
@import './wall-of-love.scss';
+@import './animations.css';
diff --git a/docs/tailwind.config.ts b/docs/tailwind.config.ts
index 86f5f6c87..fcffa75fe 100644
--- a/docs/tailwind.config.ts
+++ b/docs/tailwind.config.ts
@@ -16,6 +16,17 @@ const config: Config = {
},
fontFamily: {
sans: [
+ 'StudioFeixenSans',
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ 'Segoe UI',
+ 'Roboto',
+ 'Oxygen-Sans',
+ 'Ubuntu,Cantarell',
+ 'Helvetica',
+ 'sans-serif',
+ ],
+ inter: [
'Inter',
'-apple-system',
'BlinkMacSystemFont',
diff --git a/docs/theme.config.tsx b/docs/theme.config.tsx
index bad3a6bea..6cbc24208 100644
--- a/docs/theme.config.tsx
+++ b/docs/theme.config.tsx
@@ -1,25 +1,26 @@
-import React, { Fragment } from "react";
-import { useConfig, DocsThemeConfig } from "nextra-theme-docs";
-import LogoMark from "@/components/LogoMark";
-import FooterMenu from "@/components/FooterMenu";
-import JSONLD from "@/components/JSONLD";
-import { useRouter } from "next/router";
-import Link from "next/link";
-import { LibraryBig, Blocks, BrainCircuit, Computer } from "lucide-react";
-import { AiOutlineGithub } from "react-icons/ai";
-import { BiLogoDiscordAlt } from "react-icons/bi";
-import { RiTwitterXFill } from "react-icons/ri";
+import React, { Fragment } from 'react'
+import { useConfig, DocsThemeConfig } from 'nextra-theme-docs'
+import LogoMark from '@/components/LogoMark'
+import FooterMenu from '@/components/FooterMenu'
+import JSONLD from '@/components/JSONLD'
+import { useRouter } from 'next/router'
+import Link from 'next/link'
+import { LibraryBig, Blocks, BrainCircuit, Computer } from 'lucide-react'
+import { AiOutlineGithub } from 'react-icons/ai'
+import { BiLogoDiscordAlt } from 'react-icons/bi'
+import { RiTwitterXFill } from 'react-icons/ri'
+import Navbar from '@/components/Navbar'
-const defaultUrl = "https://jan.ai";
-const defaultImage = "https://jan.ai/assets/images/general/og-image.png";
+const defaultUrl = 'https://jan.ai'
+const defaultImage = 'https://jan.ai/assets/images/general/og-image.png'
const structuredData = {
- "@context": "https://schema.org",
- "@type": "Organization",
- name: "Jan",
- url: `${defaultUrl}`,
- logo: `${defaultImage}`,
-};
+ '@context': 'https://schema.org',
+ '@type': 'Organization',
+ 'name': 'Jan',
+ 'url': `${defaultUrl}`,
+ 'logo': `${defaultImage}`,
+}
const config: DocsThemeConfig = {
logo: (
@@ -30,59 +31,47 @@ const config: DocsThemeConfig = {
),
- docsRepositoryBase: "https://github.com/menloresearch/jan/tree/dev/docs",
+ docsRepositoryBase: 'https://github.com/menloresearch/jan/tree/dev/docs',
feedback: {
- content: "Question? Give us feedback →",
- labels: "feedback",
+ content: 'Question? Give us feedback →',
+ labels: 'feedback',
},
editLink: {
- text: "Edit this page on GitHub →",
+ text: 'Edit this page on GitHub →',
},
useNextSeoProps() {
return {
- titleTemplate: "%s - Jan",
+ titleTemplate: '%s - Jan',
twitter: {
- cardType: "summary_large_image",
- site: "@jandotai",
+ cardType: 'summary_large_image',
+ site: '@jandotai',
},
openGraph: {
- type: "website",
+ type: 'website',
},
- };
+ }
},
navbar: {
- extraContent: (
-
{(() => {
const items = [
{
- title: "Jan Desktop & Mobile",
- path: "/docs/desktop",
+ title: 'Jan Desktop & Mobile',
+ path: '/docs/desktop',
Icon: LibraryBig,
},
- { title: "Jan Server", path: "/docs/server", Icon: Computer },
- ];
+ { title: 'Jan Server', path: '/docs/server', Icon: Computer },
+ ]
return items.map((item) => {
- const active = asPath.startsWith(item.path);
+ const active = asPath.startsWith(item.path)
return active ? (
{item.title}
- );
- });
+ )
+ })
})()}
- );
+ )
}
- return title;
+ return title
},
defaultMenuCollapseLevel: 1,
toggleButton: true,
},
+ darkMode: false,
toc: {
backToTop: true,
},
head: function useHead() {
- const { title, frontMatter } = useConfig();
- const titleTemplate = (frontMatter?.title || title) + " - " + "Jan";
- const { asPath } = useRouter();
+ const { title, frontMatter } = useConfig()
+ const titleTemplate = (frontMatter?.title || title) + ' - ' + 'Jan'
+ const { asPath } = useRouter()
return (