openvibers/openvibe.games Commits
Read the Games pages' descriptions, and give the leaderboard its canonical and card (#249)
Changes
@@@ -4,10 +4,18 @@<meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Leaderboard · OpenVibe.Games</title>-- <meta-- name="description"-- content="OpenVibe.Games leaderboards: Salvage Rush best rounds and Scraplandia haul points, all time and this week. Scores come only from what the server played out."-- />++ <meta name="description" content="OpenVibe.Games leaderboards: Salvage Rush best rounds and Scraplandia haul points, all time and this week. Scores come only from what the server played out." />++ <link rel="canonical" href="https://openvibe.games/leaderboard.html" />++ <meta property="og:type" content="website" />++ <meta property="og:site_name" content="OpenVibe.Games" />++ <meta property="og:title" content="Leaderboard · OpenVibe.Games" />++ <meta property="og:description" content="OpenVibe.Games leaderboards: Salvage Rush best rounds and Scraplandia haul points, all time and this week. Scores come only from what the server played out." />++ <meta property="og:url" content="https://openvibe.games/leaderboard.html" />++ <meta property="og:image" content="https://openvibe.games/og-image.png" />++ <meta property="og:image:width" content="1200" />++ <meta property="og:image:height" content="630" />++ <meta name="twitter:card" content="summary_large_image" />++ <meta name="twitter:image" content="https://openvibe.games/og-image.png" /><!-- The reader's theme, before the first paint: the page's own light rules follow it. --><script src="/shared/theme-loader.js"></script><style>@@@ -5,10 +5,7 @@<meta name="viewport" content="width=device-width, initial-scale=1" /><link rel="icon" type="image/svg+xml" href="/favicon.svg" /><title>Scraplandia — OpenVibe.Games</title>-- <meta-- name="description"-- content="Play Scraplandia: scrappy multiplayer survival-building in and around Scrap City, in your browser, no download. Part of the OpenVibe network."-- />++ <meta name="description" content="Play Scraplandia: scrappy multiplayer survival-building in and around Scrap City, in your browser, no download. Part of the OpenVibe network." /><!-- The OpenVibe Frame: the user's theme before first paint, then navbar + footer. --><script src="/shared/theme-loader.js"></script><script src="/shared/navbar.js" defer></script>nnew file mode 100644@@@ -0,0 +1,33 @@++/**++ * The pages outside the game client's router are still read by search engines and share cards:++ * each names a one-line meta description of 120–160 characters, and the leaderboard (linked from++ * the game and the portal) names its own canonical URL and the site's og:image, the card the home++ * uses. The description is one line so a plain line-based crawler sees it too.++ */++import { readFileSync } from 'node:fs'++import { fileURLToPath } from 'node:url'++import { describe, expect, it } from 'vitest'++++const client = (path: string) => fileURLToPath(new URL(`../../${path}`, import.meta.url))++const html = (page: string) => readFileSync(client(page), 'utf8')++const description = (page: string) =>++ /<meta name="description" content="([^"]*)" \/>/.exec(html(page))?.[1] ?? ''++++describe('page metadata', () => {++ it.each(['play.html', 'worlds.html', 'leaderboard.html'])(++ '%s has a one-line description of 120 to 160 characters',++ (page) => {++ const d = description(page)++ expect(d).not.toBe('')++ expect(d.length).toBeGreaterThanOrEqual(120)++ expect(d.length).toBeLessThanOrEqual(160)++ expect(html(page)).toContain(`<meta name="description" content="${d}" />`)++ },++ )++++ it('leaderboard.html names its canonical URL and the site card', () => {++ const page = html('leaderboard.html')++ expect(page).toContain('<link rel="canonical" href="https://openvibe.games/leaderboard.html" />')++ expect(page).toContain('<meta property="og:image" content="https://openvibe.games/og-image.png" />')++ })++})@@@ -4,10 +4,7 @@<meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Creator worlds · OpenVibe.Games</title>-- <meta-- name="description"-- content="Build your own 3D world in the OpenVibe.Games map editor and publish it for anyone to join in the browser. Browse the worlds players made."-- />++ <meta name="description" content="Build your own 3D world in the OpenVibe.Games map editor and publish it for anyone to join in the browser. Browse the worlds players made." /><link rel="canonical" href="https://openvibe.games/worlds" /><meta property="og:type" content="website" /><meta property="og:site_name" content="OpenVibe.Games" />nnew file mode 100644@@@ -0,0 +1,3 @@++// file: 'apps/client/src/pages/pageMeta.test.ts'++// covers: 'apps/client/src/pages'++// Generated by node test/run.js --index; do not edit.
@@ -4,10 +4,18 @@
@@ -4,10 +4,18 @@
<meta charset="UTF-8" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Leaderboard · OpenVibe.Games</title>
<title>Leaderboard · OpenVibe.Games</title>
- <meta
- name="description"
- content="OpenVibe.Games leaderboards: Salvage Rush best rounds and Scraplandia haul points, all time and this week. Scores come only from what the server played out."
- />
+ <meta name="description" content="OpenVibe.Games leaderboards: Salvage Rush best rounds and Scraplandia haul points, all time and this week. Scores come only from what the server played out." />
+ <link rel="canonical" href="https://openvibe.games/leaderboard.html" />
+ <meta property="og:type" content="website" />
+ <meta property="og:site_name" content="OpenVibe.Games" />
+ <meta property="og:title" content="Leaderboard · OpenVibe.Games" />
+ <meta property="og:description" content="OpenVibe.Games leaderboards: Salvage Rush best rounds and Scraplandia haul points, all time and this week. Scores come only from what the server played out." />
+ <meta property="og:url" content="https://openvibe.games/leaderboard.html" />
+ <meta property="og:image" content="https://openvibe.games/og-image.png" />
+ <meta property="og:image:width" content="1200" />
+ <meta property="og:image:height" content="630" />
+ <meta name="twitter:card" content="summary_large_image" />
+ <meta name="twitter:image" content="https://openvibe.games/og-image.png" />
<!-- The reader's theme, before the first paint: the page's own light rules follow it. -->
<!-- The reader's theme, before the first paint: the page's own light rules follow it. -->
<script src="/shared/theme-loader.js"></script>
<script src="/shared/theme-loader.js"></script>
<style>
<style>
@@ -5,10 +5,7 @@
@@ -5,10 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Scraplandia — OpenVibe.Games</title>
<title>Scraplandia — OpenVibe.Games</title>
- <meta
- name="description"
- content="Play Scraplandia: scrappy multiplayer survival-building in and around Scrap City, in your browser, no download. Part of the OpenVibe network."
- />
+ <meta name="description" content="Play Scraplandia: scrappy multiplayer survival-building in and around Scrap City, in your browser, no download. Part of the OpenVibe network." />
<!-- The OpenVibe Frame: the user's theme before first paint, then navbar + footer. -->
<!-- The OpenVibe Frame: the user's theme before first paint, then navbar + footer. -->
<script src="/shared/theme-loader.js"></script>
<script src="/shared/theme-loader.js"></script>
<script src="/shared/navbar.js" defer></script>
<script src="/shared/navbar.js" defer></script>
new file mode 100644
new file mode 100644
@@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
+/**
+ * The pages outside the game client's router are still read by search engines and share cards:
+ * each names a one-line meta description of 120–160 characters, and the leaderboard (linked from
+ * the game and the portal) names its own canonical URL and the site's og:image, the card the home
+ * uses. The description is one line so a plain line-based crawler sees it too.
+ */
+import { readFileSync } from 'node:fs'
+import { fileURLToPath } from 'node:url'
+import { describe, expect, it } from 'vitest'
+
+const client = (path: string) => fileURLToPath(new URL(`../../${path}`, import.meta.url))
+const html = (page: string) => readFileSync(client(page), 'utf8')
+const description = (page: string) =>
+ /<meta name="description" content="([^"]*)" \/>/.exec(html(page))?.[1] ?? ''
+
+describe('page metadata', () => {
+ it.each(['play.html', 'worlds.html', 'leaderboard.html'])(
+ '%s has a one-line description of 120 to 160 characters',
+ (page) => {
+ const d = description(page)
+ expect(d).not.toBe('')
+ expect(d.length).toBeGreaterThanOrEqual(120)
+ expect(d.length).toBeLessThanOrEqual(160)
+ expect(html(page)).toContain(`<meta name="description" content="${d}" />`)
+ },
+ )
+
+ it('leaderboard.html names its canonical URL and the site card', () => {
+ const page = html('leaderboard.html')
+ expect(page).toContain('<link rel="canonical" href="https://openvibe.games/leaderboard.html" />')
+ expect(page).toContain('<meta property="og:image" content="https://openvibe.games/og-image.png" />')
+ })
+})
@@ -4,10 +4,7 @@
@@ -4,10 +4,7 @@
<meta charset="UTF-8" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Creator worlds · OpenVibe.Games</title>
<title>Creator worlds · OpenVibe.Games</title>
- <meta
- name="description"
- content="Build your own 3D world in the OpenVibe.Games map editor and publish it for anyone to join in the browser. Browse the worlds players made."
- />
+ <meta name="description" content="Build your own 3D world in the OpenVibe.Games map editor and publish it for anyone to join in the browser. Browse the worlds players made." />
<link rel="canonical" href="https://openvibe.games/worlds" />
<link rel="canonical" href="https://openvibe.games/worlds" />
<meta property="og:type" content="website" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="OpenVibe.Games" />
<meta property="og:site_name" content="OpenVibe.Games" />
new file mode 100644
new file mode 100644
@@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
+// file: 'apps/client/src/pages/pageMeta.test.ts'
+// covers: 'apps/client/src/pages'
+// Generated by node test/run.js --index; do not edit.