Skip to content

Commit f6f74c6

Browse files
committed
feat(website): full SEO pass + upstream lineage in the footer
The site was already well built for speed — no web fonts, no third-party requests, ~147 KB gzipped on the critical path — but shipped almost no SEO surface beyond Docusaurus's defaults. Everything below was measured against a production build, not inferred. Every canonical URL pointed at a redirect. GitHub Pages 301s the extensionless form to the trailing-slash one (verified against the live site: /docs/intro -> 301 -> /docs/intro/), while Docusaurus advertised the pre-redirect form in both <link rel="canonical"> and sitemap.xml. trailingSlash: true declares the URL that is actually served. The landing page's <title> was the bare string "OpenScreen" — ten characters, no keywords, on the page most likely to rank. No page carried a description in frontmatter, so Docusaurus derived one from the first paragraph. Five of ten overflowed Google's ~160-character snippet and were truncated mid-sentence; docs/intro ran to 371. All nine docs now have a hand-written description, 156 characters at the longest. og-image.png was 512x512. Docusaurus hardcodes twitter:card as summary_large_image, which expects 1.91:1, so every share on X, LinkedIn, Discord and Slack was cropped or downgraded to a small square. Replaced with a 1200x630 card built from the same app icon (229 KB -> 78 KB). There was no robots.txt — Docusaurus emits none — so sitemap.xml was only discoverable by submitting it in Search Console by hand. No og:type or og:site_name either, which Docusaurus never emits and without which Facebook and LinkedIn fall back to a bare link preview. No sitemap lastmod, off by default in v3. Structured data was limited to the BreadcrumbList Docusaurus adds to docs pages. Organization and WebSite are now emitted site-wide, and a SoftwareApplication entity on the landing page only — with offers at price 0, which is what lets a result carry a "Free" annotation. Also fixes layout shift: the navbar and footer logos had no intrinsic width/height, so the bar reflowed once the PNG decoded. The footer now states the project's lineage on every page, linking the archived original it spun off from (39,859 stars, MIT). The same relationship is mirrored as schema.org sameAs on the Organization entity, so it is machine -readable and not only prose. Verified against a production build: exactly one meta description per page, all ten sitemap URLs trailing-slash and carrying lastmod, every JSON-LD block parsing as valid JSON, robots.txt and apple-touch-icon emitted. typecheck and build both pass with onBrokenLinks and onBrokenAnchors set to throw. Footer checked in a browser at 1280px and 375px — wraps to two lines on mobile with no horizontal overflow. Total build output 1.3 MB -> 0.99 MB.
1 parent 1b340cb commit f6f74c6

16 files changed

Lines changed: 273 additions & 19 deletions

‎website/docs/ai-editing.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
id: ai-editing
33
title: AI editing
44
sidebar_position: 8
5+
description: "Connect your own LLM key to edit OpenScreen projects from a chat panel. Entirely optional and off by default — nothing leaves your machine until you opt in."
6+
keywords:
7+
- AI video editing
8+
- LLM video editor
9+
- chat editing
10+
- bring your own key
11+
- privacy
512
---
613

714
# AI editing

‎website/docs/captions.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
id: captions
33
title: Captions & transcript
44
sidebar_position: 7
5+
description: "Transcribe on-device with Whisper, burn in styled captions, translate them into 15 languages, and edit a recording by deleting words from the text."
6+
keywords:
7+
- automatic captions
8+
- subtitles
9+
- Whisper transcription
10+
- offline transcription
11+
- caption translation
12+
- transcript editing
513
---
614

715
# Captions & transcript

‎website/docs/editing-timeline.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
id: editing-timeline
33
title: Editing & timeline
44
sidebar_position: 6
5+
description: "Edit in OpenScreen's timeline: zoom, trim, and speed regions, Full Camera segments, annotations, cursor styling, and the floating inspector."
6+
keywords:
7+
- video timeline editor
8+
- zoom regions
9+
- speed ramping
10+
- annotations
11+
- cursor smoothing
12+
- multi-track editing
513
---
614

715
# Editing & timeline

‎website/docs/export.md‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
---
22
id: export
3-
title: Export
3+
title: Exporting video
44
sidebar_position: 9
5+
sidebar_label: Export
6+
description: "Export from OpenScreen to MP4 (720p, 1080p, or source resolution, H.264 or H.265) or animated GIF, and how the MP4 render path actually works."
7+
keywords:
8+
- export MP4
9+
- H.264
10+
- H.265
11+
- animated GIF
12+
- video export
13+
- 1080p
514
---
615

716
# Export

‎website/docs/installation.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
id: installation
33
title: Installation
44
sidebar_position: 2
5+
description: "Install OpenScreen on macOS, Windows, or Linux — .dmg, .exe, .deb, .pacman, AppImage, and a Nix flake, including the macOS Gatekeeper step."
6+
keywords:
7+
- install screen recorder
8+
- download OpenScreen
9+
- macOS dmg
10+
- Windows installer
11+
- Linux deb
12+
- AppImage
13+
- Nix flake
514
---
615

716
# Installation

‎website/docs/intro.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
id: intro
33
title: Introduction
44
sidebar_position: 1
5+
description: "OpenScreen is a free, open-source screen recorder and video editor for Windows, macOS, and Linux. Native capture, GPU compositing, MIT licensed."
6+
keywords:
7+
- screen recorder
8+
- open source screen recorder
9+
- free screen recorder
10+
- video editor
11+
- Windows
12+
- macOS
13+
- Linux
514
---
615

716
# Welcome to OpenScreen

‎website/docs/media-library.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
id: media-library
33
title: Media library & clips
44
sidebar_position: 5
5+
description: "Manage sources and clips in OpenScreen: import media, then trim, crop, split, and reorder clips on one timeline, and set the project output size."
6+
keywords:
7+
- media library
8+
- video clips
9+
- trim video
10+
- crop video
11+
- split clips
12+
- timeline
513
---
614

715
# Media library & clips

‎website/docs/quick-start.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
id: quick-start
33
title: Quick start
44
sidebar_position: 3
5+
description: "Record, trim, and export your first video with OpenScreen in six steps — from opening the recording HUD to exporting a finished MP4."
6+
keywords:
7+
- screen recording tutorial
8+
- quick start
9+
- record screen
10+
- trim video
11+
- export MP4
512
---
613

714
# Quick start

‎website/docs/recording.md‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
---
22
id: recording
3-
title: Recording
3+
title: Screen recording
44
sidebar_position: 4
5+
sidebar_label: Recording
6+
description: "Record a window, screen, or region with OpenScreen's HUD — system audio, microphone, webcam, cursor modes, countdown, and native vs. browser capture."
7+
keywords:
8+
- record screen
9+
- window capture
10+
- system audio recording
11+
- webcam recording
12+
- ScreenCaptureKit
13+
- Windows Graphics Capture
514
---
615

716
# Recording

‎website/docusaurus.config.ts‎

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,41 @@ import type * as Preset from "@docusaurus/preset-classic";
22
import type { Config } from "@docusaurus/types";
33
import { themes as prismThemes } from "prism-react-renderer";
44

5+
const SITE_URL = "https://getopenscreen.com";
6+
const REPO_URL = "https://github.com/getopenscreen/openscreen";
7+
const UPSTREAM_REPO_URL = "https://github.com/siddharthvaddem/openscreen";
8+
const DISCORD_URL = "https://discord.gg/VvT6Vtnyh";
9+
10+
// Kept under ~155 characters: past that, Google truncates the snippet mid-word.
11+
const SITE_DESCRIPTION =
12+
"Free, open-source screen recorder and video editor for Windows, macOS, and Linux. Native capture, on-device captions, no watermarks, no subscriptions.";
13+
14+
// Site-wide structured data. Organization + WebSite are true of every page, so
15+
// they belong here; the SoftwareApplication entity describes the product rather
16+
// than the site and is emitted on the landing page only (src/pages/index.tsx),
17+
// because duplicating it under every docs URL is what earns a manual action.
18+
const ORGANIZATION_LD = {
19+
"@context": "https://schema.org",
20+
"@type": "Organization",
21+
"@id": `${SITE_URL}/#organization`,
22+
name: "OpenScreen",
23+
url: SITE_URL,
24+
logo: `${SITE_URL}/img/logo-icon.png`,
25+
description: SITE_DESCRIPTION,
26+
sameAs: [REPO_URL, UPSTREAM_REPO_URL, DISCORD_URL],
27+
};
28+
29+
const WEBSITE_LD = {
30+
"@context": "https://schema.org",
31+
"@type": "WebSite",
32+
"@id": `${SITE_URL}/#website`,
33+
name: "OpenScreen",
34+
url: SITE_URL,
35+
description: SITE_DESCRIPTION,
36+
inLanguage: "en",
37+
publisher: { "@id": `${SITE_URL}/#organization` },
38+
};
39+
540
const STAR_SVG =
641
'<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"/></svg>';
742

@@ -44,41 +79,107 @@ export default async function createConfig(): Promise<Config> {
4479
// Pages serves this from the custom domain's root, not from
4580
// getopenscreen.github.io/openscreen/, so baseUrl has to be "/" — a project
4681
// baseUrl would prefix every asset URL with a path the server has nothing at.
47-
url: "https://getopenscreen.com",
82+
url: SITE_URL,
4883
baseUrl: "/",
4984

85+
// Every page is emitted as <route>/index.html, and GitHub Pages 301s the
86+
// extensionless form to the trailing-slash one. Leaving this unset makes
87+
// Docusaurus advertise the pre-redirect URL in both <link rel="canonical">
88+
// and sitemap.xml, so every indexed URL costs a crawler an extra hop to a
89+
// URL that isn't the one we declared canonical. Declaring the served form
90+
// removes the redirect from the canonical path entirely.
91+
trailingSlash: true,
92+
5093
organizationName: "getopenscreen",
5194
projectName: "openscreen",
5295

5396
onBrokenLinks: "throw",
97+
onBrokenAnchors: "throw",
5498

5599
markdown: {
56100
hooks: {
57101
onBrokenMarkdownLinks: "warn",
58102
},
59103
},
60104

105+
headTags: [
106+
{
107+
tagName: "link",
108+
attributes: {
109+
rel: "apple-touch-icon",
110+
sizes: "180x180",
111+
href: "/img/apple-touch-icon.png",
112+
},
113+
},
114+
{
115+
tagName: "script",
116+
attributes: { type: "application/ld+json" },
117+
innerHTML: JSON.stringify(ORGANIZATION_LD),
118+
},
119+
{
120+
tagName: "script",
121+
attributes: { type: "application/ld+json" },
122+
innerHTML: JSON.stringify(WEBSITE_LD),
123+
},
124+
],
125+
61126
presets: [
62127
[
63128
"@docusaurus/preset-classic",
64129
{
65130
docs: {
66131
sidebarPath: "./sidebars.ts",
67-
editUrl: "https://github.com/getopenscreen/openscreen/tree/main/website/",
132+
editUrl: `${REPO_URL}/tree/main/website/`,
68133
},
69134
blog: false,
70135
theme: {
71136
customCss: "./src/css/custom.css",
72137
},
138+
sitemap: {
139+
// Off by default in Docusaurus 3. Sourced from git history, it
140+
// gives crawlers a real freshness signal per URL instead of one
141+
// undated blob that has to be re-fetched to find out what moved.
142+
lastmod: "date",
143+
changefreq: "weekly",
144+
priority: 0.5,
145+
createSitemapItems: async ({ defaultCreateSitemapItems, ...rest }) => {
146+
const items = await defaultCreateSitemapItems(rest);
147+
// Flat 0.5 everywhere tells a crawler nothing. The landing page
148+
// and the docs entry point are the two URLs worth ranking.
149+
return items.map((item) => {
150+
if (item.url === `${SITE_URL}/`) return { ...item, priority: 1.0 };
151+
if (item.url === `${SITE_URL}/docs/intro/`) return { ...item, priority: 0.8 };
152+
return { ...item, priority: 0.7 };
153+
});
154+
},
155+
},
73156
} satisfies Preset.Options,
74157
],
75158
],
76159

77160
themeConfig: {
78-
// Social cards get the solid app icon, not the transparent mark: an
79-
// og:image with alpha is composited on whatever background the platform
80-
// picks, so a transparent logo turns into a green smear on some clients.
161+
// 1200x630, fully opaque. Docusaurus hardcodes twitter:card as
162+
// summary_large_image, which crops to 1.91:1 — the old square app icon was
163+
// letterboxed or cropped by every client. Opaque also still matters: an
164+
// og:image with alpha gets composited on whatever background the platform
165+
// picks, so a transparent mark turns into a green smear on some clients.
81166
image: "img/og-image.png",
167+
// Docusaurus emits og:title/description/url/image and twitter:card on its
168+
// own, but never og:type or og:site_name — without them Facebook and
169+
// LinkedIn fall back to a bare link preview. The robots directives lift
170+
// Google's default 160-char snippet cap and thumbnail size limit.
171+
metadata: [
172+
{ name: "description", content: SITE_DESCRIPTION },
173+
{
174+
name: "keywords",
175+
content:
176+
"screen recorder, open source screen recorder, free screen recorder, video editor, screen recording software, screen capture, Windows, macOS, Linux, Screen Studio alternative, automatic captions, subtitles, Whisper, MIT license",
177+
},
178+
{ name: "robots", content: "index, follow, max-image-preview:large, max-snippet:-1" },
179+
{ property: "og:type", content: "website" },
180+
{ property: "og:site_name", content: "OpenScreen" },
181+
{ name: "twitter:image:alt", content: "OpenScreen — free, open-source screen recorder" },
182+
],
82183
colorMode: {
83184
defaultMode: "dark",
84185
disableSwitch: false,
@@ -87,8 +188,12 @@ export default async function createConfig(): Promise<Config> {
87188
navbar: {
88189
title: "OpenScreen",
89190
logo: {
90-
alt: "OpenScreen",
191+
// Explicit intrinsic size: without it the navbar reserves no space
192+
// for the mark and the whole bar reflows once the PNG decodes.
193+
alt: "OpenScreen logo",
91194
src: "img/logo-icon.png",
195+
width: 32,
196+
height: 32,
92197
},
93198
items: [
94199
{
@@ -99,28 +204,28 @@ export default async function createConfig(): Promise<Config> {
99204
className: "navbar-link-strong",
100205
},
101206
{
102-
href: "https://github.com/getopenscreen/openscreen/blob/main/ROADMAP.md",
207+
href: `${REPO_URL}/blob/main/ROADMAP.md`,
103208
label: "Roadmap",
104209
position: "left",
105210
},
106211
{
107-
href: "https://discord.gg/VvT6Vtnyh",
212+
href: DISCORD_URL,
108213
label: "Discord",
109214
position: "left",
110215
},
111216
{
112217
type: "html",
113218
position: "right",
114219
value:
115-
'<a class="navbar-github-link" href="https://github.com/getopenscreen/openscreen" target="_blank" rel="noopener noreferrer">' +
220+
`<a class="navbar-github-link" href="${REPO_URL}" target="_blank" rel="noopener noreferrer">` +
116221
'<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 16 4-4-4-4"/><path d="m6 8-4 4 4 4"/><path d="m14.5 4-5 16"/></svg>' +
117222
`GitHub${starBadge}</a>`,
118223
},
119224
{
120225
type: "html",
121226
position: "right",
122227
value:
123-
'<a class="navbar-download-cta" href="https://github.com/getopenscreen/openscreen/releases" target="_blank" rel="noopener noreferrer">' +
228+
`<a class="navbar-download-cta" href="${REPO_URL}/releases" target="_blank" rel="noopener noreferrer">` +
124229
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V3"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/></svg>' +
125230
"Download</a>",
126231
},

0 commit comments

Comments
 (0)