Status: Analysis only. No C++ code changed. No sibling repository modified. This document records confirmed facts, recommendations, and open questions as of 2026-07-01.
Status update (2026-07-05): the recommendations below were acted on. GalaxyEggbertCNA
(src/GalaxyEggbertCNA/) now exists as a real, working, opt-in build target (builds via
-DGALAXY_EGGBERT_BUILD_CNA=ON, renders real textured/animated 3D terrain), and Easy3D gained a
real renderer (CubeMesh/CubeMeshRenderer) — see NEXT.md for current, up-to-date status. The
facts, rationale, and recommendations captured below are preserved as the historical record of why
those decisions were made; do not read "not yet built"/"does not exist" statements below as
describing the current state — check NEXT.md for that.
Status update (2026-07-08): GalaxyEggbertSimple3D (referred to throughout this document as
"the current Simple3D path") is now historical reference only — it is not built, fixed, or
maintained going forward (see CLAUDE.md's "Current Direction Lock"). By 2026-07-09,
GalaxyEggbertCNA reached terrain/object rendering parity with everything terrain/object-related
this document analyzes (all 4 tile render modes, water, MoveObject/BigDecor billboards,
platform-lift/crate objects, face culling) — the remaining gap to Simple3D is Blupi's visible
sprite, HUD, sound, and gameplay logic (§12's open questions below are mostly resolved by now; see
inline annotations).
Retirement update (2026-07-25): CNA subsequently reached playable parity and the user
explicitly approved Phase 11. The retired source tree, CMake target/option, and its obsolete
verifier tools were removed from the live tree as CLEANUP-S3D-001; the last pre-removal state is
recoverable at git commit 4afd53e. All descriptions and recommendations below remain unchanged
as a historical migration record and must not be interpreted as current build instructions.
Galaxy Eggbert is a faithful 3D remake of mobile-eggbert (itself a CNA-based port of Speedy Blupi). The project's build direction is changing:
- Old direction (superseded):
Galaxy Eggbert → Simple3D → Urho3D / Nova3D → (CNA someday) - New direction (target):
Galaxy Eggbert → CNA directly, withEasy3Dused beside CNA for small reusable 3D helpers (cameras, billboard/cube batching, texture atlas, debug draw).mobile-eggbertis used as a read-only reference/asset/data source, not as code to modify.
Three facts drive the shape of this migration plan:
- Galaxy Eggbert's own
README.mdalready describes the target CNA build (target nameGalaxyEggbert,CNA_BACKEND_*CMake flags, Web/Windows cross-build instructions) — butCMakeLists.txtdoes not yet define any such target. The README was apparently written ahead of the code.CLAUDE.md,NEXT.md, andplan.mdstill describe the Simple3D/U3D/Nova3D direction as current. These documents are now inconsistent with each other and need to be reconciled (see Phase 0 tasks inplan.md). - Easy3D has no renderer. It has real, working cameras (
Camera3D,OrbitCamera,FollowCamera) and a genuinely CNA-freeTextureAtlas, butBillboardBatch,CubeBatch, andDebugDraware confirmed to be pure CPU-side item queues — grepping their implementation for any GPU/draw-call symbol (shader, vertex buffer, index buffer,GraphicsDevice,SpriteBatch,BasicEffect) returns nothing. Turning queued items into pixels on screen is not yet built, in Easy3D or anywhere else. - mobile-eggbert cannot currently be linked as a CMake library. Its top-level
CMakeLists.txtonly definesadd_executable(WindowsPhoneSpeedyBlupi ...)(globbing all ofsrc/*.cpp); there is noadd_library()target anywhere, and no sub-CMakeLists.txtforinclude/orsrc/. Direct-link reuse of mobile-eggbert C++ code is not possible today without a mobile-eggbert-side change — which is out of scope for this migration unless the user explicitly approves it.
Because of (2) and (3), the realistic first playable milestone for the CNA/Easy3D path is much smaller than "full gameplay parity." It is: an empty CNA window, Mobile Eggbert's world format loaded and parsed, terrain drawn as flat-colored or simply-textured geometry, and Blupi rendered as a 2D billboard using Mobile Eggbert's own sprite frames — with a hand-written (not linked) terrain/billboard renderer built on top of Easy3D's CPU-side batches, since no such renderer exists yet anywhere in the stack.
Confirmed via inspection of src/GalaxyEggbertSimple3D/ and CMakeLists.txt:
-
The only buildable game target today is
GalaxyEggbertSimple3D(option(GALAXY_EGGBERT_BUILD_SIMPLE3D "Build the Simple3D port target" ON)), linkingsimple-3d(found viaSIMPLE3D_HOME, default../simple-3d), which in turn wraps U3D (Urho3D fork). The build hardcodes a U3D binary/data path (/rv/data/library/github.com/u3d-community/U3D/...) and copiesData/CoreData+Content/worldsnext to the binary post-build. -
There is no
GALAXY_EGGBERT_ENGINECMake option inCMakeLists.txttoday, despiteCLAUDE.mddocumenting one (-DGALAXY_EGGBERT_ENGINE=U3D/NOVA3D). That option is aspirational/historical, not currently wired up. -
The old direct-Urho3D tree (
GalaxyEggbertApp,GalaxyEggbertGame, aGalaxyEggberttarget linking Urho3D directly), once kept as a "historical reference until S3D-9" per the (since completed and deleted, 2026-07-05) Simple3D migration docs, no longer exists on disk.src/GalaxyEggbert/today contains only the engine-agnosticWorlds/subtree. -
src/GalaxyEggbertSimple3D/totals 3,251 lines across 10 files:File Lines Simple3D-coupled? GalaxyEggbertSimpleGame.cpp768 Yes Game/Hud.cpp624 Yes Game/GEDecorSystem.cpp305 Yes Game/BlupiController.cpp270 Yes Game/TerrainRenderer.cpp249 Yes Game/WorldRuntime.cpp176 Yes Game/GEBridgeSystem.cpp66 No — only includes GalaxyEggbert/Worlds/World.hpp,<vector>,<set>Game/GEExploSystem.cpp50 Yes Game/Sound.cpp58 Yes Game/GECameraRig.cpp22 Yes Every
Game/*.hppexceptGEBridgeSystem.hppincludes<Simple3D/Simple3D.h>.GEBridgeSystemis the one class in this tree that is already engine-agnostic pure logic. -
The Simple3D API-gap tracker (deleted 2026-07-05 once the Simple3D migration finished with zero outstanding gaps) enumerated 18 Simple3D engine-facing capabilities actually in use: tile-atlas UV offset, billboard UV-region crop, fog, ambient light, camera shake, UI image UV crop, UI progress bar, full-screen fade panel, particle emitter, looped 3D audio source + listener, save data, input action binding, trigger volumes, character controller, orbit camera, camera collision avoidance, scene fade transitions, sky dome, and 93-channel indexed audio. This list (preserved here since the source doc is gone) is a useful checklist of engine capabilities any CNA/Easy3D replacement will eventually need to cover — not a checklist to port literally, since CNA/Easy3D has a completely different API shape.
-
An old Urho3D-class → Simple3D-class mapping table (also deleted 2026-07-05 along with the rest of the completed migration's docs) is still recoverable from git history if needed purely as behavioral reference (what each class was responsible for), independent of which engine ends up implementing it.
-
NEXT.mdconfirms the Simple3D build is functionally quite far along: world loading, textured terrain with animated tiles (lava/crusher/saw/spike/water/fan/marine/temp using mobile-eggbert's own frame tables), Blupi billboard with full state machine, mobile-object billboards, a crate push mechanic, platform patrol, hazard/kill detection, enemy stomp, respawn invincibility, pickups (treasure/keys/shield/egg/drink), exit-gate logic, HUD, save/load, and full 93-channel sound. This is real, working, faithful-to-mobile-eggbert gameplay — it is not being discarded because it's broken, but because the underlying engine dependency chain (Simple3D → Urho3D/Nova3D) is being abandoned in favor of CNA + Easy3D.
include/GalaxyEggbert/ and src/GalaxyEggbert/Worlds/ are confirmed fully engine-agnostic:
Worlds/*.hpp(Block,BlockMetadata,Chunk,VoxelConfig,World) include only<cstdint>,<vector>,<filesystem>,<array>,<stdexcept>— no graphics/engine headers.Def/*.hpp(BlupiAction,ContinueMissionType,DecorAction,Direction,DoorKeyFlags,GamePhase,GameSpeed,KeyPressFlags,ObjectType,SecretPower,SoundChannel,SpriteChannel) andBlockTypes.hpp,Def.hpp,GameConstants.hppare plain enums/constants.- The world-file parser reads the identical text format used by mobile-eggbert
(
DescFile: posDecor=...;... dimDecor=100;100 world=... music=... region=... blupiPos=...;... blupiDir=...header line, then aDecor:marker, then a 100×100 grid of comma-separated tile codes).
This whole tree is portable as-is to the CNA/Easy3D target with no changes required — it does not depend on Simple3D, Urho3D, or any rendering API at all.
GalaxyEggbertWorldsTests (54 gtest cases) links only this engine-agnostic tree and should
continue to build and pass unmodified under the new direction.
../easy-3d is a small, complete (not sprawling), C++23 static library, CMake target easy3d
(alias easy3d::easy3d), namespace Easy3D, version 0.1.0. Its own docs (README.md,
docs/ARCHITECTURE.md, CLAUDE.md) are explicit and self-consistent about being a companion
library beside CNA, not an engine and not a wrapper that hides CNA. It expects ../cna as a
sibling providing a CMake target literally named CNA.
| Header/class | Confirmed state | CNA-coupled? |
|---|---|---|
Version.hpp/.cpp |
Fully implemented, trivial | No |
TextureAtlas.hpp/.cpp (95 lines) |
Fully implemented: Add, AddGrid (row-major spritesheet registration), Contains, GetRect, GetUv, GetUvOrDefault, Count, Empty; own AtlasRect/UvRect PODs |
No — the most mature and most reusable-as-is class in Easy3D |
Camera3D.hpp/.cpp (33 lines) |
Real implementation: position/target/up/fov/aspect/near/far, GetViewMatrix()/GetProjectionMatrix() via CNA Matrix::CreateLookAt/CreatePerspectiveFieldOfView |
Yes — compiles header-only, but executing view/projection math requires linking CNA |
OrbitCamera.hpp/.cpp |
Real implementation (yaw/pitch/distance → position), verified by test | Yes, same reason |
FollowCamera.hpp/.cpp (67 lines) |
Real implementation: frame-rate-independent exponential smoothing (kSmoothingReferenceFps = 60), verified by test |
Yes, same reason |
BillboardBatch.hpp/.cpp |
CPU-side item queue only (Add, Items, Begin/Clear/Empty/Count) |
No — but also no rendering |
CubeBatch.hpp/.cpp |
CPU-side item queue only | No — but also no rendering |
DebugDraw.hpp/.cpp |
CPU-side line/box queue only | No — but also no rendering |
Confirmed by direct grep across include/ and src/: zero occurrences of shader, vertex
buffer, index buffer, GraphicsDevice, draw-primitives, BasicEffect, or SpriteBatch symbols.
Easy3D issues no GPU draw calls anywhere in the current codebase.
Tests (test_basics, test_texture_atlas, test_camera, test_batches, plus two
compile-only *_compilecheck targets) genuinely exercise the claimed behavior — nothing appears
mocked or vacuous. docs/ROADMAP.md/NEXT.md self-report Phase 0–2 (scaffold, cameras,
CPU-side batching/atlas) done, Phase 3 (CPU-side vertex builders) as the next, not-yet-started
task, and Phase 4 (actual CNA GraphicsDevice draw calls) as explicitly gated behind a "CNA
draw-path decision" that has not yet been made. docs/QUESTIONS.md records that Blupi is
intended to render as a 2D billboard from Mobile Eggbert sprites, and that billboard/cube/tile
rendering only (no 3D models) is the current decision for the near term — this matches the
constraint given for this migration task.
Easy3D's own CLAUDE.md explicitly instructs agents working in that repo not to modify ../cna,
../sharp-runtime, ../mobile-eggbert, or ../galaxy-eggbert, and not to read/copy from
../simple-3d, nova-3d, or mesh-craft — consistent with the constraints given for this task.
../mobile-eggbert is a CNA-based C++ port, namespace WindowsPhoneSpeedyBlupi, depending on
../cna (via add_subdirectory(../cna CNA)), SDL3, SDL3_image, SDL3_mixer.
Build-target reality check (critical): the top-level CMakeLists.txt globs all of src/*.cpp
into a single add_executable(WindowsPhoneSpeedyBlupi ...). There is no add_library() anywhere
(the Android build's add_library(main SHARED ...) is just SDL activity glue for the same
executable-equivalent code, not a reusable library). There is no sub-CMakeLists.txt under
include/ or src/. Mobile Eggbert cannot be linked as a CMake dependency today without a
mobile-eggbert-side change.
| Component | Lines | Coupling | Assessment |
|---|---|---|---|
Game1.hpp |
955 | Owns GraphicsDeviceManager, IPixmap, ISound, Decor, InputPad, GameData, Jauge; drives the Def::Phase state machine; implements the XNA Update/Draw loop |
Top-level orchestrator, heavily CNA-coupled — architecture reference only |
Decor.hpp / Decor.cpp |
2,064 / 11,720 | Includes GameData, IPixmap, ISound, Tables, System::Random, Jauge, DecorAction, DoorKeyFlags, ObjectType, PixmapChannel; holds m_pixmap/m_sound as members |
Canonical gameplay simulation — see §5.2 for detailed reuse assessment |
Pixmap.hpp / .cpp (238/609 lines incl. IPixmap.hpp) |
— | Includes CNA Vector2, GraphicsDeviceManager, Graphics/SpriteBatch, SpriteEffects, Texture2D, Rectangle directly |
Confirmed 2D SpriteBatch wrapper — not reusable for a 3D renderer; useful only as a reference for which PixmapChannel maps to which PNG/frame layout |
Sound.hpp / .cpp (134/427 lines incl. ISound.hpp) |
— | Includes CNA SoundEffect, SoundEffectInstance directly; PlayImage takes a TinyPoint screen position (2D panning) |
Confirmed CNA-audio-coupled; SoundChannel enum + index→sound###.wav mapping is reusable as data |
GameData.hpp |
369 | Only includes SharpRuntime/SharpRuntimeHelper.hpp |
No engine coupling. Documented flat byte-array layout: 10-byte global header + 3×210-byte gamer records = 640 bytes total. Good direct-reuse candidate for save-format compatibility |
Tables.hpp / .cpp |
1,019 / 2,208 | Header only includes SharpRuntimeHelper.hpp |
No engine coupling. Dozens of flat static const shortcs table_*[N] arrays (Blupi animation frames, per-enemy-type movement/turn tables, explosion frames, decor rotation data). Strong direct-reuse candidate |
Def.hpp + Def/*.hpp + decor/*.hpp |
~215 + several small files | Only SharpRuntimeHelper.hpp |
No engine coupling. Phase, ButtonGlyph, layout constants (LXIMAGE, MAXCELX/MAXCELY, DIMOBJX/Y, etc.), ObjectType (stored as byte, ID layout must not change — matches level file format), SoundChannel (0..92, matches 93 sound*.wav files). Good direct-reuse/reference candidates |
Assets confirmed present:
Content/icons/:blupi.png,blupi1.png,button.png,element.png,explo.png,jauge.png,object-m.png,pad.png,text.png(9 files, ~4.7 MB), plus a parallelContent/icons4x/with the same 9 filenames.Content/backgrounds/:blupiyoupie.png,decor000.png…decor0XX.png.Content/sounds/: 93 files,sound000.wav…sound092.wav.worlds/: 78 files,worldNNN.txt(non-contiguous numbering — some IDs unused/reserved).
Sample confirmed format (world001.txt):
DescFile: posDecor=250;5570 dimDecor=100;100 world=0 music=0 region=0 blupiPos=770;5894 blupiDir=2
Decor:
,,,,,,,...,10,10,10,10,...
This is identical in shape to galaxy-eggbert's own worlds/world001.txt.
Galaxy Eggbert (new CNA/Easy3D source tree)
-> CNA directly (Microsoft::Xna::Framework::*, GraphicsDevice, Game loop)
-> Easy3D beside CNA (Camera3D/OrbitCamera/FollowCamera, TextureAtlas,
BillboardBatch/CubeBatch/DebugDraw item queues)
-> mobile-eggbert used read-only for:
- assets (icons, sounds, worlds, backgrounds)
- header/table knowledge (Tables, Def, ObjectType, SoundChannel, GameData layout)
- behavioral reference (Decor.cpp as the canonical simulation to port logic *from*,
not to link *to*, at least in the first phase)
Easy3D does not sit between Galaxy Eggbert and CNA. Galaxy Eggbert code is free to call CNA APIs
directly (GraphicsDevice, SpriteBatch or a custom draw path, Texture2D, input, audio) and
call into Easy3D only where a helper genuinely saves repetition (camera math, atlas UV lookup,
batching queues). This mirrors the conceptual example given in the task brief:
Microsoft::Xna::Framework::GraphicsDevice* graphics = ...; // CNA, direct
Easy3D::Camera3D camera; // Easy3D helper
Easy3D::BillboardBatch billboards; // Easy3D helperExplicitly out of scope for this migration (both for this analysis task and, per the brief, for the first playable milestone):
- No giant Entity/Component framework in Easy3D or Galaxy Eggbert.
- No new full game engine, no Urho3D-style scene graph, no Nova3D abstraction.
- No resource cache, editor, physics engine, networking, or navigation in Easy3D.
- No MeshCraft or Mesh World integration.
- No Lua in the first phase (undecided; may be discussed later as an optional separate module).
- No model importer or PBR renderer in the first phase.
- No 3D Blupi model requirement — Blupi may ship as a 2D billboard using Mobile Eggbert sprite frames for the entire first playable version.
- No deletion of
src/GalaxyEggbertSimple3D/— it remains as historical reference until the CNA/Easy3D path reaches parity or the user decides otherwise. - No modification of
mobile-eggbert,../cna,../easy-3d(beyond what the user explicitly approves after reading this document),../simple-3d,../nova-3d,../mesh-craft, or../mesh-world. - No CMake migration implemented yet in this task, beyond documenting target names as a plan.
Mobile Eggbert is read-only for this migration. If a Mobile Eggbert change would help, Claude Code
must stop and ask the user. The default migration approach is to adapt Galaxy Eggbert around
Mobile Eggbert, not to reshape Mobile Eggbert for Galaxy Eggbert. This applies even to changes
that look small or "obviously good" (e.g., adding an add_library() target) — they still require
explicit user approval before being implemented, in mobile-eggbert, by a separate task.
None are available today, because mobile-eggbert exposes no CMake library target. If the user approves adding one to mobile-eggbert (a mobile-eggbert-side change, out of scope here), the next-best direct-link candidates, ranked by how self-contained they are, would be:
| Candidate | Self-contained? | Notes |
|---|---|---|
Tables |
Yes | Pure static data, zero engine coupling in the header |
Def + Def/* + decor/* enums |
Yes | Pure enums/constants |
GameData |
Yes | Only depends on SharpRuntimeHelper.hpp |
Decor |
No | Requires concrete IPixmap/ISound implementations to instantiate; also depends on Tables, GameData, System::Random, Worlds.hpp |
Pixmap/Sound |
No | Directly coupled to CNA SpriteBatch/SoundEffect — a 3D remake would not want these anyway |
All confirmed present in ../mobile-eggbert/Content/ and ../mobile-eggbert/worlds/:
| Mobile Eggbert thing | Direct reuse? | Why / why not | Proposed Galaxy strategy |
|---|---|---|---|
Content/icons/blupi.png, blupi1.png |
Yes | Plain asset file | Use directly for Blupi billboard frames |
Content/icons/element.png |
Yes | Plain asset file | Use directly for pickups/enemies/mobile objects as billboards |
Content/icons/object-m.png |
Yes | Plain asset file | Use directly for terrain tile textures |
Content/icons/pad.png, jauge.png, button.png, text.png |
Yes | Plain asset files | Use directly for HUD/menu once that phase is reached |
Content/icons4x/* |
Yes (optional) | Higher-res variant set | Consider for higher-DPI displays later; not required for first playable |
Content/backgrounds/*.png |
Yes | Plain asset files | Use for level-specific backgrounds/skybox-equivalent |
Content/sounds/sound000.wav…sound092.wav (93 files) |
Yes | Plain WAV files, index matches SoundChannel enum |
Load by same index, same filenames |
worlds/worldNNN.txt (78 files) |
Yes | Identical text format to galaxy-eggbert's own world files | Load with the existing engine-agnostic Worlds parser |
| Mobile Eggbert thing | Direct reuse? | Why / why not | Proposed Galaxy strategy |
|---|---|---|---|
Tables::table_blupi[2911] |
Maybe | Pure static data, no engine coupling — but reuse requires either linking mobile-eggbert (not possible today) or copying the array | Prefer direct link if the user later approves adding a library target to mobile-eggbert; otherwise this is a "copy/adapt after user approval" item, not something to do in this task |
Tables::table_mirror, table_vitesse_*, table_decor_quart, per-enemy movement/turn tables, table_explo1..6 |
Maybe | Same reasoning as above | Same — direct link preferred, copy requires approval |
Def::Phase, ButtonGlyph, layout constants (MAXCELX, DIMOBJX/Y, etc.) |
Maybe | Tiny, stable, no engine coupling | Low-risk copy/adapt candidate, but still requires explicit user approval per the task rules before any code is copied |
ObjectType enum |
Maybe | No engine coupling, but IDs are load-bearing (stored in level files) and must match exactly | If copied, must be copied verbatim, byte-for-byte identical to preserve level-file compatibility — flag as approval-required |
SoundChannel enum |
Maybe | No engine coupling, IDs match WAV filenames | Same as above |
| Mobile Eggbert thing | Direct reuse? | Why / why not | Proposed Galaxy strategy |
|---|---|---|---|
sound*.wav files |
Yes | Plain assets | Load directly by path/index |
SoundChannel enum / index mapping |
Maybe | Pure data, but see §5.4 | Copy/adapt after approval, or re-derive independently since galaxy-eggbert already has its own include/GalaxyEggbert/Def/SoundChannel.hpp (needs cross-check for exact parity — see open questions) |
Sound/ISound classes |
Probably no | Confirmed CNA-SoundEffect-coupled and 2D-panning-coupled (TinyPoint pos) |
Not reusable as-is; Galaxy Eggbert needs its own thin CNA audio wrapper informed by, not copied from, this code |
| Mobile Eggbert thing | Direct reuse? | Why / why not | Proposed Galaxy strategy |
|---|---|---|---|
worlds/worldNNN.txt |
Yes | Format already confirmed identical to galaxy-eggbert's own world files | Load directly with the existing GalaxyEggbert::Worlds parser |
GameData byte layout (640-byte flat array, 10-byte header + 3×210-byte gamer records) |
Maybe | No engine coupling, but reuse means either linking the class (not possible today) or reimplementing the same byte layout | If save-file compatibility with mobile-eggbert is desired, document the layout and reimplement it in galaxy-eggbert; treat as a "copy/adapt after approval" item since it involves transcribing byte offsets from mobile-eggbert source |
- Any
Tables.cpparray contents (large, load-bearing, easy to introduce subtle transcription bugs). ObjectTypeandSoundChannelenum values (must stay byte-identical to level/asset data; a transcription mistake would silently corrupt level parsing).GameDatabyte-offset layout (same risk).- Any
Decor.cppmethod bodies, even partial (huge, subtly coupled toIPixmap/ISoundside-effects — see §5.2/§6.4 for why this is reference-only in the first phase).
src/GalaxyEggbertSimple3D/ in its entirety. It documents real, working, faithful gameplay
behavior (per §2.1) and remains the best available reference for "what does correct
galaxy-eggbert behavior look like" even after the engine underneath changes.
Everything in Game/*.cpp except GEBridgeSystem will need a CNA/Easy3D-native rewrite, since
their current implementations call Simple3D APIs (Entity::SetTileTexture, Camera::Shake,
UI::ProgressBar, etc.) that have no CNA/Easy3D equivalent. The behavior they implement (per
§6.1's capability checklist above and NEXT.md) is the porting target; the code is not reusable
verbatim.
None outright — even Simple3D-coupled code remains useful as line-by-line behavioral reference until the CNA/Easy3D path independently reaches the same feature. No deletion is proposed in this task.
GEBridgeSystem— already engine-agnostic; likely portable with zero or near-zero changes.WorldRuntime— the shape of "load aWorld, walk itsChunks, emit renderable tile requests" is a good pattern to replicate against Easy3D'sCubeBatch, even though the concrete Simple3D calls must be replaced.BlupiController,GEDecorSystem,GEExploSystem— their state-machine structure (matching mobile-eggbert'sBlupiAction/ObjectTypebehavior) is worth mirroring; their rendering calls are not.Hud,Sound,GECameraRig— smallest/most isolated pieces; useful as a checklist of what needs a CNA/Easy3D equivalent (input-bound camera, 93-channel audio, HUD text/gauges), not as code to port.
Per Easy3D's own CLAUDE.md/ARCHITECTURE.md (confirmed, not just assumed) and consistent with
this task's brief:
- Cameras (
Camera3D,OrbitCamera,FollowCamera) — already present. TextureAtlas— already present, already CNA-free and mature.- CPU-side batch queues (
BillboardBatch,CubeBatch,DebugDraw) — already present. - CPU-side vertex builders that turn queued items into vertex/index arrays — missing, needed.
- CNA renderer adapters (turning vertex arrays into actual
GraphicsDevicedraw calls) — missing, needed, and per Easy3D's own roadmap this requires a "CNA draw-path decision" that has not yet been made.
Per the task brief and confirmed by Easy3D's own non-goals list in docs/ARCHITECTURE.md: ECS,
full game engine, Urho3D-style scene graph, Nova3D-style abstraction, resource cache, editor,
physics, networking, navigation, MeshCraft import, Mesh World integration, Lua (first phase),
model importer (first phase), PBR renderer (first phase).
Confirmed missing today, all required before Galaxy Eggbert can render anything through Easy3D:
- CPU-side vertex builders for billboard quads (turn
BillboardBatch::Items()into vertex data). - CPU-side vertex builders for cube/tile terrain (turn
CubeBatch::Items()into vertex data). - CPU-side debug line/box geometry generation (turn
DebugDrawqueues into line-list vertex data). - A CNA renderer adapter for billboard batches (issue actual
GraphicsDevicedraw calls). - A CNA renderer adapter for cube batches.
- A CNA renderer adapter for debug draw.
- A texture loading/ownership strategy — likely CNA-side (
Texture2D), not Easy3D-side, since Easy3D'sTextureAtlasonly stores UV rectangles by name, not actual texture data.
These gaps can be filled either inside Easy3D itself (if the user wants Easy3D to grow a minimal renderer) or as a thin adapter layer living in Galaxy Eggbert's own new source tree. This is an open question (see §12) — Easy3D's own roadmap treats it as an open decision too, not something this task should decide unilaterally.
Game/ fixed-timestep loop (mobile-eggbert's ownGame1and itsCNA/Game.cppfixed-timestep accumulator are useful reference for matching gameplay speed across platforms).GraphicsDeviceManager,GraphicsDevice.Texture2Dloading and ownership.- Input (keyboard/gamepad — mirroring mobile-eggbert's
InputPadusage pattern, not its code). - Audio playback primitives (
SoundEffect/SoundEffectInstance), informed by mobile-eggbert'sSound/ISounddesign but not copied from it. Vector2/Vector3/Matrix/Rectanglemath types (already used throughout Easy3D).
Anything that is a direct 1:1 wrapper of a single CNA type or call (texture loading, sound playback, raw input polling) should stay as Galaxy-Eggbert-side CNA usage, not be pulled into Easy3D as a new abstraction — consistent with "Easy3D must not become Simple3D again."
Two naming options were considered, as requested by the task brief:
Option A: src/GalaxyEggbertCNA/, target GalaxyEggbertCNA
Option B: src/GalaxyEggbertEasy3D/, target GalaxyEggbertEasy3D
Recommendation: Option A (GalaxyEggbertCNA).
Reasoning: the target architecture is "CNA directly, with Easy3D as one of several helpers beside
it" (§3) — CNA is the foundational dependency (game loop, graphics device, audio, input); Easy3D
is one helper library among what could later be several. Naming the tree/target after CNA
matches the actual dependency relationship and avoids implying Easy3D is the primary engine layer
(which would risk recreating the "Simple3D" framing the project is explicitly moving away from).
The precedent of GalaxyEggbertSimple3D being named after its primary engine dependency supports
using the same convention: name the target after what it fundamentally runs on (CNA), not after
one of its helper libraries (Easy3D).
This recommendation should be confirmed with the user before implementation (see §12).
Proposed layout, mirroring the existing GalaxyEggbertSimple3D structure:
src/GalaxyEggbertCNA/
GalaxyEggbertCNAGame.hpp / .cpp — top-level CNA Game subclass, owns the loop
Game/
WorldRuntime.hpp / .cpp — loads World via existing engine-agnostic parser
TerrainRenderer.hpp / .cpp — CubeBatch-based terrain, CNA draw adapter
BlupiController.hpp / .cpp — Blupi state machine + billboard rendering
GEDecorSystem.hpp / .cpp — object/pickup/enemy billboards
Hud.hpp / .cpp
Sound.hpp / .cpp — thin CNA audio wrapper
GECameraRig.hpp / .cpp — wraps Easy3D::OrbitCamera/FollowCamera
GEExploSystem.hpp / .cpp
GEBridgeSystem.hpp / .cpp — likely near-verbatim port from Simple3D version
include/GalaxyEggbert/ (Worlds, Def/, BlockTypes, Def, GameConstants) is reused unchanged by
both GalaxyEggbertSimple3D and the new GalaxyEggbertCNA target.
- Confirmed: Easy3D auto-detects an existing
CNACMake target from a parent project, so the intended integration order isadd_subdirectory(../cna)thenadd_subdirectory(../easy-3d)inside galaxy-eggbert's ownCMakeLists.txt, thenadd_executable(GalaxyEggbertCNA ...)linking bothCNAandeasy3d. - Confirmed: mobile-eggbert cannot be added via
add_subdirectoryas a library dependency today (§5, §2.4) — only as an executable, which is not useful for reuse. Non-invasive options for asset reuse specifically (not code reuse):- Read mobile-eggbert assets directly from a sibling path at runtime
(
../mobile-eggbert/Content/...,../mobile-eggbert/worlds/...) — simplest, but couples the galaxy-eggbert runtime to a specific sibling checkout existing on disk. - Copy assets into galaxy-eggbert's own
Content/worldsdirectories at build time via a CMake custom command (file(COPY ...)oradd_custom_command) — more robust for distribution, but duplicates ~5 MB+ of binary assets in the galaxy-eggbert tree/build output. - Symlink assets — avoids duplication but is fragile on Windows and in CI without extra setup.
- This is called out explicitly as an open decision in §12, not decided here.
- Read mobile-eggbert assets directly from a sibling path at runtime
(
GalaxyEggbertSimple3Dtarget and itsGALAXY_EGGBERT_BUILD_SIMPLE3Doption remain untouched and defaultON.
See plan.md, new section "Direct CNA + Easy3D Migration", for the full checkbox task list
with E3D-MIG-* IDs. Summary of phases:
- Documentation and direction lock (this document +
plan.mdupdate — done by this task). - Build integration investigation (CNA/Easy3D/mobile-eggbert CMake requirements — mostly done by this analysis, formalized as tasks).
- New target skeleton (
GalaxyEggbertCNA, empty window, clear color, no gameplay). - Asset path strategy and first asset reuse.
- World loading in the new target.
- Easy3D terrain path (requires filling the vertex-builder/CNA-adapter gap from §7.3).
- Blupi first version (2D billboard, no 3D model).
- Object/decor first version (billboards from
element.png). - Sound.
- HUD.
- Gameplay parity pass.
- Retire Simple3D path (later, not now).
- Optional future work (3D Blupi model, camera switching, Lua discussion, renderer polish).
- Easy3D rendering gap is the critical path. Nothing in the current stack (Easy3D, CNA usage in mobile-eggbert, or galaxy-eggbert) demonstrates cube/billboard rendering today. This is new work, not integration work, and is likely the single largest risk to schedule.
- mobile-eggbert asset/table reuse is blocked on either a mobile-eggbert change (needs
approval) or manual transcription (error-prone, especially for
ObjectType/SoundChannelIDs andTablesarrays, which are load-bearing against level file data). - Decor.cpp is not a reusable component. At 11,720 lines with
IPixmap/ISoundmembers threaded through simulation methods, it can only be used as a behavioral reference to reimplement from, not linked or lifted. Porting gameplay parity (Phase 10) will be a large, incremental effort regardless of which engine is underneath — this was already true for the Simple3D port and will be true again for the CNA/Easy3D port. - Two competing sets of project docs.
README.md(CNA-oriented) vs.CLAUDE.md/NEXT.md/plan.md(Simple3D-oriented) currently disagree about what the current/target build is. Until reconciled, new contributors (human or agent) reading only one of these files will get a wrong picture. - Asset duplication vs. sibling-path coupling (§9) is an unresolved tradeoff with real consequences for distribution and CI; picking wrong now could mean redoing asset pipeline work later.
-
Target/source-tree naming: confirm or override the recommendation in §9 (
GalaxyEggbertCNA/src/GalaxyEggbertCNA/) vs. theEasy3D-named alternative.Resolved (2026-07-01):
GalaxyEggbertCNA/src/GalaxyEggbertCNA/, exactly as recommended — this is what actually got built. -
Mobile Eggbert library target: would you like to separately approve a future mobile-eggbert-side task to add an
add_library()target (e.g. forTables,Def,GameData,ObjectType/SoundChannelenums only — notDecor/Pixmap/Sound) so those pieces can be linked instead of copied? This would need to be its own approved task against../mobile-eggbert, not part of this migration.Still open as of 2026-07-09 (
plan.mdE3D-MIG-015) — mobile-eggbert has noadd_library()target today; nothing has changed here. Not blocking current work, sinceObjectType/SoundChannelturned out to already be numerically identical (see Q4 below) — no reuse-via-linking is actually needed yet. -
Asset strategy: sibling-path read at runtime, build-time copy, or symlink, for reusing
../mobile-eggbert/Content/*and../mobile-eggbert/worlds/*(§9, CMake integration notes)?Resolved (2026-07-01, implemented
E3D-MIG-030): build-time copy, via aPOST_BUILDcopy_directorystep inCMakeLists.txt— exactly the recommended default. Symlinks were rejected as fragile on Windows/CI, matching this document's own §9 leaning. -
Copy-with-approval items: do you want to proceed (in a future task) with copying
ObjectType,SoundChannel,Defconstants, and/orGameData's byte layout intoinclude/GalaxyEggbert/verbatim, given galaxy-eggbert already has its owninclude/GalaxyEggbert/Def/ObjectType.hppandSoundChannel.hpp? These need a parity check against mobile-eggbert's versions — are they already identical, or do they need to be reconciled?ObjectType/SoundChannelresolved (2026-07-01,E3D-MIG-039): already identical — both sides declare the same 204/93 numeric IDs, verified programmatically. No copying needed; nothing was changed in either repository.GameData's byte layout is still open — see Q7 below, unchanged. -
Where should the Easy3D rendering gap (§7.3) be filled — inside
../easy-3ditself (its own roadmap Phase 3/4), or as a thin adapter living only inGalaxyEggbertCNA? This affects whether../easy-3dneeds a follow-up task of its own.Decision (2026-07-02, recorded as
plan.mdE3D-MIG-050): inside../easy-3ditself. Cross-checking easy-3d's owndocs/ROADMAP.md(Phase 3 "CPU-side vertex builders", Phase 4 "CNA renderer adapters") andNEXT.md§8 item 8 showed that repo's own plan already scopes this work as its own, independent of Galaxy Eggbert — it is generic billboard/cube/debug geometry-and-draw-call plumbing with no Eggbert-specific knowledge, matchingdocs/ARCHITECTURE.md's stated helper role. Galaxy Eggbert stays the owner of all Eggbert-specific meaning (tile IDs,ObjectType, animated-tile frames) and only calls the new Easy3D functions. This is a documentation decision only — implementing it still requires separate, explicit user approval to modify../easy-3d(a sibling repo). -
Documentation reconciliation: should
README.md's aspirational CNA build instructions be rolled back to match current Simple3D reality until the new target exists, or shouldCLAUDE.md/NEXT.md/plan.mdbe updated now to describe the CNA/Easy3D target as the near-term direction (while noting it isn't buildable yet)? This task updatesplan.mdper its instructions but leavesREADME.md/CLAUDE.md/NEXT.mduntouched pending your decision.Resolved, long since overtaken by events: the second option, and then some —
CLAUDE.md/NEXT.md/plan.md/README.mdall now consistently describeGalaxyEggbertCNAas the actively developed target (not just "near-term direction") andGalaxyEggbertSimple3Das historical reference only (locked 2026-07-05, Simple3D frozen 2026-07-08) — a full documentation pass across all of these plusANDROID.md/WINDOWS.mdconfirmed this consistency 2026-07-09. -
Save-data compatibility: is byte-level save compatibility with mobile-eggbert's
GameDataformat (640-byte layout) actually a goal, or is a fresh save format acceptable for galaxy-eggbert? This affects whether §5.6's reuse strategy is worth pursuing at all.Still open as of 2026-07-09 — no save system exists yet in
GalaxyEggbertCNAat all (Phase 9/10 inplan.md, not started), so this hasn't needed answering yet. -
Lua: confirmed out of scope for the first migration per the task brief — no action needed now, but flagging that
docs/QUESTIONS.mdin../easy-3dtreats it as open too, so the two repos' timelines should probably be discussed together later.