feat: hosted-first landing + accurate fair source licensing copy

- Replace unsubstantiated hero claim with client sign-off messaging
- Rename Open Source (Self-hosted) to Fair Source (Self-hosted) with FSL
  explanation (source visible, self-hostable, Apache 2.0 after two years)
- Put Hosted Cloud first in pricing with Recommended badge and trial note
- Move self-hosting hero link to GitHub, out of primary CTA path
- Add FAQ entries for FSL licensing and 7-day free trial
- Align license language across landing, README, terms, SEO, comparisons
- Fix contact email to [email protected] everywhere (mailto links,
  notification sender fallbacks) and SEO fallback domain
This commit is contained in:
yusufipk
2026-07-12 18:32:38 +07:00
parent 5821f73d38
commit 6c6df3cf1d
10 changed files with 118 additions and 76 deletions
+5
View File
@@ -208,6 +208,10 @@ bun run check
Feature flags and self-hosting environment variables are documented in `.env.example` and `.env.docker.example`.
## License
OpenFrame is Fair Source, licensed under the [Functional Source License](https://fsl.software/) (FSL-1.1-ALv2). The full source code is publicly available, you can self-host it, and every release automatically becomes Apache 2.0 open source two years after its publication. See [LICENCE](LICENCE) for the full terms.
## Contributing
Contributions are welcome.
@@ -215,3 +219,4 @@ Contributions are welcome.
- Read [CONTRIBUTING.md](CONTRIBUTING.md) for workflow, conventions, and PR requirements.
- Use [SECURITY.md](SECURITY.md) for responsible vulnerability reporting.
- Follow [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) in all project interactions.
- Contact: [[email protected]](mailto:[email protected])
+1 -1
View File
@@ -193,7 +193,7 @@ export async function POST(request: NextRequest) {
const fromAddress =
process.env.SMTP_FROM ||
process.env.EMAIL_FROM ||
'OpenFrame <notifications@openframe.app>';
'OpenFrame <info@open-frame.net>';
try {
await transporter.sendMail({
+7 -3
View File
@@ -150,7 +150,8 @@ export default function TermsOfServicePage() {
<li>Interfere with or disrupt the integrity or performance of the Service.</li>
<li>
Reverse engineer, decompile, or attempt to extract the source code of the Service
(except where permitted by applicable open-source licenses).
(except where permitted by the applicable source license, such as the Functional
Source License covering the platform code).
</li>
<li>Use the Service to send spam or unsolicited communications.</li>
<li>
@@ -174,8 +175,11 @@ export default function TermsOfServicePage() {
intellectual property laws.
</p>
<p className="mt-3">
The core platform code is made available as open-source software; please refer to the
applicable license in the GitHub repository for details on permitted use.
The core platform code is made available under the Functional Source License
(FSL-1.1-ALv2): the source code is publicly available and may be self-hosted, and
each release becomes available under the Apache 2.0 license two years after its
publication. Please refer to the license in the GitHub repository for details on
permitted use.
</p>
</section>
+92 -60
View File
@@ -234,14 +234,14 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-primary"></span>
</span>
<span className="font-mono tracking-wide uppercase">Open Source Video Review</span>
<span className="font-mono tracking-wide uppercase">Fair Source Video Review</span>
</div>
<h1
data-hero-copy
className="text-4xl font-semibold leading-[0.95] tracking-[-0.03em] sm:text-5xl md:text-6xl lg:text-7xl"
>
Cut Video Approval Time in Half. <br className="hidden md:block" />
Get Client Sign-off From One Link. <br className="hidden md:block" />
<span className="text-muted-foreground">Stop Chasing Timecodes.</span>
</h1>
@@ -249,27 +249,35 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
data-hero-copy
className="mx-auto max-w-2xl text-base text-muted-foreground md:text-xl"
>
OpenFrame puts comments, voice notes, and annotations on a single timeline so clients
say &quot;yes&quot; faster and your team stops guessing.
Hosted video review for editors, agencies, and small studios. Comments, voice notes,
and annotations land on one timeline clients review in the browser, no account
needed.
</p>
<div
data-hero-copy
className="mx-auto flex max-w-md flex-col items-center justify-center gap-2"
className="mx-auto flex max-w-md flex-col items-center justify-center gap-3"
>
<Link
href={hostedCtaHref}
className="group relative isolate inline-flex h-12 min-w-max items-center justify-center overflow-hidden border border-primary bg-primary px-10 text-sm font-medium whitespace-nowrap text-primary-foreground transition-transform duration-300 hover:scale-[1.02]"
>
Start free
Start free trial
<MoveRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Link>
<p className="text-xs text-muted-foreground">
7-day free trial · Flat $10/mo no per-seat fees · No client accounts
</p>
<a
href="#pricing"
className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
className="text-xs font-medium text-muted-foreground/70 transition-colors hover:text-foreground"
>
Prefer self-hosting? <ArrowRight className="ml-1 inline h-3.5 w-3.5" />
Prefer self-hosting? View on GitHub{' '}
<ArrowRight className="ml-1 inline h-3 w-3" />
</a>
</div>
</div>
@@ -644,70 +652,33 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
className="text-3xl font-semibold md:text-5xl text-foreground"
style={{ fontFamily: 'monospace', letterSpacing: '-0.02em' }}
>
Deploy it yourself - or let us run it for you.
Let us run it for you - or deploy it yourself.
</h2>
</div>
<div className="grid gap-6 md:grid-cols-3">
{/* Card 1: Open Source */}
<div
data-reveal
className="relative flex flex-col border border-border/40 bg-[#141414] p-8"
>
<div className="mb-6">
<h3 className="text-xl font-semibold text-foreground">
Open Source (Self-hosted)
</h3>
</div>
<div className="mb-8 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">Free</span>
</div>
<p className="mb-8 text-sm text-muted-foreground">
For teams who want full control and can run their own infrastructure.
</p>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-center gap-3">
<CheckSquare className="h-4 w-4 text-[#06b6d4]" />
Full codebase access
</li>
<li className="flex items-center gap-3">
<CheckSquare className="h-4 w-4 text-[#06b6d4]" />
Self-hosted infrastructure control
</li>
<li className="flex items-center gap-3">
<CheckSquare className="h-4 w-4 text-[#06b6d4]" />
Manual update cadence
</li>
</ul>
<a
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden border border-border/50 bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 text-sm"
>
<Github className="mr-2 h-4 w-4" /> View on GitHub
</a>
</div>
{/* Card 2: Hosted Cloud */}
{/* Card 1: Hosted Cloud (recommended) */}
<div
data-reveal
className="relative flex flex-col border border-[#06b6d4]/40 bg-[#141414] p-8"
>
<span className="absolute -top-3 left-8 bg-[#06b6d4] px-2 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-widest text-black">
Recommended
</span>
<div className="mb-6">
<p className="font-mono text-[10px] uppercase font-semibold text-muted-foreground tracking-widest mb-4">
Best for teams who want zero setup.
Zero setup. Flat pricing, no per-seat fees.
</p>
<h3 className="text-xl font-semibold text-foreground">Hosted Cloud</h3>
</div>
<div className="mb-6 flex items-baseline gap-2">
<div className="mb-2 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">$10</span>
<span className="text-[#06b6d4]">/ month</span>
</div>
<p className="mb-6 text-sm text-muted-foreground">
Starts with a 7-day free trial. Cancel anytime.
</p>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-start gap-3">
@@ -751,10 +722,63 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
href={hostedCtaHref}
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#06b6d4] font-medium text-black transition-colors hover:bg-[#06b6d4]/90 text-sm"
>
Start free
Start free trial
</Link>
</div>
{/* Card 2: Fair Source (Self-hosted) */}
<div
data-reveal
className="relative flex flex-col border border-border/40 bg-[#141414] p-8"
>
<div className="mb-6">
<h3 className="text-xl font-semibold text-foreground">
Fair Source (Self-hosted)
</h3>
</div>
<div className="mb-8 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">Free</span>
</div>
<p className="mb-8 text-sm text-muted-foreground">
For teams who want full control and can run their own infrastructure. Licensed
under the{' '}
<a
href="https://fsl.software/"
target="_blank"
rel="noreferrer"
className="underline underline-offset-2 hover:text-foreground"
>
Functional Source License
</a>
.
</p>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 h-4 w-4 shrink-0 text-[#06b6d4]" />
Full source code read it, audit it
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 h-4 w-4 shrink-0 text-[#06b6d4]" />
Self-host on your own infrastructure
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 h-4 w-4 shrink-0 text-[#06b6d4]" />
Every release becomes Apache 2.0 open source after two years
</li>
</ul>
<a
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden border border-border/50 bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 text-sm"
>
<Github className="mr-2 h-4 w-4" /> View on GitHub
</a>
</div>
{/* Card 3: Studio & Agency */}
<div
data-reveal
@@ -775,7 +799,7 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
</p>
<a
href="mailto:support@openframe.com"
href="mailto:info@open-frame.net"
className="group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 border border-border/50 text-sm"
>
Contact us
@@ -823,7 +847,15 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
},
{
q: 'Can I self-host?',
a: 'Yes. The core is open-source and self-hostable. Hosted Cloud is for teams who want zero setup.',
a: 'Yes. The full source code is public and ships with a Docker setup for self-hosting. Hosted Cloud is for teams who want zero setup.',
},
{
q: 'Is OpenFrame open source?',
a: 'OpenFrame is Fair Source, licensed under the Functional Source License (FSL). You can read and audit the full source code and self-host it, and every release automatically becomes Apache 2.0 open source two years after publication.',
},
{
q: 'Is there a free trial?',
a: 'Yes. Hosted Cloud starts with a 7-day free trial. After that it is a flat $10/mo — no per-seat or per-client fees.',
},
{
q: 'How is this different from sending a Google Drive link?',
@@ -874,7 +906,7 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
href={hostedCtaHref}
className="group relative isolate inline-flex h-12 min-w-max items-center justify-center overflow-hidden border border-primary bg-primary px-10 text-sm font-medium whitespace-nowrap text-primary-foreground transition-transform duration-300 hover:scale-[1.02] md:min-w-[240px]"
>
Start free
Start free trial
</Link>
</div>
</section>
+1 -1
View File
@@ -111,7 +111,7 @@ export async function sendVerificationEmail(email: string, token: string): Promi
const verifyUrl = `${baseUrl}/api/auth/verify-email?token=${encodeURIComponent(token)}`;
const from =
process.env.SMTP_FROM || process.env.EMAIL_FROM || 'OpenFrame <notifications@openframe.app>';
process.env.SMTP_FROM || process.env.EMAIL_FROM || 'OpenFrame <info@open-frame.net>';
const html = brandedEmailTemplate(
`
+1 -1
View File
@@ -68,7 +68,7 @@ export async function sendInvitationEmail(input: {
}
const fromAddress =
process.env.SMTP_FROM || process.env.EMAIL_FROM || 'OpenFrame <notifications@openframe.app>';
process.env.SMTP_FROM || process.env.EMAIL_FROM || 'OpenFrame <info@open-frame.net>';
const subject = `[OpenFrame] You were invited to a ${scopeLabel(input.scope)}: ${input.targetName}`;
const html = invitationEmailTemplate({
inviterName: input.inviterName,
+4 -4
View File
@@ -202,7 +202,7 @@ export const comparisonPages: ComparisonPageDefinition[] = [
title: 'Frame.io Alternative for Small Teams',
metaDescription:
'Compare OpenFrame vs Frame.io for freelancers and small teams. Get timestamped review, approvals, guest links, and self-hosting without per-seat enterprise pricing.',
keywords: ['frame.io alternative', 'frame io alternative', 'open source frame.io alternative'],
keywords: ['frame.io alternative', 'frame io alternative', 'fair source frame.io alternative'],
headline: 'Frame.io power without the enterprise bill',
subheadline:
'Frame.io is the industry standard for large post teams. OpenFrame gives freelancers and small studios the review workflow they actually need: one link, one timeline, clear approvals, and optional self-hosting.',
@@ -249,7 +249,7 @@ export const comparisonPages: ComparisonPageDefinition[] = [
keywords: [
'self hosted frame.io alternative',
'self-hosted video review',
'open source video review',
'fair source video review',
],
eyebrow: 'Self-hosted review',
headline: 'Keep client footage on your infrastructure',
@@ -270,7 +270,7 @@ export const comparisonPages: ComparisonPageDefinition[] = [
bestForOpenFrame: [
'Teams with Docker ops capacity',
'Privacy-sensitive client work',
'Studios comparing Frame.io to open/fair-source options',
'Studios comparing Frame.io to fair-source options',
],
bestForCompetitor: [
'Teams needing Adobe enterprise integrations out of the box',
@@ -297,7 +297,7 @@ export const comparisonPages: ComparisonPageDefinition[] = [
{ label: 'Version compare', openframe: 'yes', competitor: 'yes' },
{ label: 'Enterprise DRM / SSO', openframe: 'no', competitor: 'yes' },
{ label: 'Adobe NLE integrations', openframe: 'no', competitor: 'yes' },
{ label: 'Open/fair-source codebase', openframe: 'yes', competitor: 'no' },
{ label: 'Fair-source codebase', openframe: 'yes', competitor: 'no' },
],
pricingRows: [
{ label: 'Self-hosted software cost', openframe: 'Free', competitor: 'Not available' },
+1 -1
View File
@@ -565,7 +565,7 @@ export const openFrameProfile = {
],
bestFor: [
'Freelancers and small teams shipping client cuts',
'Studios that want open/fair-source and optional self-hosting',
'Studios that want fair-source licensing and optional self-hosting',
'Teams tired of vague email and WhatsApp feedback',
],
};
+1 -1
View File
@@ -84,7 +84,7 @@ function createSmtpTransport() {
async function sendEmail(to: string, subject: string, html: string): Promise<boolean> {
const transporter = createSmtpTransport();
const fromAddress =
process.env.SMTP_FROM || process.env.EMAIL_FROM || 'OpenFrame <notifications@openframe.app>';
process.env.SMTP_FROM || process.env.EMAIL_FROM || 'OpenFrame <info@open-frame.net>';
if (!transporter) {
console.warn('SMTP not configured — skipping email notification');
+5 -4
View File
@@ -1,4 +1,4 @@
const FALLBACK_SITE_URL = 'https://openframe.net';
const FALLBACK_SITE_URL = 'https://open-frame.net';
function normalizeSiteUrl(rawUrl: string | undefined): string {
if (!rawUrl) {
@@ -26,11 +26,12 @@ export function getSiteUrl(): string {
export const seoConfig = {
name: 'OpenFrame',
title: 'Open Source Video Review Platform',
title: 'Fair Source Video Review Platform',
description:
'OpenFrame is an open source video review platform for collecting timestamped feedback with text and voice comments.',
'OpenFrame is a fair source video review platform for collecting timestamped feedback with text and voice comments.',
keywords: [
'open source video review platform',
'fair source video review platform',
'video review platform',
'video review tool',
'timestamped video feedback',
'video collaboration',