Studio job

A studio job (pipeline/show/text2game.js, runTextToGameJob) generates an asset through a hosted text-to-3D studio's web UI, driven end-to-end through Skarbiec (credentials) and the declared browser layer, Weles or the Playwright MCP server. Nothing platform-specific is hardcoded: endpoints and selectors come from the pipeline config, so swapping studios is a config change, not a code change.

Entry points: glina create <prompt> [--race r], MCP tool glina_create_asset. (--race prefixes the prompt; the MCP schema limits it to humans | dwarves | elves | skeletons.)

Steps

Every step is named, and a failure carries its name: text2game step '<name>' failed: <reason>. A config with no studio section is refused first: the pipeline config has no studio section: create needs studio.loginUrl, studio.generateUrl, studio.selectors and studio.artifact.expression.

  1. open-session / open-page — start a browser session on the browser layer the config declares and open a page.
  2. login:goto / login:user / login:pass / login:submit — navigate to studio.loginUrl, fill studio.selectors.loginUser / loginPassword with the resolved credentials.username / password, click loginSubmit.
  3. studio:goto / studio:prompt / studio:submit — open studio.generateUrl, fill promptInput, click generateSubmit.
  4. studio:artifact — one page evaluation that resolves when studio.artifact.expression (a page JavaScript expression) yields an http… string: it reads the expression at once and again on every change of the page, so nothing polls and nothing gives up after a fixed time. A studio that never produces the link leaves the run open until the operator stops it. A value that is not an http URL is refused: studio.artifact.expression resolved to <value>, not an http URL.
  5. artifact:download — fetch the artifact URL (optional artifact.downloadHeaders); non-2xx: download failed: HTTP N. The file lands at <outDir>/<slug>.glb (default assets/models).
  6. blender:postprocess (only when blender.enabled) — import → run blender.processCode (which sees INPUT_PATH and OUTPUT_PATH as injected globals) → export <name>.processed.glb. See Blender session.
  7. verify (unless verify.enabled: false) — the verification gate with throwOnFail, run against the processed file when one exists, else the download.

Result: { outPath, processedPath, artifactUrl, prompt, verification }.

Invariants

  • The browser session closes in a finally; a failed job never leaks a browser slot.
  • Credentials resolve at config load from role://<role>/<field> through Stado and Skarbiec, or the selected owner-only GLINA_CREDENTIALS_FILE. Resolved values remain in memory during a job and are never logged.
  • The example config (docs/examples/pipeline.config.example.json) targets Hunyuan3D's studio and requests role text2game-account with fields login_email / login_password; it does not select a vault item by name.