| Header | Link |
|---|---|
| Purpose | Purpose |
| Use Cases | Use Cases |
| Status Keys | Status Keys |
| Core Runtime | Core Runtime |
| 2D | 2D |
| 3D | 3D |
| UI | UI |
| Tooling And Demos | Tooling And Demos |
| Planned Work Packets | Planned Work Packets |
This page is the single source of truth for what Perro can actually do today, so you can tell before you start whether a system your game needs is shippable, half-built, or not written yet. Each row pairs an engine capability with a status and concrete notes, grouped into Core Runtime, 2D, 3D, UI, and Tooling. Most rows link to the deep-dive doc for that capability. Use it to scope a game, judge whether a feature is production-ready, and track what is coming next.
- Scope a new game before building. Scan the status column to confirm the systems you need are
done, notpartialorplanned. - Judge whether a feature is production-ready. A
donerow is usable and documented;in devandpartialrows spell out the missing pieces in the Notes column. - Jump to the reference doc for a capability. Rows link out to module docs such as Physics Module, Materials Guide, and Water Bodies.
- Check platform and target limits. For example, Steamworks is native-only, and web export status sits under Tooling And Demos.
- Track the roadmap. Planned Work Packets lists the next features in progress.
Last audited: 2026-07-08 from workspace code, docs, demos, and node registry.
Status keys:
done: implemented and documented enough to use.in dev: implementation path chosen, but feature still has known issues.partial: implemented core path, but important game-making pieces are missing.planned: not a current engine feature.research: design needed before implementation.
| Area | Status | Notes |
|---|---|---|
Scene tree + NodeID access |
done | Parent/child scene model with typed node access. |
| Rust behavior scripts | done | Lifecycle, methods, state, and generated script registry. |
| Query layer | done | Query by type, base type, tag, name, and subtree. |
BitMask layer masks |
done | Shared 32-bit mask type for camera render masks, renderable layers, physics layers/query filters, and spatial audio occlusion masks. layers fields default to BitMask::ALL; mask fields are ignore/exclude masks and default to BitMask::NONE. Rust code can use BitMask::with([1, 2]), BitMask::without(1), bitmask!([1, 2]), slice/vector helpers, and raw from_bits; scene files use layer arrays plus only(...) / without(...) for render_mask, render_layers, collision_layers, and collision_mask. See BitMask. |
| Scene preload | done | scene_preload! parses and stores a scene as PreloadedSceneID; loading copies nodes from the cached scene instead of reparsing. |
| Resource load IDs | done | Texture, mesh, material, animation, audio, and soundfont load calls return IDs immediately where applicable and queue backend work. A node can hold the ID before the backend resource is ready. *_is_loaded! checks expose readiness for load screens, spawn gates, and cutscene/audio timing. |
| Performance + flexibility philosophy | done | Dev uses plain dynamic files with no reimport database burden. Static export bakes supported assets into generated lookup data for release runtime loading, and assets.perro is a binary pack for generic files that do not have static bake support. See Performance + Flexibility Philosophy. |
| MIDI and soundfonts | done | ctx.res.Audio().midi() supports live one-shot notes, held notes with MidiNoteHandle, .mid/.midi file playback, built-in procedural GM-style programs, .sf2 soundfonts through MidiSound::SoundFont, buses, point 2D/3D propagation, and node-attached playback through ctx.run.Audio().midi(). Static builds embed audio, MIDI, and soundfont assets under embedded/audios/. See Audio. |
| Spatial audio propagation | done | Point Audio2D/Audio3D playback enters the propagation solver through ctx.res.Audio() using SpatialAudioOptions. Attached node audio is exposed through ctx.run.Audio(). Solver handles direct occlusion, material transmission/thickness, low-pass muffling, reflection energy loss, corner shift, 2D/3D audio masks, ordered audio effect zones, one-way linked 2D/3D portals, debug ray drawing, omni/directional/inverse/bidirectional audio direction modes, and perro_pawdio DSP for low-pass, EQ, compression, echo, reverb send, reflection, and occlusion. Portal rays hit collision-shape children, transform hit point and ray direction through target portal global transforms, then keep tracing through portals/physics bounces up to the cycle guard. A ray cannot immediately re-enter the portal it just exited; another portal hit or physics bounce clears that block. |
| Save data helpers | done | perro_modules::file can read assets and write to user:// or absolute paths. |
| CSV resource tables | done | csv_load! loads res:// CSV files as &'static Csv; dev parses and caches once, static export bakes CSV tables into generated lookup data. CSVQuery supports filter, OR, contains, starts_with, in, projection, sort, numeric sort, and limit. |
| Perro networking | done | perro_api::networking re-exports the perro_networking crate with HTTP client helpers, non-blocking TCP hosts/connections, UDP endpoints, WebSocket hosts/connections, frame/handshake/heartbeat helpers, and NetEvent/NetworkEvent signal bridge support. Networking is script-owned state, not a node API: games create sockets or peers in script/game state, poll them during update, then emit signals with emit_net_event! or emit_http_event! when useful. See Networking, HTTP, TCP, UDP, and WebSocket. |
| Runtime window config API | done | RuntimeWindow::Window() queues runtime changes to window mode/title/size. |
| Post-processing | done | Camera and global chains include scene-referred bloom, final ACES tonemapping, manual/auto exposure, screen effects, custom WGSL, manual color_grade, and static texture-backed lut2d/lut3d. See Post Processing. |
| Steamworks integration | done | Native project [steam] config, runtime init/callback pump, achievements, stats, leaderboards, apps/DLC entitlement, friends, rich presence, overlay/invites, lobbies, P2P/networking, server browser helpers, cloud saves, workshop/UGC, input, remote play, screenshots, timeline, utils, and event polling exist through perro_api::prelude::*. Feature-off/no-Steam paths return typed disabled errors. Web target does not support Steamworks. See Steamworks. |
| Area | Status | Notes |
|---|---|---|
Node2D transform |
done | Position, rotation, scale, z index, visibility. |
Sprite2D |
done | Textured quad with optional pixel texture region for atlas frames. |
Label2D |
done | World-space text label that uses Node2D transform, render layers, modulation, UiLabel alignment fields, and the same locale text binding path as UiLabel. |
Camera2D |
done | Active camera with zoom, camera post-processing, listener audio options, and render_mask hidden-layer filtering against node render_layers through BitMask. |
CameraStream2D |
done | Renders a source Camera2D into a world-space 2D quad using stream resolution, aspect mode, tint, and post-processing. Runtime exposes the stream texture through Textures().camera_stream(...). |
SubView2D |
done | Renders an isolated mixed Node2D/Node3D child scope through implicit local views or active descendant cameras, then composites its transparent HDR texture onto a 2D world quad. |
| 2D physics bodies | done | Static, rigid, character, area, collision shapes, force emitters, layers/masks, joints, raycast, shape cast, query filters, contact data, and area/body signals exist. See Physics Module. |
| Draw2D transient shapes | done | Circle/ring/rect, lines, polylines, polygon outlines, paths, and transient sprites exist. |
AnimatedSprite2D |
done | Sprite-sheet playback from normal texture paths plus named strip/grid animation definitions. |
| 2D button nodes | done | Button2D and ImageButton2D use Node2D transform/visibility/layers, render in world space, hit test through the active 2D camera, emit default <node_name>_<event> button signals, and treat *_signals fields as extra signals. |
NineSlice2D |
done | World-space nine-slice texture panel with fixed corners, stretched edges/center, texture regions, margins, tint, and Node2D placement. |
| Tile maps | done | TileMap2D plus .ptileset runtime/static path exists: one texture atlas, tile ids, empty tile -1, draw extraction, merged runtime 2D collision bake for collision = true auto tiles, and explicit rect/circle/triangle/polygon collision shapes. Static builds pack .ptileset into binary PTSET bytes and expose lookup_tileset(hash) -> &'static [u8]; runtime static mode decodes those bytes instead of parsing text. See TileMap2D and .ptileset. |
WaterBody2D |
done | Shaped 2D water surface node with quad/circle bounds, GPU height/foam sim, idle modes, flow/wind, render-layer filtering, max-rate GPU sample readback, analytic fallback, camera-distance sim LOD, and fixed-step buoyancy/drag LOD for RigidBody2D. Water is not a solid collider; add physics bodies/areas separately for banks, floors, triggers, or raycast targets. See Water Bodies. |
| 2D skeleton nodes | done | Skeleton2D owns Vec<Bone2D> data loaded from .pskel2d; attachment, IK target, physics chain, and bone collider nodes mirror the 3D rig workflow. |
| 2D particles | done | ParticleEmitter2D uses .ppart profiles; z fields are ignored. |
| 2D lights | partial | AmbientLight2D, RayLight2D, PointLight2D, and SpotLight2D render additive 2D lights. Shadow lights support compatible hard shadows plus sampled soft penumbra through shadow_softness/shadow_samples. Visible CollisionShape2D and enabled tilemap collision shapes cast. Sprite-alpha silhouettes and camera-stream caster capture remain future work. See 2D Shadows. |
| Area | Status | Notes |
|---|---|---|
| Mesh rendering | done | Mesh instances, surfaces, material bindings, and meshlet path exist. |
| Mesh blending | done | Screen-space seam pass covers MeshInstance3D and MultiMeshInstance3D through blend_enabled, blend_layers, blend_mask, and blend distance/noise controls. MSAA resolves through the single-sample scene target before the seam pass. Legacy in-material depth fade remains as the compatibility fallback when the screen seam path is disabled. See the Demo3D mesh blending docs. |
Sprite3D |
done | Floating 3D sprite projected from Node3D transform and world-space size, with texture, atlas region, flips, tint, render layers, and modulation. |
Label3D |
done | Floating 3D text label projected from Node3D transform and world-space size, with per-pixel scene-depth testing by default, optional visible_through_objects, UiLabel alignment fields, and the same locale text binding path as UiLabel. |
| 3D materials | done | .pmat, glTF :mat[index] refs, inline scene materials, runtime load/reserve/create/write APIs, per-surface material bindings, and custom WGSL materials exist. See Materials Guide. |
| Multi-mesh rendering | done | Repeated static mesh instances. |
| 3D cameras | done | Perspective, orthographic, frustum settings, listener audio options, camera post-processing, and render_mask hidden-layer filtering against node render_layers through BitMask. |
CameraStream3D |
done | Renders a source Camera3D into a 3D world quad with stream resolution/aspect/tint/post-processing. UI camera streams can also display 2D or 3D camera output. |
SubView3D |
done | Renders an isolated mixed Node2D/Node3D child scope through implicit local views or active descendant cameras, then composites its transparent HDR texture onto a 3D world quad. |
| 3D lights | done | Ambient, sky, ray, point, and spot lights. |
| 3D shadows | done | Ray, spot, and point shadow paths exist for 3D lights/casters with cast_shadows and mesh receive_shadows/cast_shadows flags. Cascades, point/spot slots, shadow culling, and multimesh shadow casters are implemented. RayLight3D, PointLight3D, and SpotLight3D expose shadow_strength, shadow_depth_bias, shadow_normal_bias, and nested shadow = { ... } tuning. See 3D Shadows. |
| 3D particles | done | ParticleEmitter3D driven by .ppart profiles. |
| 3D physics | done | Static, rigid, character, area, primitive/trimesh collision shapes, force emitters, raycast, primitive shape cast, query filters, contacts, area overlap signals, layers/masks, and core joint nodes exist. Trimesh as cast shape is not a 1.0 target. See Physics Module. |
WaterBody3D |
done | Shaped 3D water surface node on the X/Z plane with box/cylinder bounds, GPU height/foam sim, idle modes, flow/wind, render-layer filtering, max-rate GPU sample readback, analytic fallback, camera-distance sim LOD, and fixed-step buoyancy/drag LOD for RigidBody3D. Water is not a solid collider; add physics bodies/areas separately for lake beds, shores, triggers, or raycast targets. See Water Bodies. |
| Skeleton skinning | done | A MeshInstance3D can bind to a Skeleton3D and use mesh weights. |
| Shared-skeleton mesh reuse | done | Works when the mesh uses the same rig contract: matching joint order/indices and compatible weights. |
| Blend shapes | done | glTF morph targets import as blend shapes. MeshInstance3D and MultiMeshInstance3D expose blend_shape_weights, including per-instance overrides for multimesh. |
| Automatic retargeting | done | .pretarget maps support exact names, aliases, local rest-pose alignment, and all/root_only/none translation policy. perro_cli import_anim --retarget-map <map> --target-rig <rig.glb> reads source/target glTF rest poses. Static builds bake sibling .panim + .pretarget files. |
| LOD | done | Automatic mesh LOD works for dynamic/dev loads and static .pmesh v2 builds. Mesh nodes can clamp automatic LOD quality with min_lod/max_lod (0 least detail, 5 most detail). |
| Decals | done | Decal3D projects albedo/normal/emission onto lit geometry before lighting. Standard, toon, and multimesh surfaces receive decals; unlit materials ignore them. Demo3D includes decal docs, textures, and a working scene. |
| Navmesh | partial | NavMeshID, .pnav text assets, static embedding, resource APIs, and runtime path queries exist for static 3D triangle navmeshes. Runtime supports snap-to-mesh, layer masks, shared-edge A*, funnel/string-pull smoothing, area costs, authored one-way/two-way off-mesh links, and conservative per-query circle/AABB obstacles. Mesh/scene auto-bake, binary .pnav, NavMesh3D scene node, and Demo3D lane remain planned. |
| Area | Status | Notes |
|---|---|---|
| Panels/buttons/labels | done | UiPanel, UiButton, and UiLabel data nodes plus retained UI render path. |
| Text input | done | UiTextBox and UiTextBlock support one-line and multi-line edit flows. |
| Layout nodes | done | H/V/grid/tree list layout nodes exist with retained invalidation. |
| Scroll containers | done | UiScrollContainer offsets child content and clips to its rect. |
| Focus navigation | done | Text focus plus Tab, Shift+Tab, gamepad D-pad/left stick, Joy-Con stick, focused button activation, and player/device input masks exist. |
| Selector/input widgets | done | UiDropdown, UiCheckbox, and UiColorPicker exist with event/hit/focus integration. |
| UI shape node | done | UiShape renders rect/circle/triangle UI primitives. |
| UI image node | done | UiImage renders texture IDs with tint, region, scale mode, alignment, and aspect ratio. |
| UI image button node | done | UiImageButton renders a clickable image with image scale/alignment plus hover/pressed tint/layout overrides, default <node_name>_<event> button signals, and extra *_signals lists. |
| UI nine-slice node | done | UiNineSlice auto-splits textures into thirds with fixed corners and tiled edges/center; custom margins override the split. |
| UI animated image node | done | UiAnimatedImage renders sprite-sheet animations in UI space with UiImage scale/alignment behavior. |
| UI camera stream | done | UiCameraStream renders 2D or 3D camera output inside UI layout, with aspect mode, tint, corner radius, and stream texture reuse. |
| UI sub view | done | UiSubView renders UI-owned mixed Node2D/Node3D descendants inside its clipped UI rect through implicit local views or active descendant cameras. Legacy UiViewport names load as an alias. |
| UI style resources | done | Inline style = { ... } blocks and res://path/to/style.uistyle load for normal/hover/pressed/focused state styles, mirroring material resource flow. See .uistyle. |
| Area | Status | Notes |
|---|---|---|
| CLI project flow | done | new, check, dev, build, DLC, profiling, format, clippy, clean. |
perro doctor |
done | Checks project config, scene/resource refs, and user script path/member warnings. |
| Web export | done | perro_cli build --target web, WASM docs, and perro_website demo hosting exist. |
| Demo hubs | done | demos/Demo3D has a hub, pause flow, feature scenes, docs, and web bundle. demos/Demo2D has matching hub/pause flow and stress zones. |
| Demo2D parity | done | Demo2D covers sprite, light, water, animation, physics, skeletal, dense batch, particle, and positional-audio stress zones. |
| Perro editor | in dev | Core authoring milestone includes project manager, responsive shell, scene tabs, asset browser/watch, 2D/3D/UI viewport tools, inspector, animation and GLB workflows, undo/redo, destructive-action confirmation, external-change guards, tests, CI, and an editor guide. Play/build launch and richer import tooling remain follow-up work. |
- Navmesh static bake + Demo3D lane.
- Automatic retargeting.
- 2D shadow polish.
- Perro editor play/build launch and richer import tooling.
- Joint polish: optional limits/motors/springs if needed.