Skip to content

feat(duet-keys): real KayKit GLB assets + textured environment - #835

Merged
Noisemaker111 merged 3 commits into
mainfrom
claude/aaa-duet-keys-kaykit
Jul 16, 2026
Merged

Noisemaker111 merged 3 commits into
mainfrom
claude/aaa-duet-keys-kaykit

Conversation

@Noisemaker111

Copy link
Copy Markdown
Owner

Summary

Fresh redo of #832 (closed — wired kenney-mini-dungeon, now barred repo-wide per #829) on KayKit only — zero Kenney assets.

  • Heroes: kaykit-adventurers Mage (Lumen, cyan-tinted) / Barbarian (Anchor, orange-tinted), posed via the rig's Idle clip.
  • Walls: kaykit-dungeon/pillar — a real fluted-stone colonnade around each room instead of flat dark cubes.
  • Gate/plate/receiver/spike: barrier_half / floor_tile_small_decorated / torch_mounted / floor_tile_big_spikes, dynamically tinted via renderObject from live room state — the gate now sinks into the floor when open and spikes physically retract instead of just recoloring a box.
  • Floor: real floor_tile_small tiles (three variants hashed per cell for texture variety) replacing the flat colored plane + debug grid.
  • Emitter/exit: torch / stairs, tinted per hero.
  • Held VFX props: Lumen's prism is a spinning coin crystal, Anchor's weight is a trunk_small_A, replacing primitive octahedron/cylinder geometry.

Engine fix

Found while shooting this: a bare useLoader(GLTFLoader, url, ...) constructs the implicit THREE.DefaultLoadingManager. Under this dev server's repeated navigations that shared singleton manager's internal AbortController can end up already-aborted, which FileLoader.load() composes into every future request's abort signal — silently stalling every subsequent GLTFLoader.load() forever with no thrown error (parsing already-fetched bytes still works fine, so it's a fetch-stage-only hang). packages/shell/src/GamePlayerShell.tsx's EntityModel/BoneAttachment now share one GLTFLoader constructed with a dedicated LoadingManager instead. duet-keys does the same for its own custom model rendering, and — since the engine's static objectModels map resolves through the shell's own loader instance, separate from a game's local one — routes every placed object (including wall/emitter/exit) through its own single loader so its module-level useLoader.preload warms every model it uses before the Canvas render loop starts competing for the main thread.

Assets

kaykit-dungeon + kaykit-adventurers (CC0, KayKit), pulled via assets add. .gitignore whitelists both under apps/dev/public/models/; .glb/texture files are staged in this PR. packages/assets/src/generated/* already carried both source indexes on main (from a sibling PR) — no changes needed there.

Before / after (Room 1, same camera framing)

before
after

Test plan

  • bun run check-types clean (repo-wide)
  • bun run test:all — 4354 pass
  • bun run build clean
  • bun run --cwd Games/duet-keys check-types clean
  • bun test Games/duet-keys — 19/19 pass
  • Before/after screenshots (same room, same camera framing) pushed to pr-shots
  • git status confirmed zero kenney-* files staged

Generated by Claude Code

Replace duet-keys' hand-built primitive shapes with kaykit-dungeon /
kaykit-adventurers GLB models: heroes (Mage/Barbarian, tinted per hero),
gate/plate/receiver/spike (dynamically tinted via renderObject; the gate
sinks into the floor when open and spikes physically retract instead of
just recoloring a box), wall (fluted stone pillars forming a real
colonnade)/emitter/exit, and real floor tiles (three variants, hashed
per cell) replacing the flat colored plane + debug grid. Held VFX props
(prism, anchor weight) are now real crystal/trunk models instead of
primitive geometry. Zero Kenney assets (barred repo-wide, #829).

Fixes a real engine bug found while shooting this: `useLoader`'s implicit
THREE.DefaultLoadingManager can end up with an already-aborted internal
AbortController under repeated dev-server navigations, silently stalling
every future GLTFLoader.load() with no thrown error. GamePlayerShell now
constructs its shared GLTFLoader with a dedicated LoadingManager;
duet-keys does the same, and routes every placed object (including
wall/emitter/exit, which would otherwise sit on the engine's own
objectModels/sharedGltfLoader path) through its own single preloaded
loader instance, so the module-level preload actually warms every model
this game uses before the Canvas render loop starts competing for the
main thread.
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
jgengine-web Ready Ready Preview, Comment Jul 16, 2026 7:24pm

Keep KayKit duet-keys assets/render; take main GamePlayerShell refactor,
generated skill apis, and baselines. Union model gitignore exceptions.
@Noisemaker111
Noisemaker111 merged commit 0356389 into main Jul 16, 2026
5 of 6 checks passed
@Noisemaker111
Noisemaker111 deleted the claude/aaa-duet-keys-kaykit branch July 16, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants