Bullet Heaven / Dark Cosmos — art asset pipeline & workflow
Bullet Heaven / Dark Cosmos — art asset pipeline & workflow
Section titled “Bullet Heaven / Dark Cosmos — art asset pipeline & workflow”Written 2026-07-18 as a handoff reference: how to create and use art assets in this project, which tools to reach for, and in what order. Cross-references
docs/architecture/rendering-and-performance.md(the technical rendering/perf architecture — read that too for anything touching the swarm renderer or quality ladder) andDESIGN.md/PRODUCT.md(the visual style contract). This doc is the process layer; those are the constraints and rules layers.
0. The visual style contract — read this before generating anything
Section titled “0. The visual style contract — read this before generating anything”Everything below serves one look, defined in DESIGN.md/PRODUCT.md: neon-void — near-black space as canvas, one confident cyan accent carrying most UI weight, per-system colours (weapon/element identity) used sparingly and only where they carry real meaning. Anti-references explicitly called out: mobile free-to-play HUD clutter, generic “gamer” bevels/gradients, anything requiring careful reading mid-fight. Any new asset — AI-generated or hand-authored — gets judged against this contract before it gets judged on technical merit. A gorgeous asset in the wrong register (e.g. a busy multi-colour icon, a hard directional key-light) is a rejection, not a polish task.
Two concrete rules that bite generated art specifically:
- Colour discipline: a weapon/element keeps its own identity colour regardless of context (
WeaponPanel._WeaponIcon._COLOR,ElementPalette) — never let a generator’s colour grading drift an asset’s hue away from itsbible.json-defined colour. - Motion register: continuous subtle idle motion (thruster pulse, glow breathing), never static — but never fast/busy enough to compete with gameplay reading. This applies to VFX asset design, not just code.
1. Decision tree — procedural, baked-sprite, or AI-generated?
Section titled “1. Decision tree — procedural, baked-sprite, or AI-generated?”This project deliberately mixes three asset strategies. Picking the right one per-asset is the single highest-leverage decision in this whole pipeline — the wrong one either tanks performance at swarm scale or wastes an artist/generation pass on something code already does better.
Is this entity drawn in large numbers simultaneously (enemies, projectiles, gems — "swarm scale")?├─ YES → Procedural shape + MultiMeshInstance2D + additive halo (ArchetypeRenderer/SwarmRenderer).│ Do NOT bake glow into swarm-scale sprite textures — confirmed imperceptible next to the│ existing runtime additive halo (tried and shelved on ghost/orbiter-scale sprites).│ Confirmed by research: Nova Drift's own baked-glow-sprite technique is real, but the│ payoff is at boss/hero scale, not swarm scale — see docs/research/2026-07-05-nova-drift-│ visual-style-tech.md.│└─ NO — this is a hero/singular/one-off asset (player hull, a boss, an icon, marketing key art) │ ├─ Does it need to rotate/reorient in-engine, or show tier/state variation procedurally? │ └─ YES → Bake a sprite from the project's OWN procedural renderer via tools/ship_preview │ (SHIP_VARIANT=bake / hero3d / current), so the sprite is provably consistent with │ what the game actually simulates. This is how the shipped app icon was made — a │ hero3d render of the real starter hull, not an artist's "inspired by" reinterpretation. │ └─ NO — it's genuinely one-off reference/key art (concept art, marketing, an icon with no in-engine procedural source, a boss/enemy sprite where hand-authored detail beats a procedural shape) → AI-generate (Section 3), then glow-bake if it's boss/hero-scale (tools/glow_bake), then verify in-engine before committing.The load-bearing principle behind all three branches, straight from the polish-audit categories’ “asset-fiction mismatch” finding: an asset must show what the game actually IS, not a generic reinterpretation of it. The old app icon failure (generic neon-teal emblem, zero resemblance to the real cobalt hull) happened because someone treated icon generation as independent of the game’s own renderer. Always generate FROM or verify AGAINST the real in-game recipe/data, never from imagination alone.
2. Tool stack — what to reach for, in order
Section titled “2. Tool stack — what to reach for, in order”2a. In-house Godot bake/preview tools — reach for these FIRST for anything with an in-engine procedural source
Section titled “2a. In-house Godot bake/preview tools — reach for these FIRST for anything with an in-engine procedural source”| Tool | Command | Use for |
|---|---|---|
tools/ship_preview/preview.tscn |
godot --path . res://tools/ship_preview/preview.tscn --rendering-method forward_plus (windowed — headless can’t render shaders/MultiMesh) |
SHIP_VARIANT=current/enhanced (2D procedural hull, 5 tiers), =3d (real 3D Ship3DRenderer), =hero3d (one large flagship render — icon/logo source), =bake (grabs SubViewport per ship class → render/ship_sprites/ship3d_*.png), =bake_tilt (baked-angle flipbook frames) |
tools/glow_bake/bake_*_glow.gd |
godot --headless --path . -s res://tools/glow_bake/bake_orbiter_glow.gd (headless OK — pure Image/CPU work) |
Pre-composite a Nova-Drift-style layered glow into a sprite’s own pixels: tight glow (downscale 10, opacity 0.55) + wide glow (downscale 26, opacity 0.35) + diffuse ~20%-opacity radial layer. Boss/hero scale only — confirmed a no-op at swarm scale. |
tools/bg_preview/preview.tscn |
godot --path . res://tools/bg_preview/preview.tscn --rendering-method forward_plus (windowed) |
Iterate ArenaBackground variants (BG_VARIANT=grid/starfield/nebula/aurora/galaxy) before wiring a new one into main.gd. Pick camera zoom for legible element size, not full-arena fit. |
tools/shop_lab/shop_lab.tscn |
godot --path . res://tools/shop_lab/shop_lab.tscn (windowed) |
Isolated sandbox for shop/card visual styles — hack freely, only port a settled design back into the real meta_shop_panel.gd. |
tools/funzo_lab/preview.tscn |
godot --path . res://tools/funzo_lab/preview.tscn --rendering-method forward_plus (windowed) |
Sandbox for boss attack-pattern VFX treatments (TREATMENT= env var) against a real minimal Sim. |
tools/ui_sweep/sweep.tscn |
godot --path . --rendering-method mobile res://tools/ui_sweep/sweep.tscn, then scripts/ui-sweep.sh [--bless] |
Mandatory regression gate for any UI-visual change — screenshots every menu/panel, diffs against 9 blessed baselines (RMSE 0.06). Never skip this after touching UI art/styling. |
All of these are windowed-only except glow_bake — headless Godot cannot read back MultiMesh/shader/_draw() output (a dummy RenderingServer returns 0/black), so pixel-level visual verification always needs a real GPU pass.
2b. External AI generation — for genuinely new reference/key art with no procedural source
Section titled “2b. External AI generation — for genuinely new reference/key art with no procedural source”Already proven in this project (use these first, they have working techniques documented):
- Gemini web (
gemini-image-video-music-genskill) — used for concept art (concept-art/gemini/, 10 pieces: hero keyart, boss portraits, bestiary sheet, VFX reference, icon exploration, marketing hero backgrounds) and the shipped app icon (generated from ahero3dreference render of the real starter hull). Comes with a working SynthID watermark-removal technique (flat-top-mask blur-inpaint) already in the skill — don’t reinvent this. - Recraft — source of the Orbiter and Warden enemy sprites (native alpha, wired into dedicated
ArchetypeRenderershape buckets). Referenced in-repo as the intended tool for “reference-image character-consistency” work — i.e. generating a new asset that must visually match an existing one across variations (exactly the Ship Tilt / cruiser problem below).
Current landscape worth knowing about (verified via web search, 2026):
- Recraft V4 remains one of the strongest options in 2026 specifically for design-oriented, consistent vector/character generation — a reasonable default to keep using rather than chase alternatives.
- Scenario (scenario.com) is the current standout for studio-grade style-locked generation: you train a small custom model on your own art (their own docs recommend 10-15 curated images, capped around 20 — they explicitly discourage pushing toward larger sets), then generate new props/enemies/UI in that exact style indefinitely. Worth evaluating if/when this project wants to generate many more enemy or item sprites in a consistent hand-authored style rather than one-off pieces — probably premature for the current asset volume, but the right tool if the “12 promotable enemy types need bespoke art” backlog item (Section 4) ever gets tackled as a batch.
- Multi-angle/turnaround generation (directly relevant to Section 4’s Ship Tilt problem): dedicated “character/ship turnaround” and “8-direction sprite” generators now exist that take one reference image and output consistent multi-angle views. The underlying technique when more control is wanted: FLUX.1-dev + a trained LoRA + view-direction prompting in a multi-panel ComfyUI workflow, or SDXL + OpenPose/ControlNet conditioning on a turnaround template. Expect to generate 10-20 candidates and hand-pick — full automation isn’t there yet.
- ComfyUI — Chris already runs a local ComfyUI/LoRA pipeline for photorealistic product work (see memory
comfyui_imagen_workflow.md,lora_training_stack.md). That pipeline is tuned for photoreal output, not this game’s stylized neon look — don’t reach for it by default here. If asset volume ever justifies standing up a dedicated stylized pipeline, the 2026 indie playbook is: workflow JSONs committed to the repo (e.g. apipeline/comfyui/dir), outputs written to a staging folder, a human review step before anything moves intorender/enemy_sprites/or similar. That’s more infrastructure than this project’s current asset cadence (occasional hero/marketing pieces) needs — don’t build it speculatively.
Baked-hull sprite generation prompt pattern (confirmed working, from docs/architecture/godot-gotchas.md): “flat top-down orthographic, nose-up, symmetric, no perspective, isolated on plain background.” Any generated hull/ship art that will rotate in-engine MUST follow this — a 3/4 hero-shot with directional shadows breaks the instant the sprite rotates, since there’s no per-frame relighting shader. Isolate alpha via flood-fill from the image corners, never a global colour threshold (a threshold strips enclosed bright details like engine glow).
2c. Why generated assets keep coming out “not quite right” — and the fix
Section titled “2c. Why generated assets keep coming out “not quite right” — and the fix”Diagnosed 2026-07-18 after repeated near-misses with ad hoc Recraft prompting. The root cause almost never turns out to be Recraft’s raw capability — it’s that every generation has been an independent, un-anchored prompt, with no persistent style lock and no hard colour constraint. That produces exactly the symptom described: individually plausible images that don’t cohere into one game’s look.
The concrete fix, in priority order:
- Build and save a Recraft Custom Style from this project’s OWN existing assets, before generating anything new. Recraft supports uploading 1-5 reference images, extracting “the essence” of them, and saving that as a reusable named style applied to every future generation (
recraft.ai/docs/best-practices/character-consistency). Feed it: 2-3 pieces fromconcept-art/gemini/(the hero keyart + a boss portrait), the Orbiter/Warden sprite pair, and atools/ship_previewhero3drender. Use “Style essentials” mode (colours/textures only), not “Style & composition” — the latter also locks in layout/framing, which fights the flat-top-down-orthographic requirement for anything that needs to rotate in-engine. This single step is the biggest lever available: it’s the difference between “regenerate from scratch and hope” and “every new asset is a variation on an already-locked look.” - Enforce a hard, small colour palette in every prompt — don’t let the model free-associate colour. The clearest real-world validation of this: Void Balls, a 2026-shipped indie game in the same genre (2D roguelite bullet-hell, Vampire-Survivors-adjacent) built with an AI stack of Claude Code + Replicate + ElevenLabs, attributes its asset cohesion specifically to a 7-colour palette constraint applied to every generation — “without it, AI-generated art looks like a random collage; with it, everything feels intentional and unified.” This project already has the equivalent discipline defined (
bible.json’s per-element/enemy colours, the single-cyan-accent rule inDESIGN.md) — the fix isn’t inventing a new constraint, it’s actually quoting the exact hex values frombible.json/NeonThemein the generation prompt itself, not just checking the result against them after the fact. - Use reference images + frames for anything that must match an existing asset, not a fresh prompt each time. Recraft’s reference-image workflow (attach a prior generation or upload, set it as visual context) and its “frames” feature (edit an isolated part — pose, colour, detail — without regenerating the whole composition) are the documented tools for this. This is the exact mechanism to use for the Ship Tilt per-hull art gap and the cruiser re-bake.
- Reconsider whether Recraft is even the right tool for every asset type. Void Balls’ actual split:
replicate/flux-2d-game-assets(a Flux LoRA trained specifically on game-asset aesthetics — vector-like graphics, sprites, icons, UI elements; ~$0.006/generation, ~4s) as the primary “workhorse” for characters, enemies, and icons, with Recraft V4 Pro reserved for backgrounds/environments where a more painterly result is wanted. That division of labour matches this project’s own needs closely (small stylised enemy/ship sprites vs. atmospheric arena backgrounds) and is worth adopting rather than pushing Recraft to do both jobs. Needs aREPLICATE_API_TOKEN(not currently in~/.secrets— would need signing up). - For the specific multi-angle/turnaround problem (Ship Tilt’s per-hull flipbook art), also consider PixelLab — its stated differentiator is that its tools “see and understand” an uploaded reference image while generating variations (8-directional sprites, pose/accessory changes) rather than reinterpreting from a text prompt alone, which is a stronger consistency guarantee than Recraft’s reference-image-as-context approach for this specific use case. (It’s built for pixel art’s grid/palette constraints specifically — evaluate whether its output still reads correctly once scaled/anti-aliased for this project’s smooth-vector style, don’t assume it transfers.)
Confirmed hands-on, 2026-07-18 — Chris’s existing Recraft project already showed the failure mode
Section titled “Confirmed hands-on, 2026-07-18 — Chris’s existing Recraft project already showed the failure mode”Logged into Chris’s real Recraft account and found this project already had prior generation attempts sitting in it — direct, visible evidence of the “not quite right” complaint, plus two new causes the research above didn’t surface:
- Likely biggest cause: “Auto mode” (Recraft Studio’s default model picker) silently defaults to a painterly/photoreal-leaning model, not a flat-vector one, and can pick a DIFFERENT model on every generation. A prior “alien creature” prompt found already in the project (run under Auto mode, exact date/settings unknown) had produced two visibly different failures across its two saved outputs — one with a hazy grey-gradient backdrop, one with a solid white backdrop — despite both explicitly asking for “dark void aesthetic, no background.” A fresh generation in this session, with the model explicitly pinned to
Recraft V4.1 Vectorinstead of Auto, produced a noticeably better result: a solid true-black background exactly as asked, and crisp flat geometric linework instead of a soft indistinct blob. Caveat — this is not a clean controlled comparison. The fresh attempt also used a reworded, more explicit prompt (dropped “transparent”/“no background” framing in favour of “solid pure black background,” added “flat vector illustration style”), and an unknown time/model-version gap separates it from the two older images — so the improvement can’t be cleanly attributed to model-pinning alone; prompt wording and/or model drift over time could each explain some or all of it independently. The underlying mechanism (Auto mode silently varying model choice) is real, documented Recraft Studio behaviour, so pinning a model explicitly is still a sound, low-cost default — just don’t treat this specific before/after as proof of the mechanism until it’s re-tested as a same-session, same-prompt, Auto-vs-pinned A/B. Pick a model explicitly (theModelbutton next to the prompt box) for anything going into the game, matching it to the asset type (see the generalgame-art-generationskill for the full model-selection table) rather than just avoiding Auto for its own sake. - “Transparent background” / “no background” as prompt TEXT is confirmed unreliable — exactly as suspected, neither of the two Auto-mode attempts produced anything resembling transparency; both produced an opaque, unwanted backdrop. What worked instead: asking for a solid, single flat colour background (“solid pure black background”) rather than “transparent” — gives the model an achievable literal instruction, and the result is trivially alpha-keyable afterwards.
- Recraft’s own one-click “Remove background” tool is NOT reliable and must be eyeballed, not trusted blindly. Ran it on the successful V4.1 Vector generation above — it inverted the mask, keeping the black ring linework as “foreground” and cutting out the actual glowing core. Likely cause: the foreground had thin dark linework sitting close in tone to the black backdrop, confusing the segmentation. Design implication: keep an asset’s actual foreground content bright/saturated and avoid thin dark linework touching a dark background if it needs one-click removal to work — or skip the tool and use the manual flood-fill-from-corners technique (Section 2b) instead, which works on pixel position/colour rather than a learned segmentation model and isn’t fooled by this.
- Recraft Studio’s “AI chat” mode is itself an LLM agent that restructures your prompt before generating — it is not a raw passthrough. Visible in its own “Thinking” trace: given a prompt with a literal hex colour, it decided to move that value into a separate structured
colorsparameter instead of leaving it in the text description, because the underlying tool exposes that as a dedicated field. This is a real source of run-to-run inconsistency for anything but the simplest prompts — two similar requests can get reinterpreted differently by this intermediary layer. For reproducible results, prefer explicit structured settings (the Style/Palette/Aspect-ratio controls in the Settings panel) over trusting the chat agent to correctly extract them from prose, or use the separate “Create” tab if it exposes the same controls without the conversational rewriting step. - A previous attempt at this exact project mechanically leaked internal reasoning notes into the live prompt sent to Recraft — the saved prompt text literally included a parenthetical like “(Recraft’s native-alpha mode needs the explicit ask)” as part of what was submitted to the model, not just as a private note. That kind of meta-commentary bleeding into user-facing generation content will degrade output independent of any model/style choice. Always re-read a prompt in full immediately before submitting it — a stray aside meant as a note-to-self is easy to miss once it’s buried inside a long paragraph.
- “Generate a sprite sheet of N frames rotating through angles” in one shot is unlikely to work well — a prior attempt (found already in the project, unknown model/date, not a fresh controlled test) asking for an 8-frame 4×2 grid of a ship “rotating through banking angles from left-roll to right-roll” produced 8 near-identical ships in the same orientation, not an actual angle progression. No retry was attempted with a different model or a more explicit per-frame prompt, so this single example doesn’t rule out a cheaper fix within Recraft itself — but it’s consistent with the general research finding that diffusion-style models lack a real 3D representation to rotate. Treat single-prompt multi-angle grids as high-risk, and prefer either a dedicated turnaround tool (PixelLab) or generating one angle at a time with reference-image consistency.
- Bonus finding, not yet exploited: Recraft Studio is a full multi-model aggregator under one credit pool — Nano Banana/Nano Banana Pro (Google), GPT Image 2 (OpenAI), Flux 2/Kontext (Black Forest Labs), Seedream, Ideogram, Krea, ImagineArt, Qwen, Grok Imagine, and NVIDIA models are all directly selectable from the same
Modelmenu already used to pin V4.1 Vector. Chris doesn’t need separate accounts to A/B a Recraft result against Nano Banana Pro or GPT Image 2 High — just pick a different entry from the same menu, same project, same credits.
3. The end-to-end workflow (every new hero/one-off asset)
Section titled “3. The end-to-end workflow (every new hero/one-off asset)”- Check the decision tree (Section 1). Confirm this genuinely needs generated/baked art rather than a procedural shape — procedural is cheaper to maintain and automatically theme-correct (see the Centurion enemy’s colourless
SHAPE_ROSETTE, which inherits whatever colour its current Elemental Dimension assigns with zero tinting code). - Source of truth first. If there’s an existing in-engine recipe (a ship class, a boss’s real stats/behaviour), generate FROM it (a
tools/ship_previewrender as the reference image) or verify AGAINST it — never invent independently. - Generate via Gemini/Recraft (Section 2b), following the orthographic/isolated-background prompt pattern if it’s anything that rotates.
- Clean up: remove any watermark (Gemini’s SynthID technique), isolate alpha from corners, confirm native alpha (no baked-in background).
- Glow-bake if boss/hero scale (
tools/glow_bake) — skip entirely for swarm-scale entities. - Wire in — mind the Godot art gotchas in Section 5 (colour LUT sizing,
modulatevs per-instance colour, adaptive-quality wiring for any new full-screen/decorative effect). - Verify in-engine, windowed — through the matching preview tool (
ship_previewfor hulls,funzo_labfor boss VFX, etc.) before committing. Headless cannot show you the real pixels. - Run the regression gate —
scripts/ui-sweep.shfor anything UI-visual; ascripts/soak.shrun for anything gameplay/swarm-visual. - Apply the polish-audit lens (Section 6) before calling it done — this is the “does it actually look right and read correctly” pass, distinct from “does it run.”
4. Concrete backlog — the actual next art tasks, in priority order
Section titled “4. Concrete backlog — the actual next art tasks, in priority order”These are the real open items found in CLAUDE.md, ROADMAP.md, and docs/superpowers/plans/2026-06-25-graphics-perf-plan.md — use them as the first test cases for whichever workflow above gets used:
- Obsidian cruiser is on a placeholder Aurum-copy sprite. Lowest-effort fix, pure execution of Section 2a:
tools/ship_previewSHIP_VARIANT=bakefor the cruiser class, verify at=currentacross its tier range, commit. - Player upgrade-tier indicator has no design yet (the orbiting accent-orb was removed 2026-07-16 with nothing decided to replace it). This needs a brainstorm/spec pass with Chris before any generation — genuinely undesigned, not just unbuilt. Constraint from
PRODUCT.md: prefer diegetic feedback (something the ship itself does) over a new abstract icon. - Ship Tilt baked flipbook only has matching art for the
cobalthull (5 procedurally-baked angle frames). Other hulls need the same treatment. This is the best current fit for a multi-angle/turnaround AI workflow (Section 2b) — Recraft’s reference-image consistency approach, or a dedicated turnaround/8-direction generator, seeded from each hull’s existingship_previewbake. - Normal-mapped 2D hull lighting —
render/hero_lights.gdonly does a flat glowPointLight2Dtoday. The exact missing piece (aSprite2D-via-CanvasTexturediffuse+normal setup withLightOccluder2Dshadows) is already a working, reviewed reference implementation at~/Claude/godot-graphics-showcase/techniques/2d/dynamic_lighting_2d.gd— port the technique rather than re-solving theSprite2D-has-no-normal_mapproblem from scratch. This is a rendering-code task more than an asset-generation one, but it changes what a baked hull sprite needs to supply (a normal map alongside the diffuse texture). - Full palette overhaul (OKLCH hue re-spacing across every element/enemy colour in
bible.json) — explicitly flagged in the perf plan as “subjective, wants Chris’s eye.” Not a generation task; needs Chris reviewing swatches directly, possibly viatools/design-bible. - 12 promotable enemy types get only a generic elite buff, no bespoke art. Lowest priority, largest volume — the one item where a style-locked batch tool like Scenario (Section 2b) could genuinely pay off if tackled all at once rather than one sprite at a time.
5. Godot art/asset gotchas (from docs/architecture/godot-gotchas.md, art-relevant subset)
Section titled “5. Godot art/asset gotchas (from docs/architecture/godot-gotchas.md, art-relevant subset)”SwarmRenderer.configure(color)setsmodulate, andsync()separately sets per-instance colour — passing the same colour to both squares/darkens it. Configure withWHITE; let per-instance colour drive the look.ArchetypeRenderer.sync()takes a per-enemy colour array indexed by slot, not a per-type lookup table — get this wrong and per-enemy aura/boss tints silently no-op.- Any render-side type→colour LUT must be sized by the max type id, not the entry count (ids are non-contiguous) — undersizing indexes out of bounds.
- A windowed preview harness that fits an entire large arena in a small window can render sparse elements (e.g. individual stars) functionally invisible below a screen pixel — pick camera zoom for legible element size, not full-scene fit.
- Any new glow/additive visual must be wired into the adaptive-quality toggle (
render/quality_manager.gd) or it silently ignores every quality tier and costs full overdraw regardless of device performance. This matters more than usual right now —ADAPTIVE_QUALITY := falsesince 2026-06-28 (re-enabling is gated on the v0.1 release), so nothing is currently catching an expensive new effect automatically. SwarmRenderer.sync()’sscalesparam and its velocity-oriented_orientmode are mutually exclusive — passing per-instance scales silently drops orientation.- Any windowed (non-
--headless)godot --path .invocation can silently corruptproject.godot(mangled comments, dropped sections). Alwaysgit diff project.godotimmediately after any windowed preview/bake run.
6. The polish-audit lens — apply before calling any art task done
Section titled “6. The polish-audit lens — apply before calling any art task done”Four reusable issue-classes (.claude/skills/bh-overnight-audit-loop/references/polish-categories.md), each phrased as a question to ask of a finished asset:
- Asset-fiction mismatch — does this show what’s actually in the game, or a generic reinterpretation nobody circled back to correct? (Compare directly against the real in-game asset/recipe.)
- Snap-vs-ramp — if this asset drives a continuous quantity (HP, charge, danger), does it read continuously, or does it hard-cut at a threshold?
- UI pattern inconsistency — does this match the established visual pattern for its class of screen, or is it a stale holdover from before that pattern existed?
- Invisible progression — if this is a weapon/ability upgrade, can the player actually perceive the upgrade visually, or only via a menu stat?
Related docs
Section titled “Related docs”docs/architecture/rendering-and-performance.md— the technical rendering/perf architecture (swarm rendering, adaptive quality ladder, renderer split).docs/research/2026-07-05-nova-drift-visual-style-tech.md— the sourced research behind the baked-glow-sprite technique.DESIGN.md/PRODUCT.md— the visual style contract and UI design system..claude/skills/bh-overnight-audit-loop/references/polish-categories.md— the full audit method (Section 6 is a condensed pointer, not a replacement).- Skill
gemini-image-video-music-gen— the SynthID-removal technique referenced in Section 2b.
Player drone sprites (2026-09-29)
Section titled “Player drone sprites (2026-09-29)”The five drone classes (sentinel = Decoy, bomber, interceptor, disruptor, logistics) use the same Nova plate/seam/glow recipe as the enemy units, drawn in code (Python/PIL, not AI-generated): designs are DRONES in tools/nova_units/nova_unit_designs.py, preview with --preview-drones <dir>, export with --export-drones render/enemy_sprites/nova (then godot --headless --path . --import). Drawn by render/drone_sprites.gd (DroneSprites.draw) from DecoyRenderer (field, additive material) and DronePanel (top-left readout); the triangle is the fallback when VisualLook.nova is off or a texture is missing. Drone textures are exported UNflipped (plain draw_texture_rect), unlike the enemy exports which are pre-flipped for QuadMesh. Field size is DecoyRenderer.SPRITE_RADIUS. Design lesson: a tall narrow body with two round pods at its base reads as phallic; keep bilateral silhouettes roughly as wide as tall.