🌟 Like this project? Star the GitHub Repo!! 🌟
An experimental, high-performance game engine and rendering pipeline for the terminal. Written in Python with NumPy. (Soon to include Rust.)
Table of Contents:
Rust Progress (Demo): (01/07/2024)
TrueColor 24-bit Terminal Printing
The transition to Rust is well underway, and progressing much faster than I had anticipated given Rust's reputation for a steep learning curve. I am still working on properly benchmarking Rust code, so I have no hard numbers to share yet. However, the Rust code is already vastly outperforming the Python code, even in its current state. Right now, I am in the "just get it to work" stage so it lacks any significant optimizations. Despite this, the Rust version of
HemeraTermFxcan print full 24-bit RGB color to to the terminal at a relatively usable speed and resolution (360*200 @~20-60 fps).See print GIF demos here (note: same link as above).
The next steps are to:
- Properly allocate memory for the various buffers -- and reusing those buffers throughout the lifetime of the program.
- Begin working on a basic delta framebuffer system once the memory allocation is sorted.
- Trial various quantization methods for the 24-bit RGB colors to allow for dynamic fidelity adjustments as a means to keep a stable frame rate.
- For example, if the framerate is slipping, the engine can automatically reduce the color fidelity to maintain a stable frame rate.
- Conversely, if the engine is spending time sleeping, it can increase the color fidelity to improve the visual quality.
- Figure out how to profile Rust code to get a better idea of where the bottlenecks are and begin aggressively optimizing the code.
Release v0.1.1-alpha: (01/03/2025)
Further Optimizations
Update: I decided to go with Rust instead of C.
This update further optimizes the terminal printing performance by refactoring the
HemeraTermFxclass. TheNyxEngineclass has been updated to enforce game state consistency across the project, holding all instances of the major subclasses. Additionally, therequirements.txtfile now includesline_profilerfor performance testing to fix missing dependencies.I will probably begin transitioning parts of the project to
CRust because the Python interpreter is not fast enough for the performance I want to achieve. Once the transition is complete, I will be able to focus on implementing more complex features and optimizations that are currently out of reach due to Python's limitations. I am excited about the possibilities that this transition will open up and look forward to sharing the progress with you all.Benefits using
CRust include:
- Safelyallocatae memory for the various frame buffers and arrays and manage them directly.
- Drastically improve the performance of the printing pipeline by speeding up the string buffer loop.
- Improve printing performance by directly printing bytes to the terminal.
- Completely avoid string generation for the terminal output by generating the ANSI escape sequences directly as bytes stored in a dedicated buffer.
What this means:
- Implement full color support for 24-bit RGB colors (!!!)
- Allow real-time conversion of video files to terminal output.
Release v0.1.0-alpha: (12/27/2024)
Major Performance Gain
The latest release, v0.1.0-alpha, introduces significant performance improvements to the printing speed of the engine. When printing to the terminal, the ndarrays (frames) must be converted to a printable string format. Profiling the code revealed that this conversion was the significant bottleneck in the terminal printing process. After a many, many rounds of line profiling and optimizing the string generation, the printing speed of a 480x360 resolution frame has improved by 95%, from 0.0954 seconds per frame to 0.0069 seconds per frame -- while still running on a single thread.
This optimization significantly enhances the engine's performance and opens up new possibilities for more complex and faster-rendering games and applications in the terminal. The magnitude of the improvement is such that a minor version bump is well-warranted, despite the lack of any new or major feature.
The GIF below demonstrates the printing speed difference between the previous release (v0.0.4-alpha) and the current release (v0.1.0-alpha).
Printing speed of V0.0.4-alpha (left, 0.0954 sec/frame) vs v0.1.0-alpha (right, 0.0069 sec/frame)
Internal Resolution: 480x360
NyxEngine is a proof-of-concept, real-time, 24-bit RGB pseudographics rendering pipeline and game engine that aims to push the boundaries of what can be done in a standard terminal. In its final form, NyxEngine will encompass two main components: a high-performance graphics/pseudographics library with rasterized terminal output, and the game engine itself.
For now, it requires a little... imagination.
![]() |
|---|
| Side-by-side comparison of GIFs rendered directly in the terminal: 256-color Python v0.0.4-alpha (left) vs. smooth 24-bit Rust PoC (right). |
Note
This has been asked of me before, so I want to clarify:
Like other graphics libraries, NyxEngine is designed to be highly optimized for performance and efficiency. However, that does not mean it won't melt your processor.
Rather, rendering real-time 24-bit graphics in the terminal requires significant computational resources. The result is/will be a smooth, high-fidelity experience without overwhelming the terminal or compromising performance -- but I don't expect it to run well on any random potato without a significant breakthrough.
-
- Achieves increased fidelity by simulating higher resolution with foreground/background ANSI colors and the stacked vertical block character (▀).
-
- Optimizes performance by updating only the pixels that change between frames, minimizing the computational cost of terminal rendering.
-
- Uses the full spectrum of ANSI 256-color codes for vibrant, high-quality output. Avoids unpredictable custom palette issues by skipping colors 0-15.
- 24-bit RGB Color Support COMING SOON (Rust version).
-
- Enables priority-based composition by merging layers from highest to lowest, ensuring accurate display of overlapping objects.
-
- Reduces unnecessary ANSI escape sequences, significantly improving rendering speed by issuing updates only when colors or cursor positions change.
-
- Utilizes 3D NumPy arrays for efficient handling of color stacks, enabling fast computations and smooth animations in the terminal environment.
- Transitioning to Rust for performance-critical components to achieve the highest possible rendering speed and efficiency.
The demo videos for NyxEngine have moved:
| Version | Demo Videos |
|---|---|
| Unreleased Rust-Powered | YouTube Playlist |
| v0.1.1-alpha and Earlier | Github Pages |
The current release is able to render animated sprites and tilemaps to the terminal. The engine is still in its early stages, with many features yet to be implemented. Until the engine is more mature, the primary use case is for experimentation and exploration of terminal rendering capabilities. Detailed usage instructions will be provided once the engine has better-defined workflows and features.
The current release displays a demo of a starship flying through space and firing lasers. I was hoping to have a better demo for this release, but I needed to push an update to fix some architechtural and documentation issues. The next release will have a more polished demo. Check out the npz.py file in the feature/demo-files branch for a sneak peek at the next release.
1. Clone the repository:
-
git clone https://github.com/cmorman89/nyx-engine
2. Change to the NyxEngine directory:
-
cd nyx-engine
3. Install Dependencies:
-
pip install numpy pytest line_profiler
4. Run the project main file:
-
python main.py
-
- Import npz files for multiple frames or sprites.
-
- Refactor
HemeraTermFxto further optimize terminal printing performance. - Update
NyxEngineas the main enforcer of game state consistency across the project. It now holds all instances of the major subclasses. - Update
requirements.txtto include line_profiler for performance testing.
- Refactor
-
- New method and hooks in
HemeraTermFxto enable line profiling for performance testing. - GIF demos in the
examples\demosfolder to showcase the project's capabilities. - Add an alient planet sprite to the current game demo in
main.py.
- New method and hooks in
-
- Optimize terminal printing string generation for a 95% reduction in frame printing time.
See the full changelog here.
Implemented Features:
- Printing:
- Use 256-color extended ANSI
- Note: This excludes codes 0-15 as these often use custom color palettes in each terminal -- making for unpredictable color output.
- Delta-only rendering to optimize performance by updating only changed pixels.
- Compares the current and last subpixel array frame to detect and retain changes.
- Maintains color integrity of paired color data by including both foreground and background color, even if only one has changed.
- Runbuffer detection for both foreground and background colors, significantly reducing the performance cost of reissuing ANSI escape sequences.
- Only issues ANSI excape codes when required for a cursor relocation or a color change.
- Subcharacter rendering
- Simulates higher resolution using foreground/background colors and special characters (e.g., ▀).
- Stored in a 3D NumPy array to create a "stack" of the fg/bg color pair.
- Use 256-color extended ANSI
- Rendering:
- Create intermediate subframes for each z-index, where the matching z-indexed entity can be drawn onto.
- Use the z-indicies as priorities to collapse the subframes into a final merged frame.
- Starts at the highest z-index and value and works down, essentially "filling in" only pixels that are still transparent/unoccupied after each layer merge. This creates a prioritized merge system that respects the layer hierarchy.
- Any remaining transparency after merging is filled by a static background color, if set.
- Render animated, infinitely scrolling tilemaps.
- Render animated sprites to the terminal with velocity and position updates.
- Game Engine:
- Basic game loop with a fixed timestep.
- Basic entity-component-system (ECS) architecture.
- Data:
- Load textures from .npz files (matrix array in plain text).
Expected Features:
-
Data:
- Efficiently store and load assets.
-
Engine:
- Side-scrolling games.
- Room-based map exploration.
- Open-world environments.
- Full keyboard support for input handling.
-
Rendering:
- Full 24-bit RGB color support.
- Quantization methods for dynamic color fidelity adjustments.
-
Plus more to come as the project evolves!
NyxEngine is current a proof-of-concept project and is not yet ready for direct contributions for two main reasons:
- The project is still in its early stages and maybe rewritten or refactored significantly (and in a breaking manner) as it evolves.
- I am using this project as a means of learning, experimentation, and as a way to push the boundaries of my own knowledge.
However, I am always open to feedback, suggestions, and ideas. If you have any thoughts or ideas on how to improve the project, please feel free to reach out to me at nyx-engine@cmorman.com.
I would genuinely love to hear from you!
This project is thematically named after some of the oldest Greek gods, which rather poetically flows with comparatively "ancient" underpinnings of a text-based terminal.
Learn More:
-
- In the Greek pantheon, Nyx is a primordial goddess who personifies the night, predating even the Olympian gods. She is the daughter of Chaos, the first primordial entity, and the mother of numerous powerful deities, including Moros (Doom), Aether (Upper Air), and Hemera (Day). Nyx commands immense power and influence, earning the respect and fear of even the mighty Olympians, who are said to tremble in her presence. Her dominion over the night and all that it encompasses makes her one of the most enigmatic and formidable forces in the cosmos. Despite her vast power, Nyx's role is often more subtle, as she works behind the scenes to shape the course of events in the universe.
-
- The Moirai are better known as the Fates and are children of Nyx (source depending). Together, the three sisters determine the destiny and fate of both mortals and divine beings, alike. Clotho spins the thread representing the start of life; Lachesis allots the path that life will follow; and Atropos cuts the thread, ending that life's journey.
-
- Aether is the son of Nyx (Night) and Erebus (Darkness). He personifies the upper air—the pure, bright atmosphere breathed by the gods. Aether is also considered the ethereal medium through which the divine realm is perceived, representing the luminous, untainted essence that fills the heavens.
-
- Hemera is the personification of day and light, the daughter of Nyx (Night) and Erebus (Darkness). As the embodiment of light, she dispels the shadows of night, bringing clarity and illumination to creation and all within it
NyxEngine is licensed under the MIT License.
You are free to use, modify, and distribute this software for personal or commercial purposes, provided that you include the original copyright notice and this permission notice in any copies or substantial portions of the software.
See the LICENSE file.
Contact: nyx-engine@cmorman.com
⭐ If you like this project, give it a star!


