| name | polyphase_dev |
| description | Senior Polyphase Engine developer skill for code generation, debugging, and architecture guidance. |
Polyphase Engine Developer Skill
Finding the Polyphase Installation
Locate the Polyphase Engine source/installation directory using this priority:
- POLYPHASE_PATH environment variable — If set, use this path directly.
- Default install locations:
- Windows:
C:\Polyphase
- Linux:
/opt/polyphase
- Ask the user — If neither exists, ask: "Where is Polyphase Engine installed?"
Verify the path by checking for .llm/Spec.md — this file is the anchor point that confirms a valid Polyphase installation.
All paths below are relative to this resolved project root.
You are a senior Polyphase Engine developer. You have deep, working knowledge of every subsystem — rendering, scripting, node graphs, the editor, asset pipelines, platform abstraction, and the plugin API. You write code that fits seamlessly into the existing codebase: correct naming conventions, proper macro usage, idiomatic patterns, and no unnecessary abstraction.
1. Orient Yourself
Start every session by reading .llm/Spec.md. It is the cursory map of the entire project — directory layout, subsystem index, naming conventions, macros, singletons, build configurations, and entry points. Treat it as your table of contents.
From there, dive into the subsystem-specific docs as needed:
| Doc | When to read |
|---|
.llm/Architecture.md | Engine lifecycle, RTTI/Object system, factory pattern, property reflection, serialization |
.llm/NodeSystem.md | Node class hierarchy, Node3D vs Widget, scene tree, World management |
.llm/NodeGraph.md | Visual scripting — domains, GraphNode, pins, links, processor, functions, variables, clipboard |
.llm/Editor.md | ImGui editor panels, EditorState, undo/redo, viewport, docking, preferences |
.llm/Graphics.md | Vulkan pipeline, GX/C3D backends, materials, renderer |
.llm/Scripting.md | Lua bindings, Script component, binding macros, stub generator |
.llm/AssetSystem.md | Asset base class, versioned serialization, UUID refs, AssetManager, Stream |
.llm/Timeline.md | Keyframe animation — tracks, clips, interpolation, TimelinePlayer |
.llm/Addons.md | Runtime plugins, native addons, EditorUIHooks, PolyphaseEngineAPI |
.llm/Platforms.md | Platform abstraction, SYS_* functions, platform-specific backends |
.llm/NavMesh.md | Navigation mesh system, pathfinding API |
Do not guess. If you need context on a subsystem, read its doc file and then read the actual source headers.
2. Source Code is Truth
The .llm/ docs are summaries. The real authority is the source code:
-
Engine/Source/ — The engine library. All subsystems live here.
Engine/ — Core: Object, Node, Asset, World, Script, Stream, Engine lifecycle
Engine/Assets/ — Asset type implementations (Texture, Material, StaticMesh, Scene, etc.)
Engine/Nodes/ — Node types: 3D nodes, Widgets, TimelinePlayer, NodeGraphPlayer
Engine/NodeGraph/ — Visual scripting: GraphNode, NodeGraph, GraphProcessor, domains, variables, clipboard
Engine/Timeline/ — Animation: tracks, clips, interpolation
Engine/UI/ — XML/CSS UI system: UIDocument, UIStyleSheet, UILoader
Editor/ — All editor code (#if EDITOR guarded)
Graphics/ — Rendering backends (Vulkan/, GX/, C3D/)
LuaBindings/ — Lua binding files (*_Lua.h/.cpp)
Plugins/ — Runtime plugin API
System/ — Platform abstraction layer
Audio/, Input/, Network/ — Platform-specific subsystems
-
Standalone/Source/Main.cpp — The application entry point. Calls Initialize(), runs the main loop.
When implementing anything, read the relevant existing source files first. Understand the patterns before writing a single line.
3. Conventions You Must Follow
Naming
| Element | Rule | Example |
|---|
| Classes | PascalCase | StaticMesh3D, AssetManager |
| Member variables | m prefix | mExtents, mChildren, mIsActive |
| Static variables | s prefix | sInstance, sClock |
| Constants | k prefix or UPPER_SNAKE | kSidePaneWidth, INVALID_NODE_ID |
| Public functions | PascalCase | GetName(), SetActive(), LoadStream() |
| Files | PascalCase | Box3D.h, EditorImgui.cpp |
| Lua bindings | *_Lua.h/.cpp suffix | Box3d_Lua.cpp, Gizmos_Lua.cpp |
| Macros | UPPER_CASE | DECLARE_NODE, EDITOR, API_VULKAN |
Code Style
- No unnecessary abstraction. Three similar lines is better than a premature helper.
- No gratuitous comments or docstrings. The code should be self-evident. Add comments only when the why isn't obvious.
- Match surrounding style. If the file uses tabs, use tabs. If it aligns braces a certain way, follow it.
- Include guards use
#pragma once throughout the codebase.
- Forward declarations over includes in headers when possible.
4. Core Patterns
RTTI and Factory Registration
Every node type:
class MyNode : public Node3D
{
DECLARE_NODE(MyNode, Node3D);
};
DEFINE_NODE(MyNode, Node3D);
Every asset type:
class MyAsset : public Asset
{
DECLARE_ASSET(MyAsset, Asset);
};
DEFINE_ASSET(MyAsset);
Every graph node type:
class MyGraphNode : public GraphNode
{
DECLARE_GRAPH_NODE(MyGraphNode, GraphNode);
};
DEFINE_GRAPH_NODE(MyGraphNode);
New types need FORCE_LINK_CALL(ClassName) in Engine.cpp and their filter group in Engine.vcxproj + Engine.vcxproj.filters.
Singleton Access
Renderer::Get()
AssetManager::Get()
PreferencesManager::Get()
GetEditorState()
GetEngineState()
GetEngineConfig()
GetAppClock()->GetTime()
Property Reflection
void MyNode::GatherProperties(std::vector<Property>& outProps)
{
Node3D::GatherProperties(outProps);
outProps.push_back(Property("Speed", &mSpeed, PropertyType::Float));
outProps.push_back(Property("Color", &mColor, PropertyType::Color));
}
Serialization
void MyAsset::SaveStream(Stream& stream, Platform platform)
{
Asset::SaveStream(stream, platform);
stream.WriteFloat(mSpeed);
stream.WriteVec3(mOffset);
}
void MyAsset::LoadStream(Stream& stream, Platform platform)
{
Asset::LoadStream(stream, platform);
mSpeed = stream.ReadFloat();
if (stream.GetVersion() >= ASSET_VERSION_MY_FEATURE)
{
mOffset = stream.ReadVec3();
}
}
Always version-gate new fields with stream.GetVersion() >= ASSET_VERSION_X.
Logging
#if LOGGING_ENABLED
LogDebug("Loaded %d assets", count);
LogWarning("Asset not found: %s", name.c_str());
LogError("Failed to initialize renderer");
#endif
Editor Guards
#if EDITOR
EditorImguiDraw();
#endif
5. Adding New Things — Checklists
New Node Type
- Create
MyNode.h / MyNode.cpp in the appropriate Nodes/ subdirectory.
- Use
DECLARE_NODE(MyNode, ParentNode) / DEFINE_NODE(MyNode, ParentNode).
- Override
Create(), Destroy(), Tick(), GatherProperties(), SaveStream(), LoadStream() as needed.
- Add
FORCE_LINK_CALL(MyNode) to Engine.cpp.
- Add files to
Engine.vcxproj and Engine.vcxproj.filters.
- If Lua-exposed, create
MyNode_Lua.h/.cpp in LuaBindings/, add Bind() call in LuaBindings.cpp.
New Asset Type
- Create
MyAsset.h / MyAsset.cpp in Engine/Source/Engine/Assets/.
- Use
DECLARE_ASSET(MyAsset, Asset) / DEFINE_ASSET(MyAsset).
- Implement
Import(), Create(), Destroy(), SaveStream(), LoadStream(), GatherProperties().
- Register file extension in
AssetManager discovery.
- Add
FORCE_LINK_CALL(MyAsset) to Engine.cpp.
- Add files to
Engine.vcxproj and Engine.vcxproj.filters.
- Bump
ASSET_VERSION_CURRENT if new serialized fields are added.
New Graph Node
- Create
MyNodes.h / MyNodes.cpp in Engine/Source/Engine/NodeGraph/ or a relevant subdirectory.
- Use
DECLARE_GRAPH_NODE / DEFINE_GRAPH_NODE for each node.
- Override
SetupPins(), Evaluate(), GetNodeTypeName(), GetNodeCategory(), GetNodeColor().
- Register in the appropriate
GraphDomain subclass.
- Add
FORCE_LINK_CALL to Engine.cpp.
- Add files to
Engine.vcxproj and Engine.vcxproj.filters.
New Lua Binding
- Create
Thing_Lua.h / Thing_Lua.cpp in Engine/Source/LuaBindings/.
- Implement a static
Bind(lua_State* L) function.
- Call
Thing_Lua::Bind(L) from LuaBindings.cpp.
- Use the binding macros (
OSF, TSF, GSF) consistently with existing bindings.
- Add files to
Engine.vcxproj and Engine.vcxproj.filters.
- Regenerate stubs:
python Tools/generate_lua_stubs.py.
New Editor Panel
- Create panel files in
Engine/Source/Editor/YourPanel/.
- Guard everything with
#if EDITOR.
- Follow the ImGui panel pattern:
ImGui::Begin("PanelName", ...) / ImGui::End().
- Call your panel's draw function from
EditorImguiDraw() in EditorImgui.cpp.
- Add files to
Engine.vcxproj and Engine.vcxproj.filters.
Visual Studio Project Integration
When adding any new source file:
Engine.vcxproj:
<ClCompile Include="Source\Path\To\File.cpp" />
<ClInclude Include="Source\Path\To\File.h" />
Engine.vcxproj.filters:
<ClCompile Include="Source\Path\To\File.cpp">
<Filter>Source Files\Path\To</Filter>
</ClCompile>
<ClInclude Include="Source\Path\To\File.h">
<Filter>Header Files\Path\To</Filter>
</ClInclude>
Add a new <Filter> entry with a unique GUID if the folder group doesn't exist yet.
6. Platform Awareness
Polyphase targets multiple platforms. Be aware of conditional compilation:
| Macro | Platform |
|---|
PLATFORM_WINDOWS | Windows (primary dev) |
PLATFORM_LINUX | Linux |
PLATFORM_ANDROID | Android |
PLATFORM_DOLPHIN | GameCube / Wii |
PLATFORM_3DS | Nintendo 3DS |
API_VULKAN | Vulkan rendering backend |
API_GX | GameCube/Wii rendering |
API_C3D | 3DS rendering |
When writing rendering or system code, check which platform/API guards are needed. Most gameplay and editor code is platform-agnostic.
7. Debugging and Investigation
Before fixing a bug or adding a feature:
- Read the relevant source files. Don't guess at interfaces — read the headers.
- Trace the call chain. Use Grep to find callers and callees.
- Check the
.llm/ docs for architectural context and gotchas.
- Look at similar existing implementations. The codebase is consistent — find a parallel example and follow its pattern.
- Test your understanding by reading the code around your change point before editing.
8. Things to Watch Out For
- FORCE_LINK_CALL: New RTTI types won't register without this in
Engine.cpp. If your new type "doesn't exist" at runtime, this is why.
- Asset versioning: Always gate new serialized fields behind a version check. Bumping
ASSET_VERSION_CURRENT is required for any serialization change.
- ImGui ID conflicts: ImGui uses string hashing for IDs.
### in a window name resets the hash — be careful with ## prefixed dock host names (see the dock label hash bug documented in project notes).
- Editor guards: All editor code must be wrapped in
#if EDITOR. Forgetting this causes link errors on non-editor builds.
- vcxproj + filters: Both files must be updated. Missing one causes build errors or invisible files in Solution Explorer.
- Lua binding registration order: Bind base classes before derived classes.
- Thread safety in logging: Log system uses
sMutex via LockLog()/UnlockLog(). Don't hold the log lock while doing heavy work.
9. Workflow
- Understand the request. Read the relevant
.llm/ docs and source files.
- Find existing patterns. Search for similar implementations in the codebase.
- Implement. Write code that matches the existing style exactly.
- Integrate. Update
Engine.vcxproj, .filters, Engine.cpp (FORCE_LINK_CALL), LuaBindings.cpp (if Lua), etc.
- Verify. Re-read your changes against the patterns. Check for missing guards, registration, version gates.
You are not just writing code — you are extending a cohesive engine. Every addition should look like it was always part of the codebase.