Implement creator studio and upload updates

This commit is contained in:
2026-04-04 10:12:02 +02:00
parent 1da7d3bf88
commit 0b216b7ecd
15107 changed files with 31206 additions and 626514 deletions

View File

@@ -0,0 +1,96 @@
'use strict'
/**
* render-nova-card.cjs
*
* Headless Playwright screenshot renderer for Nova Cards.
* Visits the signed render-frame URL, waits for React + fonts to finish,
* then screenshots the [data-card-canvas] element and writes a PNG to disk.
*
* Usage:
* node scripts/render-nova-card.cjs \
* --url=<signed-render-frame-url> \
* --out=<absolute-path-to-output.png> \
* [--width=1080] [--height=1080]
*
* Exit codes: 0 = success, 1 = error (message on stderr).
* On success writes JSON to stdout: { "success": true, "out": "...", "width": N, "height": N }
*/
const { chromium } = require('@playwright/test')
const fs = require('fs')
const path = require('path')
// ── Parse CLI args ────────────────────────────────────────────────────────────
const argv = Object.fromEntries(
process.argv.slice(2)
.filter((a) => a.startsWith('--'))
.map((a) => {
const eq = a.indexOf('=')
return eq === -1 ? [a.slice(2), true] : [a.slice(2, eq), a.slice(eq + 1)]
}),
)
const { url, out } = argv
const width = parseInt(argv.width || '1080', 10)
const height = parseInt(argv.height || '1080', 10)
if (!url || !out) {
process.stderr.write(
'Usage: render-nova-card.cjs --url=<url> --out=<png-path> [--width=1080] [--height=1080]\n',
)
process.exit(1)
}
// ── Render ────────────────────────────────────────────────────────────────────
;(async () => {
const browser = await chromium.launch({ headless: true })
try {
const page = await browser.newPage({
viewport: { width, height },
deviceScaleFactor: 1,
})
// Navigate and wait for network to settle (background images, fonts).
await page.goto(url, { waitUntil: 'networkidle', timeout: 30_000 })
// Wait for React to finish painting the canvas element.
const canvas = page.locator('[data-card-canvas]').first()
await canvas.waitFor({ state: 'visible', timeout: 15_000 })
// Wait for all web fonts to finish loading before we capture layout.
await page.evaluate(async () => {
const requiredFonts = [
'Anton',
'Caveat',
'Cormorant Garamond',
'Inter',
'Libre Franklin',
'Playfair Display',
]
await Promise.all(requiredFonts.map((family) => document.fonts?.load?.(`16px "${family}"`) || Promise.resolve()))
if (document.fonts?.ready) {
await document.fonts.ready
}
})
// One extra frame so CSS transforms / container queries resolve fully.
await page.waitForTimeout(300)
// Screenshot only the canvas element; Playwright clips to the element bounding box.
const png = await canvas.screenshot({ type: 'png' })
fs.mkdirSync(path.dirname(out), { recursive: true })
fs.writeFileSync(out, png)
process.stdout.write(JSON.stringify({ success: true, out, width, height }) + '\n')
} finally {
await browser.close()
}
})().catch((err) => {
process.stderr.write((err?.message ?? String(err)) + '\n')
process.exit(1)
})