app
Hero Studio
Public Made by Adomby adom
The hero-image lab with a human gate: `hero-studio pose <owner/slug>` opens the studio in front of the human, posed for their package, and blocks until they click Generate, producing the provenance-stamped 2000x1250 PNG the registry's hero gate requires. The image carries the title and artwork; the exported image also bakes the type pill (top right) and full wiki slug (bottom right); the page shows the hero bare, and only the homepage marquee overlays its own dynamic info. Every hero wears its P
← Commit history
package.json+1−1@@ -2,7 +2,7 @@ "slug": "hero-studio", "title": "Hero Studio", "type": "app",- "version": "0.19.6",+ "version": "0.19.7", "description": "The hero-image lab with a human gate: `hero-studio pose <owner/slug>` opens the studio in front of the human, posed for their package, and blocks until they click Generate, producing the provenance-stamped 2000x1250 PNG the registry's hero gate requires. The image carries the title and artwork; the exported image also bakes the type pill (top right) and full wiki slug (bottom right); the page shows the hero bare, and only the homepage marquee overlays its own dynamic info. Adom-org pages get the house wordmark and palette automatically; every other owner brings their own accent and background colors, with placement fixed for all. The floating app window is the vitrine: it auto-loads a real screenshot from the package's wiki page (screenshots/, docs/), takes a manual import, or a full-hero import (the human-ratified re-stamp path for existing heroes). The pose gate opens in verification mode: per-item checklist (title, subtitle, vitrine, type match) and a Generate that unlocks only fully confirmed. Includes vitrine bleeds, brand tile themes, gradient angles, pixel-faithful wiki marquee and index-card previews, and a component-hero mode with a photo/raytrace/phong fallback ladder.", "license": "MIT", "tags": [
page.json+1−1@@ -2,7 +2,7 @@ "slug": "hero-studio", "title": "Hero Studio", "type": "app",- "version": "0.19.6",+ "version": "0.19.7", "description": "The hero-image lab with a human gate: `hero-studio pose <owner/slug>` opens the studio in front of the human, posed for their package, and blocks until they click Generate, producing the provenance-stamped 2000x1250 PNG the registry's hero gate requires. The image carries the title and artwork; the exported image also bakes the type pill (top right) and full wiki slug (bottom right); the page shows the hero bare, and only the homepage marquee overlays its own dynamic info. Adom-org pages get the house wordmark and palette automatically; every other owner brings their own accent and background colors, with placement fixed for all. The floating app window is the vitrine: it auto-loads a real screenshot from the package's wiki page (screenshots/, docs/), takes a manual import, or a full-hero import (the human-ratified re-stamp path for existing heroes). The pose gate opens in verification mode: per-item checklist (title, subtitle, vitrine, type match) and a Generate that unlocks only fully confirmed. Includes vitrine bleeds, brand tile themes, gradient angles, pixel-faithful wiki marquee and index-card previews, and a component-hero mode with a photo/raytrace/phong fallback ladder.", "license": "MIT", "tags": [
server.js+31−2@@ -310,11 +310,40 @@ function resolvedText() { // count feeds the pre-ticked checklist). Container-local v1; per-account // needs wiki identity (backend ask filed separately). const GATES_FILE = path.join(INSTANCES_DIR, 'gates.json');-function readGates() {+function readLocalGates() { try { return JSON.parse(fs.readFileSync(GATES_FILE, 'utf8')).count || 0; } catch { return 0; } } function bumpGates() {- try { fs.writeFileSync(GATES_FILE, JSON.stringify({ count: readGates() + 1, updated: new Date().toISOString() })); } catch {}+ try { fs.writeFileSync(GATES_FILE, JSON.stringify({ count: readLocalGates() + 1, updated: new Date().toISOString() })); } catch {}+ fetchRemoteGates(); // a fresh gate may tip the account over the threshold+}+// Per-ACCOUNT gate count from the wiki (their GET /api/users/:handle/+// hero-gates, derived server-side from studio-stamped heroes by author):+// stable across machines. The local file counts this container's gates the+// wiki cannot see yet (a gated hero not yet published); max() of the two is+// the honest number. Absent endpoint (pre-deploy) = local only.+let remoteGates = null;+async function fetchRemoteGates() {+ try {+ const REG = process.env.ADOM_WIKI_REGISTRY || 'https://wiki.adom.inc';+ const headers = {};+ try { headers.Authorization = 'Bearer ' + fs.readFileSync('/var/run/adom/api-key', 'utf8').trim(); } catch {}+ const who = await fetch(REG + '/api/me', { headers }).then((r) => (r.ok ? r.json() : null)).catch(() => null);+ const handle = who && (who.name || who.handle || (who.user && (who.user.name || who.user.handle)));+ if (!handle) return;+ const r = await fetch(REG + '/api/users/' + handle + '/hero-gates', { headers });+ if (!r.ok) return;+ const d = await r.json();+ if (typeof d.hero_gates === 'number') {+ remoteGates = { count: d.hero_gates, seasoned: !!d.seasoned, handle };+ logLine('info', 'account gate count: ' + d.hero_gates + ' (' + handle + ', seasoned=' + d.seasoned + ')');+ stateRev += 1;+ }+ } catch {}+}+fetchRemoteGates();+function readGates() {+ return Math.max(readLocalGates(), remoteGates ? remoteGates.count : 0); } // Live wiki re-fetch for a page row, shared by /refresh-page, the dropdown,