◆Lab

The lab notebook / Evidence

R1 Console

Technical evidence is published in English.

Tool / pipeline · ACTIVE · verified 2026-10-03

R1 Console is the studio behind the games: one entry point that generates, validates and publishes. It keeps a catalogue of 577,910 indexed sprites with a per-asset licence table, improves existing art with a local SDXL + ControlNet pass, synthesises audio in pure Python, runs a dual-GPU video pipeline, and delivers every file into a product only through a SHA-256 manifest. The games are separate products with their own repositories; the studio is the authority that produces and certifies them, not a library they import at runtime.

Numbers below were re-measured on disk on 2026-10-03 by walking library/triagem/sprites (os.walk) and by querying library/triagem/indice.db read-only, plus the studio's own CLI (python r1.py doctor, python r1.py acervo --full) and its test suite. Where a figure in the studio's own README disagrees with the disk, the disagreement is stated.

◆sections

The flow: brief to published build

The official path is a single line, written in the architecture document and repeated in the README: brief -> DeepSeek in worktree -> tests -> local generation -> validation -> SHA-256 manifest -> publication -> product build.

Code generation is delegated, not hand-waved. The studio hands a task to a DeepSeek agent running inside its own git worktree, and the result has to pass local tests before it is allowed into a product — that is invariant 6, not a convention.

Art and audio are generated locally: an SDXL + ControlNet pass for sprites, a pure-Python synthesiser for sound, and a two-GPU pipeline for video. Everything lands first in a delivery area, never straight into the product.

Publication is the part with the most machinery, and it is worth being precise about it. python r1.py publish-manifest closes an open list of files and stamps each one with a SHA-256. python r1.py publish then runs a preflight over the whole manifest before touching a single destination: every source must exist, every destination must stay inside the product, no destination may repeat, and every declared hash must match the bytes on disk. A manifest with no files is refused, and so is a file with no hash.

Only after that preflight does it write. Every byte is copied to a temporary file beside its destination and re-hashed; every existing destination is moved aside to a backup; then each staged file is swapped in. If any swap fails, the already-applied ones are rolled back in reverse order and the error is re-raised. The receipt — project, timestamp, dry_run flag and the full file list with hashes — is written to var/runs/publish/.

python r1.py publish <manifest> --dry-run runs the same preflight and returns the same receipt without writing anything. The reference for a product is its own manifest: projects/star_swarm/manifests/PUBLISH-star_swarm.json.

  • docs/ARQUITETURA-ALVO.md:9-11 — brief -> DeepSeek em worktree -> testes -> geração local -> validação -> manifesto SHA-256 -> publicação -> build do produto
  • README.md:7-8 — same flow restated; README.md:184 — r1.py code --project star_swarm delivers the task to DeepSeek
  • docs/ARQUITETURA-ALVO.md:31 — invariant 6: 'Código gerado passa por testes locais antes de entrar no produto'
  • studio/publish.py:97-132 — _preflight: source exists, destination inside product, no duplicate destination, hash must match, empty manifest refused
  • studio/publish.py:143-188 — stage every byte, back up every destination, os.replace, and rollback in reverse on failure
  • studio/publish.py:190-209 — receipt written to var/runs/publish/<stamp>-<project>.json
  • README.md:189-191 — 'Toda a entrega é validada e preparada antes da primeira troca; se uma troca falhar, as anteriores são restauradas. O recibo fica em var/runs/publish/'
  • tests_studio/test_studio.py:103-139 — test_publish_preflight_prevents_partial_delivery, passing
  • tests_studio/test_studio.py:153-194 — test_publish_rolls_back_if_a_destination_swap_fails, passing

The seven invariants

1. No junction between R1 and the products.

2. No fallback that makes a game read R1 console/assets at runtime.

3. Publication only through a manifest and a hash.

4. Every model and engine has a state, a version, a licence and a health check.

5. Every generation records prompt, seed, workflow, hardware, models and output.

6. Generated code passes local tests before it enters the product.

7. The CLI, ComfyUI and the products run in separate environments.

These seven are the load-bearing part of the design: they are what keeps the studio from becoming a runtime dependency of the things it makes. The separation is real and not aspirational — config/studio.toml points each product at its own repository, and the studio doctor checks that every product path resolves outside the studio root.

  • docs/ARQUITETURA-ALVO.md:26-32 — the seven invariants, verbatim
  • config/studio.toml:22-32 — star_swarm, tank_duel and arcade_dagger each mapped to an external path with a role
  • tests_studio/test_studio.py:22-25 — test_project_paths_are_external_products asserts project_path(...) != ROOT for every project, passing
  • README.md:222-224 — 'Cada produto traz o seu próprio motor/ vendorizado e o seu rodar.py, e nada lá dentro lê a partir de R1 console/ — é o que as invariantes 1 e 2 exigem'

The sprite catalogue: choosing art by query, not by browsing

The catalogue is a SQLite index, indice.db, with one row per sprite. Each row carries the path, category, view (side/top/iso/front/unknown), whether the sprite has alpha, a size band, width, height, byte count, source repo and branch. Choosing art becomes a query instead of a filesystem search.

Measured on 2026-10-03 by querying indice.db read-only: 577,910 rows, of which 329,337 are classified alpha; the byte column sums to exactly 15,317,369,625. Those three numbers also match the studio's own vault contract file and its runtime inspection.

The same figures were confirmed a second way, independently of the index: walking the 577,910 files under library/triagem/sprites returned 577,910 files totalling 15,317,369,625 bytes — the index and the bytes agree exactly.

The catalogue is spread over 23 categories. The largest are outro (186,859), terreno (82,053), modelo_3d (45,202), interface (42,769) and item (38,145). The ones that matter for 2D games are personagem (31,924), monstro (15,206), nave (9,632), asteroide (3,618), arma (3,459) and projetil (2,622).

This is not a convenience. The source collection these bytes came from has been deleted — the whole f51-labs folder is gone — and the index cannot be rebuilt, because the script that built it read a laboratory database that no longer exists. Each file is the last known link to its own bytes.

Note on the index file size: the studio's README quotes '340 MB' in one place and '348 MiB' in another, and the method document quotes '324,8 MB'. The file on disk is 364,650,496 bytes = 347.8 MiB, so '348 MiB' is the correct figure and the other two are stale — the index grew when the destino column was rewritten during the 2026-09-29 migration, and the method document was not updated afterwards.

  • Measured 2026-10-03 — sqlite3 read-only on library/triagem/indice.db: COUNT(*) = 577910; COUNT(*) WHERE pixel='alfa' = 329337; SUM(bytes) = 15317369625; 23 distinct categories
  • Measured 2026-10-03 — os.walk over library/triagem/sprites: 577910 files, 15317369625 bytes (259 s)
  • library/triagem/VAULT.json:8-10 — expected_files 577910, expected_bytes 15317369625, expected_max_physical_path 259
  • library/triagem/LEIA.md:48-70 — per-category totals; the 23 alpha counts sum to exactly 329337
  • docs/ACERVO.md:29-30 — Ficheiros 577.910; Bytes 15.317.369.625 = 14,27 GiB
  • docs/ACERVO.md:33 — 'Índice indice.db: 364.650.496 bytes (347,8 MiB) — era 340.615.168 antes da migração de destino'
  • README.md:16 — claims indice.db is '340 MB' (stale, understated)
  • README.md:105 — claims 'índice de 348 MiB' (correct)
  • docs/ESTUDIO.md:47 and docs/ESTUDIO.md:87 — claim '324,8 MB' (stale, pre-migration figure)
  • README.md:16-18 — a row per sprite with path, category, view, alpha, size, repo and branch; 577.910 sprites, 329.337 with alpha
  • README.md:28-32 — the example query used to pick the tank pack
  • docs/ACERVO.md:62-69 — the source folder f51-labs/assets was deleted, not emptied; each file has nlink = 1; there is no rebuild recipe

The local model improves what already exists

The catalogue solves provenance; it does not solve resolution. Some of the right sprites are 38x36 and do not have enough pixels. The studio's answer is not to generate a replacement but to enlarge what is already there under the control of its own silhouette.

The recipe takes an existing sprite, centres it on a square, upscales with LANCZOS, extracts the edges with Canny, and runs SDXL with controlnet-canny-sdxl. The ControlNet holds the shape; the denoise setting decides how much the model is allowed to invent. Low denoise mostly cleans what is there; high denoise redraws it.

Three results are kept as proof, all 512x512, from a 38x36 tank body. At denoise 0.4 the upscale keeps its blockiness and nothing is added. At 0.6 volume appears: the centre circle becomes two bolts, a hatch appears, the tracks gain segments. At 0.8 it is a drawn tank — panelled lines, rivets, a raised cupola, tracks with highlights. 0.8 is the point for that sprite; it is not a rule.

The recipe also carries two corrections that the laboratory script did not have, and both are recorded with their reason: centre before enlarging, because the original stretched non-square sprites into 512x512, and re-apply the alpha at the end, because the SaveImage node writes RGB and the sprite becomes an opaque square.

This part is proven for one sprite. It is not proven for a set: seven sprites going through the same process and coming out coherent with each other has not been attempted, and the studio says so itself.

  • pipelines/image/r1-sdxl/detalhar.py — the recipe: detail an existing sprite via SDXL + ControlNet canny
  • README.md:34-45 — 'O ControlNet segura a silhueta; o denoise decide quanto o modelo pode inventar'; centre-before-enlarge and re-apply-alpha corrections, with reasons; fixed seed and one prompt family for the whole batch
  • docs/ESTUDIO.md:111-117 — the step chain: sprite 38x36 -> ImageScale nearest-exact 512x512 -> Canny (0,35 / 0,75) -> SDXL + controlnet-canny-sdxl -> img2img denoise 0.4/0.6/0.8
  • docs/ESTUDIO.md:139-143 — what each of the three denoise files actually shows, described from looking at them
  • assets/r1/detail-denoise-0.4.png, assets/r1/detail-denoise-0.6.png, assets/r1/detail-denoise-0.8.png — the three proofs, 512x512, copied from projects/tank_duel/experiments/detalhamento/
  • assets/r1/base-sprite-sombra.png and assets/r1/base-sprite-vagalume-asa.png — the recipe's real inputs, copied from pipelines/image/r1-sdxl/bases/
  • Measured 2026-10-03 — the two base sprites are 103x84 and 97x84 in Format32bppArgb; the three denoise outputs are 512x512 in Format24bppRgb. The inputs carry alpha and the outputs do not, which is the defect the re-apply-alpha correction addresses
  • docs/PRODUCAO.md:54-55 — vagalume and sombra are named enemies in the star_swarm art contract ('rápido, pequeno' and 'o 1º bandido')
  • docs/ESTUDIO.md:152-159 — proven for one sprite; set consistency not resolved; the result is not wired into any game

Audio synthesised in pure Python

The soundtrack is generated here rather than licensed from anyone. pipelines/sound/procedural/ writes everything with the standard library alone — wave and struct, no third-party samples and no audio library.

What it adds over the original mould: a phase accumulator so a swept frequency does not click, filtered noise, envelopes measured in seconds instead of fractions, and normalisation to a peak measured below 0 dBFS. The star_swarm trail writes two 44.1 kHz square-wave files at 118 bpm, and 136 bpm for the boss.

This matters for exactly one reason, and the studio states it plainly: being the house's own work is what sustains the licence table and keeps the game sellable.

  • pipelines/sound/procedural/ — sintese.py, trilha.py, efeitos.py, gerar.py, medir.py
  • README.md:59-66 — pure Python via wave + struct, no third-party samples, no audio library; phase accumulator, filtered noise, seconds-based envelope, peak below 0 dBFS; 118 bpm and 136 bpm for the boss
  • README.md:64-66 — 'É obra própria, não licença de terceiros — é isso que sustenta a tabela de procedência'
  • README.md:147 — audio of star_swarm: generated here, own work, sellable

Anime video: both GPUs or it fails

The 2D video factory chains three models: Animagine XL 4.0 defines the drawing, FLUX.1 Kontext Dev corrects the keyframes, Wan 2.2 TI2V-5B animates from the first frame.

It is written to use two cards, not to fall back to one: one GPU runs the diffusion with dynamic offload while the second runs the VAE, and there is no layer splitting over PCIe. Each run stores its workflow, telemetry, ffprobe output and hashes under var/runs/video-2d/, because without proof that both cards were used there is no complete receipt.

The studio configuration declares that requirement explicitly rather than leaving it implied: the ComfyUI service declares required_cuda_devices = 2 and enables dynamic VRAM.

One model in this chain is not commercially usable, and it is registered as such: FLUX.1 Kontext Dev carries a non-commercial licence and the registry notes it is used in the laboratory only, for editing and keyframe continuity.

  • docs/FABRICA-VIDEO-2D.md — model choice, linked from README.md:75
  • README.md:68-75 — Animagine XL 4.0 -> FLUX.1 Kontext Dev -> Wan 2.2 TI2V-5B; one GPU for diffusion with dynamic offload, another for the VAE; no PCIe layer splitting; per-run workflow, telemetry, ffprobe and hashes in var/runs/video-2d/
  • config/studio.toml:10-14 — ComfyUI on port 8189, cuda_device 'all', required_cuda_devices = 2, enable_dynamic_vram = true
  • registry/licenses.toml:24-28 — flux-1-kontext-dev, LicenseRef-FLUX.1-dev-Non-Commercial-1.1.1, 'Modelo usado apenas no laboratorio para edicao e continuidade de keyframes'
  • registry/licenses.toml:19-22 — animagine-xl-4.0, LicenseRef-CreativeML-OpenRAIL++-M
  • registry/licenses.toml:30-33 — wan-2.2, Apache-2.0

Provenance: the table that decides what can be sold

Every asset came from somewhere with a different legal status, and the studio keeps that written down because it is the table that decides what may be sold. Assets were matched to their origin by md5, not by resemblance.

The star_swarm and tank_duel art is CC0, from the Kenney 2D packs (space-shooter-remastered, space-shooter-extension, top-down-tanks-remastered). The star_swarm art under assets/arte/ is different: it was generated on this machine by the r1-sdxl pipeline with seed 77001, and is the house's own. The arcade_dagger art is GPL — Endless Sky and Wesnoth — and is the one part that cannot be sold as it stands; the studio marks that project as laboratory with commercial = false.

The engine is the only dependency that is neither CC0 nor MIT: raylib-python is EPL-2.0, which permits commercial use but is not public domain.

One honest gap is recorded rather than hidden: an older manifest for the star_swarm art covers 16 of 23 PNG files. The provenance of the missing ones was confirmed by md5 — they are Kenney CC0 — but the manifest itself does not list them.

  • README.md:138-152 — the provenance table: piece, origin, licence, sellable
  • README.md:154-156 — the per-file proof with the md5 of each piece is materialised in LICENSE
  • LICENSE:26-58 — arcade_dagger: six PNG, md5 per file, Endless Sky GPL-3.0 and Wesnoth GPL-2.0-or-later; 'esta arte não pode ser relicenciada nem vendida como está'
  • LICENSE:61-68 — star_swarm and tank_duel art is CC0 Kenney, linked by md5; none of it is model-generated
  • README.md:158-166 — the two sides: arcade_dagger has assets_status audit / commercial_use audit; star_swarm and tank_duel are sellable in art; EPL-2.0 is the only non-CC0/MIT item
  • docs/ESTUDIO.md:249-250 — the estoque/MANIFEST.json has 16 entries for 23 PNG; the three forma_*, laser_* and poder_* are not covered
  • registry/licenses.toml:1-39 — machine-readable licence register: raylib-python EPL-2.0, comfyui GPL-3.0-only, star-swarm-kenney-assets CC0-1.0

The state today, including what is broken

(local source: R1 console and several of the paths it expects were left behind.)

(local source: R1Vault, so that broad searches do not walk 577,910 files. On disk it is now a plain directory, and the vault target does not exist. The studio's own inspector reports three problems: not a junction, vault absent, and the junction resolving to itself.)

This does not mean the bytes are lost — they are present and complete. The index and the disk agree exactly on both count and total bytes. What changed is the arrangement, not the content: the vault was flattened back inside the repository. The move to D: also lengthened the logical paths: the longest path measured on disk is 274 characters, 15 more than the 259 recorded for the shorter vault root, which is the arithmetic of a 37-character base instead of a 22-character one. The index file itself still verifies: the studio's full check passes the SHA-256 comparison against the manifest.

The second real failure is the star_swarm delivery. The verifier reports the delivered art and audio manifests as divergent, 2 art files missing from the delivery, and 5 delivery files missing from the product. It counts 39 manifested art files where the studio's own test expects 42.

The studio is also not as tested as its README implies. The README says the suite is 44 tests. There are indeed 44 test functions, but pytest collects 47 cases and the honest result is 2 failed, 43 passed, 2 skipped. The two failures are the vault check and the delivery check described above — the suite is catching real drift, which is the point of having it.

Two more things are recorded as missing rather than solved: animation. The studio has proven a still sprite can be redrawn properly; the same sprite across several frames of a walk cycle has not been attempted or measured. And the Triagem folder is no longer rebuildable at all, by any code path.

  • assets/r1/output-r1-doctor.txt — python r1.py doctor, 2026-10-03: 17 checks, 8 FALHA, exit code 2
  • README.md:174 — 'python r1.py doctor # runtimes, cofre, motores e produtos — 17 verificações' (count confirmed)
  • assets/r1/output-r1-acervo-full.json — python r1.py acervo --full, 2026-10-03: ok false; indexed_files 577910; indexed_bytes 15317369625; max_physical_path 259; index_hash_checked true; three problems
  • studio/acervo.py:34-46 — the junction check, the vault-exists check and the resolved-target comparison that produce those three problems
  • (local source: R1Vault does not exist)
  • (local source: sprites is 37, so 274 - 15 = 259, consistent with the recorded vault figure)
  • assets/r1/output-r1-pytest.txt — python -m pytest tests_studio -q, 2026-10-03: '2 failed, 43 passed, 2 skipped in 2.01s'
  • Measured 2026-10-03 — 44 'def test_' functions across 6 files in tests_studio/ (test_video_factory 22, test_studio 9, test_cli_process 6, test_entrega_e_raiz 4, test_generation_pipeline 2, test_star_swarm_delivery 1); pytest collects 47 cases
  • README.md:196 — claims '44 testes'
  • Measured 2026-10-03 — python projects/star_swarm/production/tools/verificar_entrega.py: ok false, manifested_art 39, delivery_files 58, published_files 58, 9 problems
  • tests_studio/test_star_swarm_delivery.py:32 — the test expects manifested_art == 42, delivery_files == 58, published_files == 58
  • README.md:227-230 — animation: a still image becoming a walk cycle does not exist yet, and was neither attempted nor measured
  • README.md:240-243 — library/triagem/montar.py has no origin; the triage is not rebuildable today
  • library/triagem/montar.py:1-28 — the script's own docstring: 'ESTADO A 2026-09-29: ESTE SCRIPT NAO PODE CORRER. A FONTE MORREU.'
◆figures
What enters the pipeline
A base sprite the recipe takes as input — 97x84, flat, a handful of solid colours, and carrying a real alpha channel (32bpp ARGB). This is the shape of art the studio starts from: the right sprite for the job, with nowhere near enough pixels. The studio's method is to improve this, not to generate a replacement for it.
A second base sprite
Another input to the same recipe, 103x84, also 32bpp ARGB. Both of these are enemies in the shipped game — sombra and vagalume appear in the production contract for star_swarm. Note the contrast with the three files below: the inputs have alpha, the detail-pass outputs do not, because the SaveImage node writes RGB. That is exactly the defect the recipe's re-apply-alpha correction exists to fix.
Detail pass, denoise 0.4
The 38x36 tank body enlarged to 512x512 with denoise 0.4. The upscale keeps its blockiness and nothing is added — faithful and ugly. ControlNet holds the silhouette; the denoise value decides how far the model may go.
Detail pass, denoise 0.6
Denoise 0.6. Volume appears: the centre circle becomes two bolts, a hatch appears at the base, the tracks gain segments. Cleaner — and still flat.
Detail pass, denoise 0.8
Denoise 0.8 — a tank actually drawn: panelled lines, rivets, a raised cupola, tracks with highlights. This is the point for this sprite, and the studio records that it is not a rule.
python r1.py acervo --full, 2026-10-03. The index verifies against the manifest (577,910 rows, 15,317,369,625 bytes, SHA-256 of the index matches) but the vault contract does not: it is not a junction, the vault is absent, and the link resolves to itself.
python r1.py doctor, 2026-10-03: 17 named checks, 8 failures, exit code 2. The failures are missing paths left behind by the move from the Desktop to D:, plus the sprite vault and the missing ComfyUI installation.
python -m pytest tests_studio -q, 2026-10-03: 2 failed, 43 passed, 2 skipped. The two failures are the sprite vault contract and the star_swarm delivery manifest — the suite catching real drift.
◆documents
README.md — the studio, the method in five parts, the provenance table

D:\R1 console\README.md

The flow, the catalogue figures, the detail pass corrections, the audio method, the provenance table, the known traps, and the list of what is still missing.

docs/ARQUITETURA-ALVO.md — target architecture

D:\R1 console\docs\ARQUITETURA-ALVO.md

The official flow and the seven invariants, verbatim.

docs/ACERVO.md — the sprite collection

D:\R1 console\docs\ACERVO.md

What the collection is, how much of it there is, why it cannot be replaced, what was verified and how, and the index migration.

docs/ESTUDIO.md — how a game is made here

D:\R1 console\docs\ESTUDIO.md

The catalogue and index method, the denoise experiment described file by file, and the honest list of gaps.

docs/INVENTARIO-MOTORES.md — engines and generators

D:\R1 console\docs\INVENTARIO-MOTORES.md

The state, canonical destination and version of every registered engine and generator, verified 2026-09-30.

library/triagem/VAULT.json — the verifiable vault contract

D:\R1 console\library\triagem\VAULT.json

The expected file count, byte total, maximum physical path and index SHA-256 that the studio checks against.

LICENSE — third-party attribution and licences

D:\R1 console\LICENSE

Per-file md5 provenance for the GPL art, and the materialised licence position of every third-party component. The studio's own licence is stated as undecided.

registry/ — engines, models, tools, licences

D:\R1 console\registry\

Machine-readable register: engines.toml, licenses.toml, models.toml, tools.toml, each component with state, licence and canonical path.

◆missing

What we could not verify

Back to the lab notebook