openvibers/openvibe.games Commits
Share the content-hashed Games card (#280)
Changes
@@@ -20,8 +20,11 @@content="Collaborative map editor for Scraplandia on OpenVibe.Games."/><meta property="og:url" content="https://openvibe.games/editor" />-- <meta property="og:image" content="https://openvibe.games/og-image.png" />++ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />++ <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/shared/social/games.jpg?v=a77ab4204f47" /><!-- 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>@@@ -26,7 +26,7 @@content="Play Scraplandia, Salvage Rush or Vibe Heroes in your browser, no download: survival-building in Scrap City, timed scrap-collecting rounds, or an idle hero collector for your phone. One OpenVibe account across the whole network."/><meta property="og:url" content="https://openvibe.games/" />-- <meta property="og:image" content="https://openvibe.games/og-image.png" />++ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="630" /><meta name="twitter:card" content="summary_large_image" />@@@ -35,7 +35,7 @@name="twitter:description"content="Play Scraplandia, Salvage Rush and Vibe Heroes free in your browser, and see what's selling and on sale on Steam."/>-- <meta name="twitter:image" content="https://openvibe.games/og-image.png" />++ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><!-- JSON-LD (WebSite + the game as the site's primary type) is injected as this page is served,built with openvibe-shared/seo so it stays in step with the other OpenVibe sites. --><style>@@@ -11,11 +11,11 @@<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" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><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" />++ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><!-- The reader's theme, before the first paint: the page's own light rules follow it. --><script src="/shared/theme-loader.js"></script><style>@@@ -20,7 +20,7 @@content="Scrappy multiplayer survival-building in and around Scrap City. Physgun anything, weld it to anything else, haul your salvage home. No download."/><meta property="og:url" content="https://play.openvibe.games/" />-- <meta property="og:image" content="https://openvibe.games/og-image.png" />++ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="630" /><meta name="twitter:card" content="summary_large_image" />@@@ -29,7 +29,7 @@name="twitter:description"content="Multiplayer survival-building on the OpenVibe network. In your browser, no download."/>-- <meta name="twitter:image" content="https://openvibe.games/og-image.png" />++ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><script type="application/ld+json">{"@context": "https://schema.org",@@@ -37,7 +37,7 @@"@id": "https://play.openvibe.games/#game","name": "Scraplandia","url": "https://play.openvibe.games/",-- "image": "https://openvibe.games/og-image.png",++ "image": "https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47","description": "Scrappy multiplayer survival-building in and around Scrap City: physgun anything, weld it to anything else, chase supply drops in the wilds and haul your salvage home.","genre": ["Survival", "Sandbox", "Building"],"playMode": "MultiPlayer",@@@ -1,10 +1,11 @@/*** 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.++ * each names a one-line meta description of 120–160 characters, and every page that had the old++ * share image names the site's content-hashed card (openvibe-shared/social), with its size and the++ * Twitter mirror. The description is one line so a plain line-based crawler sees it too.*/import { readFileSync } from 'node:fs'++import { createRequire } from 'node:module'import { fileURLToPath } from 'node:url'import { describe, expect, it } from 'vitest'@@@ -12,6 +13,10 @@ const client = (path: string) => fileURLToPath(new URL(`../../${path}`, import.mconst html = (page: string) => readFileSync(client(page), 'utf8')const description = (page: string) =>/<meta name="description" content="([^"]*)" \/>/.exec(html(page))?.[1] ?? ''++// The server already depends on the pinned openvibe-shared; its social helper is what names the card.++const req = createRequire(new URL('../../../server/package.json', import.meta.url))++const social = req('openvibe-shared/social') as { url(service: string): string | null }++const CARD = `https://openvibe.games${social.url('games')}`describe('page metadata', () => {it.each(['play.html', 'worlds.html', 'leaderboard.html'])(@@@ -25,9 +30,19 @@ describe('page metadata', () => {},)-- it('leaderboard.html names its canonical URL and the site card', () => {++ it('leaderboard.html names its canonical URL', () => {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" />')})++++ it.each(['index.html', 'play.html', 'worlds.html', 'editor.html', 'leaderboard.html'])(++ '%s shares the content-hashed site card',++ (page) => {++ const doc = html(page)++ expect(doc).toContain(`<meta property="og:image" content="${CARD}" />`)++ expect(doc).toContain('<meta property="og:image:width" content="1200" />')++ expect(doc).toContain('<meta property="og:image:height" content="630" />')++ expect(doc).toContain(`<meta name="twitter:image" content="${CARD}" />`)++ },++ )})@@@ -14,11 +14,11 @@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 property="og:url" content="https://openvibe.games/worlds" />-- <meta property="og:image" content="https://openvibe.games/og-image.png" />++ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><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" />++ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" /><link rel="icon" type="image/svg+xml" href="/favicon.svg" /><style>/* The whole page follows the reader's theme (theme-loader.js sets --bg-primary, --text-primary, … on <html>); the dark
@@ -20,8 +20,11 @@
@@ -20,8 +20,11 @@
content="Collaborative map editor for Scraplandia on OpenVibe.Games."
content="Collaborative map editor for Scraplandia on OpenVibe.Games."
/>
/>
<meta property="og:url" content="https://openvibe.games/editor" />
<meta property="og:url" content="https://openvibe.games/editor" />
- <meta property="og:image" content="https://openvibe.games/og-image.png" />
+ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
+ <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:card" content="summary_large_image" />
+ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<!-- 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>
@@ -26,7 +26,7 @@
@@ -26,7 +26,7 @@
content="Play Scraplandia, Salvage Rush or Vibe Heroes in your browser, no download: survival-building in Scrap City, timed scrap-collecting rounds, or an idle hero collector for your phone. One OpenVibe account across the whole network."
content="Play Scraplandia, Salvage Rush or Vibe Heroes in your browser, no download: survival-building in Scrap City, timed scrap-collecting rounds, or an idle hero collector for your phone. One OpenVibe account across the whole network."
/>
/>
<meta property="og:url" content="https://openvibe.games/" />
<meta property="og:url" content="https://openvibe.games/" />
- <meta property="og:image" content="https://openvibe.games/og-image.png" />
+ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:card" content="summary_large_image" />
@@ -35,7 +35,7 @@
@@ -35,7 +35,7 @@
name="twitter:description"
name="twitter:description"
content="Play Scraplandia, Salvage Rush and Vibe Heroes free in your browser, and see what's selling and on sale on Steam."
content="Play Scraplandia, Salvage Rush and Vibe Heroes free in your browser, and see what's selling and on sale on Steam."
/>
/>
- <meta name="twitter:image" content="https://openvibe.games/og-image.png" />
+ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<!-- JSON-LD (WebSite + the game as the site's primary type) is injected as this page is served,
<!-- JSON-LD (WebSite + the game as the site's primary type) is injected as this page is served,
built with openvibe-shared/seo so it stays in step with the other OpenVibe sites. -->
built with openvibe-shared/seo so it stays in step with the other OpenVibe sites. -->
<style>
<style>
@@ -11,11 +11,11 @@
@@ -11,11 +11,11 @@
<meta property="og:title" content="Leaderboard · 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: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:url" content="https://openvibe.games/leaderboard.html" />
- <meta property="og:image" content="https://openvibe.games/og-image.png" />
+ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:image" content="https://openvibe.games/og-image.png" />
+ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<!-- 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>
@@ -20,7 +20,7 @@
@@ -20,7 +20,7 @@
content="Scrappy multiplayer survival-building in and around Scrap City. Physgun anything, weld it to anything else, haul your salvage home. No download."
content="Scrappy multiplayer survival-building in and around Scrap City. Physgun anything, weld it to anything else, haul your salvage home. No download."
/>
/>
<meta property="og:url" content="https://play.openvibe.games/" />
<meta property="og:url" content="https://play.openvibe.games/" />
- <meta property="og:image" content="https://openvibe.games/og-image.png" />
+ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:card" content="summary_large_image" />
@@ -29,7 +29,7 @@
@@ -29,7 +29,7 @@
name="twitter:description"
name="twitter:description"
content="Multiplayer survival-building on the OpenVibe network. In your browser, no download."
content="Multiplayer survival-building on the OpenVibe network. In your browser, no download."
/>
/>
- <meta name="twitter:image" content="https://openvibe.games/og-image.png" />
+ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<script type="application/ld+json">
<script type="application/ld+json">
{
{
"@context": "https://schema.org",
"@context": "https://schema.org",
@@ -37,7 +37,7 @@
@@ -37,7 +37,7 @@
"@id": "https://play.openvibe.games/#game",
"@id": "https://play.openvibe.games/#game",
"name": "Scraplandia",
"name": "Scraplandia",
"url": "https://play.openvibe.games/",
"url": "https://play.openvibe.games/",
- "image": "https://openvibe.games/og-image.png",
+ "image": "https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47",
"description": "Scrappy multiplayer survival-building in and around Scrap City: physgun anything, weld it to anything else, chase supply drops in the wilds and haul your salvage home.",
"description": "Scrappy multiplayer survival-building in and around Scrap City: physgun anything, weld it to anything else, chase supply drops in the wilds and haul your salvage home.",
"genre": ["Survival", "Sandbox", "Building"],
"genre": ["Survival", "Sandbox", "Building"],
"playMode": "MultiPlayer",
"playMode": "MultiPlayer",
@@ -1,10 +1,11 @@
@@ -1,10 +1,11 @@
/**
/**
* The pages outside the game client's router are still read by search engines and share cards:
* 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.
+ * each names a one-line meta description of 120–160 characters, and every page that had the old
+ * share image names the site's content-hashed card (openvibe-shared/social), with its size and the
+ * Twitter mirror. The description is one line so a plain line-based crawler sees it too.
*/
*/
import { readFileSync } from 'node:fs'
import { readFileSync } from 'node:fs'
+import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import { describe, expect, it } from 'vitest'
@@ -12,6 +13,10 @@ const client = (path: string) => fileURLToPath(new URL(`../../${path}`, import.m
@@ -12,6 +13,10 @@ const client = (path: string) => fileURLToPath(new URL(`../../${path}`, import.m
const html = (page: string) => readFileSync(client(page), 'utf8')
const html = (page: string) => readFileSync(client(page), 'utf8')
const description = (page: string) =>
const description = (page: string) =>
/<meta name="description" content="([^"]*)" \/>/.exec(html(page))?.[1] ?? ''
/<meta name="description" content="([^"]*)" \/>/.exec(html(page))?.[1] ?? ''
+// The server already depends on the pinned openvibe-shared; its social helper is what names the card.
+const req = createRequire(new URL('../../../server/package.json', import.meta.url))
+const social = req('openvibe-shared/social') as { url(service: string): string | null }
+const CARD = `https://openvibe.games${social.url('games')}`
describe('page metadata', () => {
describe('page metadata', () => {
it.each(['play.html', 'worlds.html', 'leaderboard.html'])(
it.each(['play.html', 'worlds.html', 'leaderboard.html'])(
@@ -25,9 +30,19 @@ describe('page metadata', () => {
@@ -25,9 +30,19 @@ describe('page metadata', () => {
},
},
)
)
- it('leaderboard.html names its canonical URL and the site card', () => {
+ it('leaderboard.html names its canonical URL', () => {
const page = html('leaderboard.html')
const page = html('leaderboard.html')
expect(page).toContain('<link rel="canonical" href="https://openvibe.games/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" />')
})
})
+
+ it.each(['index.html', 'play.html', 'worlds.html', 'editor.html', 'leaderboard.html'])(
+ '%s shares the content-hashed site card',
+ (page) => {
+ const doc = html(page)
+ expect(doc).toContain(`<meta property="og:image" content="${CARD}" />`)
+ expect(doc).toContain('<meta property="og:image:width" content="1200" />')
+ expect(doc).toContain('<meta property="og:image:height" content="630" />')
+ expect(doc).toContain(`<meta name="twitter:image" content="${CARD}" />`)
+ },
+ )
})
})
@@ -14,11 +14,11 @@
@@ -14,11 +14,11 @@
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."
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 property="og:url" content="https://openvibe.games/worlds" />
<meta property="og:url" content="https://openvibe.games/worlds" />
- <meta property="og:image" content="https://openvibe.games/og-image.png" />
+ <meta property="og:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:card" content="summary_large_image" />
- <meta name="twitter:image" content="https://openvibe.games/og-image.png" />
+ <meta name="twitter:image" content="https://openvibe.games/shared/social/games.jpg?v=a77ab4204f47" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<style>
<style>
/* The whole page follows the reader's theme (theme-loader.js sets --bg-primary, --text-primary, … on <html>); the dark
/* The whole page follows the reader's theme (theme-loader.js sets --bg-primary, --text-primary, … on <html>); the dark