openvibers/openvibe.play Commits
Home: a taste and a door on phones (#84)
Changes
@@@ -102,3 +102,24 @@ button.sc-btn.sc-primary { border: 0; }.pl-faq details[open] { padding-bottom: 12px; }.pl-faq summary { cursor: pointer; font-weight: 600; padding: 8px 0; }.pl-faq p { margin: 4px 0 0; color: var(--text-secondary, #96a7c2); }++++/* The home on phones (2026-10-29): a taste and a door. The games are one sideways row (each with its board), the++ figures one row, and the developer material one fold under its heading. */++.pl-makers { margin: 2rem 0 0; }++.pl-fold { border: 1px solid var(--border, #1f2d47); border-radius: 14px; background: var(--bg-card, #131c2e); }++.pl-fold > summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 0 18px; cursor: pointer; list-style: none; }++.pl-fold > summary::-webkit-details-marker { display: none; }++.pl-fold > summary h2 { margin: 0; }++.pl-fold > summary span { color: var(--text-muted, #7386a3); font-weight: 600; font-size: .86rem; text-align: right; }++.pl-fold > summary:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: -2px; border-radius: 14px; }++.pl-fold .sc-sec { max-width: none; margin: 0; padding: 0 18px 18px; }++.pl-fold-go { margin: 0; padding: 0 18px 18px; }++@media (max-width: 599px) {++ .pl-titles .pl-grid { display: flex; flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: 16px; scrollbar-width: none; gap: 10px; margin-left: -16px; margin-right: -16px; padding: 0 16px 4px; }++ .pl-titles .pl-grid::-webkit-scrollbar { display: none; }++ .pl-titles .pl-grid > .pl-card { flex: 0 0 84%; min-width: 0; scroll-snap-align: start; }++ .pl-stats { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(124px, 1fr); grid-template-columns: none; gap: 8px; overflow-x: auto; scrollbar-width: none; margin-left: -16px; margin-right: -16px; padding: 0 16px 2px; }++ .pl-stats::-webkit-scrollbar { display: none; }++ .pl-stats dt, .pl-stats dd { overflow-wrap: normal; word-break: normal; }++ .pl-fold > summary span { display: none; }++}@@@ -85,8 +85,9 @@ function createPageRoutes(ctx) {accent: 'and cloud saves for every game.',lede: 'The game services behind OpenVibe games: achievements players keep, weekly and all-time leaderboards, and saves that follow them from device to device. Guests play at once; their progress moves to their OpenVibe account when they sign in.',actions: me-- ? [{ label: 'Your achievements', href: '/me', primary: true }, { label: 'Read the API', href: '/docs' }, { label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/' }]-- : [{ label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/', primary: true }, { label: 'Read the API', href: '/docs' }, { label: 'Sign in to see yours', href: '/auth/login?next=%2Fme' }],++ // Two, so they sit side by side on a phone; the API is under "For game makers".++ ? [{ label: 'Your achievements', href: '/me', primary: true }, { label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/' }]++ : [{ label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/', primary: true }, { label: 'Sign in to see yours', href: '/auth/login?next=%2Fme' }],note: 'Boards show a name and a score, never a player id.',html: `<dl class="pl-stats">${stats.map(([dt, dd]) => `<div><dt>${dt}</dt><dd>${dd}</dd></div>`).join('')}</dl>`,});@@@ -106,7 +107,7 @@ ${leaders.has(t.id) ? html`<h4>This week: ${leaders.get(t.id).name}</h4>${boardT</section>${popular.length ? html`<section class="pl-popular" aria-labelledby="pl-popular-h"><h2 id="pl-popular-h">Most earned</h2><p class="pl-muted">The achievements the most players have unlocked.</p><ul class="pl-ach">${popular.map((a) => html`<li><span class="pl-ach-name">${a.name}</span>${a.description ? html`<span class="pl-ach-desc">${a.description}</span>` : ''}<span class="pl-ach-meta"><a href="/t/${a.game.id}">${a.game.name}</a> · ${plural(a.unlocked_by, 'player', 'players')}${a.game.players ? ` · ${pct(a.unlocked_by, a.game.players)}` : ''}</span></li>`)}</ul></section>` : ''}--${raw(showcase.features({++<section class="pl-makers" aria-labelledby="pl-makers-h"><details class="pl-fold"><summary><h2 id="pl-makers-h">For game makers</h2><span>what a game gets, the SDK, the limits</span></summary>${raw(showcase.features({title: 'What a game gets',lede: 'Four services, one OpenVibe account for every player, and nothing to host yourself.',items: [@@@ -163,6 +164,7 @@ ${raw(showcase.limits({{ label: 'Requests per caller', values: [`${num(config.limits.minute)} a minute, ${num(config.limits.hour)} an hour`] },],}))}++<p class="pl-fold-go"><a class="sc-btn" href="/docs">Read the API</a></p></details></section><section class="pl-faq" aria-labelledby="pl-faq-h"><h2 id="pl-faq-h">Questions</h2>${HOME_FAQ.map((f) => html`<details><summary>${f.q}</summary><p>${f.a}</p></details>`)}</section>`,};}@@@ -20,8 +20,8 @@ const BUDGETS = {jsRawKB: 308, // 307.8 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); 300.5 openvibe-shared 4.25.0: the menu's orb beside the brand, both balances on phones, messages, the account sheet on phones and the bar stepping away on phones; 293 openvibe-shared 4.22.0: the navbar's magnifier search button and More dropdown (search.js and loading.js load only when used); 287.2 Shared 4.17.0: OpenCoins and Vibes chips (wallet: true) in the navbar; 273.2 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 264.3 with Shared 4.13.0 (2026-10-26: account links); 239.8jsBrotliKB: 77, // 76.1 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); 74.2 openvibe-shared 4.25.0: the menu's orb beside the brand, both balances on phones, messages, the account sheet on phones and the bar stepping away on phones; 70.5 Shared 4.17.0: OpenCoins and Vibes chips (wallet: true) in the navbar; 67.9 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 65.3 Shared 4.12.0: the light/dark switch, the seasonal mark and the theme pairs; 56.5cssFiles: 2, // 2 (app.css + the cached /shared/showcase.css)-- cssRawKB: 36, // 31.8 openvibe-shared 4.26.1 (hero visual); 26.3 with Shared 4.13.0 (2026-10-26: account links); 18.7 (app.css 7.1 with Play's cards, boards and achievement tiles, plus showcase.css; 2026-10-14)-- cssBrotliKB: 7.5, // 5.8 with Shared 4.13.0 (2026-10-26: account links); 4.9 // raised 7 -> 8 for the openvibe-shared Kit 2 pin (kit.css grew) // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did++ cssRawKB: 37, // 36.2 the home's phone row and fold (2026-10-29); 31.8 openvibe-shared 4.26.1 (hero visual); 26.3 with Shared 4.13.0 (2026-10-26: account links); 18.7 (app.css 7.1 with Play's cards, boards and achievement tiles, plus showcase.css; 2026-10-14)++ cssBrotliKB: 8, // 7.8 the home's phone row and fold (2026-10-29); 5.8 with Shared 4.13.0 (2026-10-26: account links); 4.9 // raised 7 -> 8 for the openvibe-shared Kit 2 pin (kit.css grew) // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it didexternalFiles: 0, // 0};
@@ -102,3 +102,24 @@ button.sc-btn.sc-primary { border: 0; }
@@ -102,3 +102,24 @@ button.sc-btn.sc-primary { border: 0; }
.pl-faq details[open] { padding-bottom: 12px; }
.pl-faq details[open] { padding-bottom: 12px; }
.pl-faq summary { cursor: pointer; font-weight: 600; padding: 8px 0; }
.pl-faq summary { cursor: pointer; font-weight: 600; padding: 8px 0; }
.pl-faq p { margin: 4px 0 0; color: var(--text-secondary, #96a7c2); }
.pl-faq p { margin: 4px 0 0; color: var(--text-secondary, #96a7c2); }
+
+/* The home on phones (2026-10-29): a taste and a door. The games are one sideways row (each with its board), the
+ figures one row, and the developer material one fold under its heading. */
+.pl-makers { margin: 2rem 0 0; }
+.pl-fold { border: 1px solid var(--border, #1f2d47); border-radius: 14px; background: var(--bg-card, #131c2e); }
+.pl-fold > summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 56px; padding: 0 18px; cursor: pointer; list-style: none; }
+.pl-fold > summary::-webkit-details-marker { display: none; }
+.pl-fold > summary h2 { margin: 0; }
+.pl-fold > summary span { color: var(--text-muted, #7386a3); font-weight: 600; font-size: .86rem; text-align: right; }
+.pl-fold > summary:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: -2px; border-radius: 14px; }
+.pl-fold .sc-sec { max-width: none; margin: 0; padding: 0 18px 18px; }
+.pl-fold-go { margin: 0; padding: 0 18px 18px; }
+@media (max-width: 599px) {
+ .pl-titles .pl-grid { display: flex; flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: 16px; scrollbar-width: none; gap: 10px; margin-left: -16px; margin-right: -16px; padding: 0 16px 4px; }
+ .pl-titles .pl-grid::-webkit-scrollbar { display: none; }
+ .pl-titles .pl-grid > .pl-card { flex: 0 0 84%; min-width: 0; scroll-snap-align: start; }
+ .pl-stats { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(124px, 1fr); grid-template-columns: none; gap: 8px; overflow-x: auto; scrollbar-width: none; margin-left: -16px; margin-right: -16px; padding: 0 16px 2px; }
+ .pl-stats::-webkit-scrollbar { display: none; }
+ .pl-stats dt, .pl-stats dd { overflow-wrap: normal; word-break: normal; }
+ .pl-fold > summary span { display: none; }
+}
@@ -85,8 +85,9 @@ function createPageRoutes(ctx) {
@@ -85,8 +85,9 @@ function createPageRoutes(ctx) {
accent: 'and cloud saves for every game.',
accent: 'and cloud saves for every game.',
lede: 'The game services behind OpenVibe games: achievements players keep, weekly and all-time leaderboards, and saves that follow them from device to device. Guests play at once; their progress moves to their OpenVibe account when they sign in.',
lede: 'The game services behind OpenVibe games: achievements players keep, weekly and all-time leaderboards, and saves that follow them from device to device. Guests play at once; their progress moves to their OpenVibe account when they sign in.',
actions: me
actions: me
- ? [{ label: 'Your achievements', href: '/me', primary: true }, { label: 'Read the API', href: '/docs' }, { label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/' }]
- : [{ label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/', primary: true }, { label: 'Read the API', href: '/docs' }, { label: 'Sign in to see yours', href: '/auth/login?next=%2Fme' }],
+ // Two, so they sit side by side on a phone; the API is under "For game makers".
+ ? [{ label: 'Your achievements', href: '/me', primary: true }, { label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/' }]
+ : [{ label: 'Play on OpenVibe.Games', href: 'https://openvibe.games/', primary: true }, { label: 'Sign in to see yours', href: '/auth/login?next=%2Fme' }],
note: 'Boards show a name and a score, never a player id.',
note: 'Boards show a name and a score, never a player id.',
html: `<dl class="pl-stats">${stats.map(([dt, dd]) => `<div><dt>${dt}</dt><dd>${dd}</dd></div>`).join('')}</dl>`,
html: `<dl class="pl-stats">${stats.map(([dt, dd]) => `<div><dt>${dt}</dt><dd>${dd}</dd></div>`).join('')}</dl>`,
});
});
@@ -106,7 +107,7 @@ ${leaders.has(t.id) ? html`<h4>This week: ${leaders.get(t.id).name}</h4>${boardT
@@ -106,7 +107,7 @@ ${leaders.has(t.id) ? html`<h4>This week: ${leaders.get(t.id).name}</h4>${boardT
</section>
</section>
${popular.length ? html`<section class="pl-popular" aria-labelledby="pl-popular-h"><h2 id="pl-popular-h">Most earned</h2><p class="pl-muted">The achievements the most players have unlocked.</p>
${popular.length ? html`<section class="pl-popular" aria-labelledby="pl-popular-h"><h2 id="pl-popular-h">Most earned</h2><p class="pl-muted">The achievements the most players have unlocked.</p>
<ul class="pl-ach">${popular.map((a) => html`<li><span class="pl-ach-name">${a.name}</span>${a.description ? html`<span class="pl-ach-desc">${a.description}</span>` : ''}<span class="pl-ach-meta"><a href="/t/${a.game.id}">${a.game.name}</a> · ${plural(a.unlocked_by, 'player', 'players')}${a.game.players ? ` · ${pct(a.unlocked_by, a.game.players)}` : ''}</span></li>`)}</ul></section>` : ''}
<ul class="pl-ach">${popular.map((a) => html`<li><span class="pl-ach-name">${a.name}</span>${a.description ? html`<span class="pl-ach-desc">${a.description}</span>` : ''}<span class="pl-ach-meta"><a href="/t/${a.game.id}">${a.game.name}</a> · ${plural(a.unlocked_by, 'player', 'players')}${a.game.players ? ` · ${pct(a.unlocked_by, a.game.players)}` : ''}</span></li>`)}</ul></section>` : ''}
-${raw(showcase.features({
+<section class="pl-makers" aria-labelledby="pl-makers-h"><details class="pl-fold"><summary><h2 id="pl-makers-h">For game makers</h2><span>what a game gets, the SDK, the limits</span></summary>${raw(showcase.features({
title: 'What a game gets',
title: 'What a game gets',
lede: 'Four services, one OpenVibe account for every player, and nothing to host yourself.',
lede: 'Four services, one OpenVibe account for every player, and nothing to host yourself.',
items: [
items: [
@@ -163,6 +164,7 @@ ${raw(showcase.limits({
@@ -163,6 +164,7 @@ ${raw(showcase.limits({
{ label: 'Requests per caller', values: [`${num(config.limits.minute)} a minute, ${num(config.limits.hour)} an hour`] },
{ label: 'Requests per caller', values: [`${num(config.limits.minute)} a minute, ${num(config.limits.hour)} an hour`] },
],
],
}))}
}))}
+<p class="pl-fold-go"><a class="sc-btn" href="/docs">Read the API</a></p></details></section>
<section class="pl-faq" aria-labelledby="pl-faq-h"><h2 id="pl-faq-h">Questions</h2>${HOME_FAQ.map((f) => html`<details><summary>${f.q}</summary><p>${f.a}</p></details>`)}</section>`,
<section class="pl-faq" aria-labelledby="pl-faq-h"><h2 id="pl-faq-h">Questions</h2>${HOME_FAQ.map((f) => html`<details><summary>${f.q}</summary><p>${f.a}</p></details>`)}</section>`,
};
};
}
}
@@ -20,8 +20,8 @@ const BUDGETS = {
@@ -20,8 +20,8 @@ const BUDGETS = {
jsRawKB: 308, // 307.8 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); 300.5 openvibe-shared 4.25.0: the menu's orb beside the brand, both balances on phones, messages, the account sheet on phones and the bar stepping away on phones; 293 openvibe-shared 4.22.0: the navbar's magnifier search button and More dropdown (search.js and loading.js load only when used); 287.2 Shared 4.17.0: OpenCoins and Vibes chips (wallet: true) in the navbar; 273.2 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 264.3 with Shared 4.13.0 (2026-10-26: account links); 239.8
jsRawKB: 308, // 307.8 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); 300.5 openvibe-shared 4.25.0: the menu's orb beside the brand, both balances on phones, messages, the account sheet on phones and the bar stepping away on phones; 293 openvibe-shared 4.22.0: the navbar's magnifier search button and More dropdown (search.js and loading.js load only when used); 287.2 Shared 4.17.0: OpenCoins and Vibes chips (wallet: true) in the navbar; 273.2 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 264.3 with Shared 4.13.0 (2026-10-26: account links); 239.8
jsBrotliKB: 77, // 76.1 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); 74.2 openvibe-shared 4.25.0: the menu's orb beside the brand, both balances on phones, messages, the account sheet on phones and the bar stepping away on phones; 70.5 Shared 4.17.0: OpenCoins and Vibes chips (wallet: true) in the navbar; 67.9 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 65.3 Shared 4.12.0: the light/dark switch, the seasonal mark and the theme pairs; 56.5
jsBrotliKB: 77, // 76.1 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); 74.2 openvibe-shared 4.25.0: the menu's orb beside the brand, both balances on phones, messages, the account sheet on phones and the bar stepping away on phones; 70.5 Shared 4.17.0: OpenCoins and Vibes chips (wallet: true) in the navbar; 67.9 openvibe-shared 4.15 footer: the compact footer opens into the whole one, and the pulse line; 65.3 Shared 4.12.0: the light/dark switch, the seasonal mark and the theme pairs; 56.5
cssFiles: 2, // 2 (app.css + the cached /shared/showcase.css)
cssFiles: 2, // 2 (app.css + the cached /shared/showcase.css)
- cssRawKB: 36, // 31.8 openvibe-shared 4.26.1 (hero visual); 26.3 with Shared 4.13.0 (2026-10-26: account links); 18.7 (app.css 7.1 with Play's cards, boards and achievement tiles, plus showcase.css; 2026-10-14)
- cssBrotliKB: 7.5, // 5.8 with Shared 4.13.0 (2026-10-26: account links); 4.9 // raised 7 -> 8 for the openvibe-shared Kit 2 pin (kit.css grew) // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did
+ cssRawKB: 37, // 36.2 the home's phone row and fold (2026-10-29); 31.8 openvibe-shared 4.26.1 (hero visual); 26.3 with Shared 4.13.0 (2026-10-26: account links); 18.7 (app.css 7.1 with Play's cards, boards and achievement tiles, plus showcase.css; 2026-10-14)
+ cssBrotliKB: 8, // 7.8 the home's phone row and fold (2026-10-29); 5.8 with Shared 4.13.0 (2026-10-26: account links); 4.9 // raised 7 -> 8 for the openvibe-shared Kit 2 pin (kit.css grew) // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did // back to the pre-Kit 2 value: Kit 2 has its own files (kit-data.css) since openvibe-shared v4.37.0, so kit.css weighs what it did
externalFiles: 0, // 0
externalFiles: 0, // 0
};
};