mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 09:36:08 +00:00
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:
@@ -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])
|
||||
|
||||
@@ -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
@@ -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
@@ -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 "yes" 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>
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -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
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user