'use client' import { Button } from '@/components/button' import { Container } from '@/components/container' import { Footer } from '@/components/footer' import { Gradient, GradientBackground } from '@/components/gradient' import { Link } from '@/components/link' import { Mark } from '@/components/logo' import { Navbar } from '@/components/navbar' import { Heading, Lead, Subheading } from '@/components/text' import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react' import { CheckIcon, ChevronUpDownIcon, MinusIcon, } from '@heroicons/react/16/solid' import { useSearchParams } from 'next/navigation' import type React from 'react' function DropLogo() { return (
) } function GameVaultLogo() { return (
GameVault Logo GameVault
) } function GameVaultPlus() { return (
GameVault+ icon GameVault+
) } function ComingSoon() { return (
coming soon™
) } function RomMLogo() { return (
RomM icon RomM workmark
) } const projects: Array<{ name: string slug: string logo: () => React.JSX.Element description: string href: string highlights: Array<{ description: string; disabled?: boolean; paid?: boolean }> features: { [key: string]: { [key: string]: number | string | boolean | (() => React.JSX.Element) } } }> = [ { name: 'Drop OSS' as const, slug: 'drop', logo: DropLogo, description: 'An open-source and free self-hosted Steam alternative.', href: '/', highlights: [ { description: 'First-class Linux support' }, { description: 'Game versioning' }, { description: 'Multiple metadata sources' }, { description: 'Cloud saves & playtime tracking', disabled: true }, { description: 'Overlay network for Steam-like play together', disabled: true, }, ], features: { Library: { 'Multiple libraries': true, 'Versioned layout': true, 'Non-versioned layout': true, 'Installer/setup games': true, 'Portable games': true, 'Archives support': '.zip', }, Metadata: { IGDB: true, GiantBomb: true, PCGamingWiki: true, Manual: true, }, Clients: { Windows: true, Linux: true, macOS: true, Android: ComingSoon, }, Authentication: { Simple: true, SSO: true, }, Cloud: { 'Cloud saves': ComingSoon, 'Steamworks-compatible networking': ComingSoon, 'Dedicated server discovery': ComingSoon, }, 'Client Features': { 'Proton compatible for Linux': true, 'Multi-server': ComingSoon, 'In-game overlay': ComingSoon, }, Additional: { 'User collections': true, 'Server news': true, }, }, }, { name: 'GameVault' as const, slug: 'gamevault', logo: GameVaultLogo, description: 'A source-available, mature Steam-like experience for your home server.', href: 'https://gamevau.lt/', highlights: [ { description: 'Native Windows app' }, { description: 'Published on Microsoft Store' }, { description: 'Playtime tracking' }, { description: 'Cloud saves', paid: true }, { description: 'Third-party integrations', paid: true }, ], features: { Library: { 'Multiple libraries': 'Using Docker volumes or symlinks', 'Automatic import': true, 'Non-versioned layout': true, 'Installer/setup games': true, 'Portable games': true, 'Archives support': '.7z .xz .bz2 .gz .tar .zip .wim .ar .arj .cab .chm .cpio .cramfs .dmg .ext .fat .gpt .hfs .ihex .iso .lzh .lzma .mbr .msi .nsis .ntfs .qcow2 .rar .rpm .squashfs .udf .uefi .vdi .vhd .vmdk .wim .xar .z' .split(' ') .sort() .join(' '), }, Metadata: { IGDB: true, Manual: true, }, Clients: { Windows: true, Linux: 'Possible, unsupported', macOS: 'Possible, unsupported', }, Authentication: { Simple: true, SSO: true, }, Cloud: { 'Cloud saves': GameVaultPlus, }, 'Client Features': { Theming: GameVaultPlus, 'Multi-profile usage': GameVaultPlus, 'Playnite integration': GameVaultPlus, 'Steam integration': GameVaultPlus, 'Discord integration': GameVaultPlus, }, Additional: { 'Parental controls': true, 'Server news': true, }, }, }, { name: 'RomM' as const, slug: 'romm', logo: RomMLogo, description: 'An open-source, self-hosted rom manager, with built-in large emulator support.', href: 'https://romm.app/', highlights: [ { description: '400+ supported platforms' }, { description: 'Web-based (EmulatorJS) emulation' }, { description: 'Multiple metadata sources' }, { description: 'Android app' }, { description: 'Cloud sync', disabled: true }, ], features: { Library: { 'Non-versioned layout': true, }, Metadata: { IGDB: true, Hasheous: true, SteamGridDB: true, Retroachievements: true, PlayMatch: true, ScreenScraper: true, LaunchBox: true, }, Clients: { Browser: true, Android: true, muOS: true, }, Authentication: { Simple: true, SSO: true, }, Cloud: { 'Cloud saves': ComingSoon, }, }, }, ] function Header() { return ( What's the{' '} git diff ? A breakdown between the different projects available to you, put together by the Drop OSS project. Last updated 02-09-2025 ) } function PricingCards() { return (
{projects.map((tier, tierIndex) => ( ))}
) } function PricingCard({ tier }: { tier: (typeof projects)[number] }) { return (
{tier.logo()}
{tier.name}

{tier.description}

Key features:

    {tier.highlights.map((props, featureIndex) => ( ))}
) } function PricingTable({ selectedTier: selectedProject, }: { selectedTier: (typeof projects)[number] }) { function onlyUnique(value: T, index: number, array: Array) { return array.indexOf(value) === index } const sections = projects .map((e) => Object.keys(e.features)) .flat() .filter(onlyUnique) const features: { [key: string]: string[] } = {} for (const section of sections) { const uniqueFeatures = projects .filter((e) => e.features[section]) .map((e) => Object.keys(e.features[section])) .flat() .filter(onlyUnique) features[section] = uniqueFeatures } return ( ))} {projects.map((tier) => ( ))} {sections.map((section) => ( {features[section].map((name) => ( {projects.map((project) => { let value = project.features[section]?.[name] return ( ) })} ))} ))}
Pricing plan comparison
{projects.map((project) => ( {project.name}
{selectedProject.name} {projects.map((tier) => ( {tier.name} ))}
Get started
{section}
{name} {typeof value === 'function' ? ( <>{value()} ) : value === true ? ( <> Included in {project.name} ) : value === false || value === undefined ? ( <> Not included in {project.name} ) : (
{value}
)}
) } function FeatureItem({ description, disabled = false, paid = false, }: { description: string disabled?: boolean paid?: boolean }) { return (
  • {disabled && Coming soon:} {description} {disabled && ( coming soon™ )} {paid && }
  • ) } function PlusIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( ) } export default function Pricing() { let params = useSearchParams() let tier = typeof params.get('tier') === 'string' ? projects.find(({ slug }) => slug === params.get('tier'))! : projects[0] return (
    ) }