Top Related Projects
Quick Overview
Coffee is a Rust library for building cross-platform graphical user interfaces (GUIs). It provides a high-level, declarative API for creating and managing GUI applications, with a focus on simplicity, performance, and flexibility.
Pros
- Cross-platform: Coffee supports multiple platforms, including Windows, macOS, and Linux, allowing developers to create a single codebase that can be deployed across different operating systems.
- Declarative API: The library's API is declarative, making it easier to reason about and compose UI elements, leading to more maintainable and scalable code.
- Performance: Coffee is built on top of the Rust programming language, which provides low-level control and high-performance, making it suitable for building responsive and efficient GUI applications.
- Flexibility: The library is designed to be modular and extensible, allowing developers to customize and extend its functionality as needed.
Cons
- Relatively new: Coffee is a relatively new library, and as such, it may have a smaller community and fewer resources available compared to more established GUI frameworks.
- Learning curve: The declarative nature of the API and the use of Rust may present a steeper learning curve for developers who are more familiar with imperative or object-oriented approaches to GUI development.
- Limited ecosystem: While Coffee provides a solid foundation for building GUI applications, the ecosystem of third-party libraries and tools may be smaller compared to more mature GUI frameworks.
- Rust-specific: As Coffee is built on Rust, it may not be the best choice for developers who are not familiar with or interested in learning the Rust programming language.
Code Examples
Here are a few code examples demonstrating the usage of the Coffee library:
- Creating a simple window:
use coffee::prelude::*;
fn main() {
Application::new()
.title("Hello, Coffee!")
.size(800, 600)
.run(HelloWorld {})
}
struct HelloWorld {}
impl Program for HelloWorld {
type Msg = ();
type Settings = ();
fn update(&mut self, _msg: Self::Msg, _state: &mut ApplicationState) {}
fn draw(&self, frame: &mut Frame) {
frame.clear(Color::WHITE);
frame.text("Hello, Coffee!", (400, 300), 32.0, Color::BLACK);
}
}
- Creating a button:
use coffee::prelude::*;
fn main() {
Application::new()
.title("Button Example")
.size(800, 600)
.run(ButtonExample {})
}
struct ButtonExample {
button_state: ButtonState,
}
impl Program for ButtonExample {
type Msg = ButtonMessage;
type Settings = ();
fn new(_settings: Self::Settings) -> Self {
ButtonExample {
button_state: ButtonState::new(),
}
}
fn update(&mut self, msg: Self::Msg, state: &mut ApplicationState) {
self.button_state.update(msg, state);
}
fn draw(&self, frame: &mut Frame) {
frame.clear(Color::WHITE);
self.button_state.draw(frame, (400, 300), 100, 50, "Click me!");
}
}
- Handling user input:
use coffee::prelude::*;
fn main() {
Application::new()
.title("Input Example")
.size(800, 600)
.run(InputExample {})
}
struct InputExample {
input_state: InputState,
}
impl Program for InputExample {
type Msg = InputMessage;
type Settings = ();
fn new(_settings: Self::Settings) -> Self {
InputExample {
input_state: InputState::new(),
}
}
fn update(&mut self, msg: Self::Msg, state: &mut ApplicationState) {
self.input_state.update(msg, state);
}
fn draw(&self, frame: &mut Frame) {
frame.clear(Color::WHITE);
self.input_state.draw(frame
Competitor Comparisons
A fast and flexible Markdown parser written in Swift.
Pros of Ink
- Written in Swift, offering native performance and integration with Apple platforms
- Supports custom themes and syntax highlighting out of the box
- Provides a more comprehensive set of features for static site generation
Cons of Ink
- Limited to Swift ecosystem, reducing cross-platform compatibility
- Steeper learning curve for developers not familiar with Swift
- Less flexible for creating custom templating languages
Code Comparison
Ink (Swift):
struct MyTheme: HTMLFactory {
func makeHeader(for site: Site) -> Node {
.header(
.h1(.text(site.name)),
.p(.text(site.description))
)
}
}
Coffee (Rust):
fn header(site: &Site) -> Node {
html! {
<header>
<h1>{ &site.name }</h1>
<p>{ &site.description }</p>
</header>
}
}
Both examples demonstrate creating a header component, but Ink uses a more object-oriented approach with structs and methods, while Coffee utilizes a functional style with standalone functions and a custom HTML macro.
Stencil is a simple and powerful template language for Swift.
Pros of Stencil
- More actively maintained with recent updates
- Larger community and ecosystem
- Supports a wider range of template features and syntax
Cons of Stencil
- Steeper learning curve for beginners
- Potentially more complex setup for simple projects
- Heavier dependency footprint
Code Comparison
Stencil example:
struct Article: Codable {
let title: String
let body: String
}
let context = ["article": Article(title: "Hello", body: "World")]
let template = "{{ article.title }} - {{ article.body }}"
let rendered = try stencil.renderTemplate(string: template, context: context)
Coffee example:
use coffee::graphics::{Color, Frame, Window, WindowSettings};
use coffee::load::Task;
use coffee::{Game, Result, Timer};
struct MyGame;
impl Game for MyGame {
fn load(_window: &Window) -> Task<MyGame> {
Task::new(|| MyGame)
}
}
While both projects serve different purposes (Stencil for templating and Coffee for game development), this comparison highlights their syntax and usage differences. Stencil focuses on template rendering, while Coffee provides a game development framework with a more declarative approach.
A package manager that installs and runs executable Swift packages
Pros of Mint
- More active development with recent updates and releases
- Broader scope, supporting full app development beyond just UI
- Larger community and more extensive documentation
Cons of Mint
- Steeper learning curve due to more complex features
- Less focused on UI-specific tasks compared to Coffee
- Potentially overkill for simple projects or prototypes
Code Comparison
Mint example:
component Main {
fun render : Html {
<div>
<h1>"Hello, Mint!"</h1>
<p>"Welcome to my app."</p>
</div>
}
}
Coffee example:
view : Model -> Html Msg
view model =
div []
[ h1 [] [ text "Hello, Coffee!" ]
, p [] [ text "Welcome to my app." ]
]
Both frameworks use a declarative approach to UI development, but Mint's syntax is more concise and JavaScript-like, while Coffee follows Elm's functional style. Mint's component-based structure is evident in the example, whereas Coffee's view function is part of the Elm architecture.
Mint offers a more comprehensive solution for web app development, including state management and routing out of the box. Coffee, being based on Elm, provides a simpler and more focused approach to UI development with strong type safety. The choice between the two depends on project requirements and developer preferences.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Coffee
An opinionated 2D game engine for Rust focused on simplicity, explicitness, and type-safety.
Coffee is in a very early stage of development. Many basic features are still missing, some dependencies are experimental, and there are probably many bugs. Feel free to contribute!
Features
- Responsive, customizable GUI
- Declarative, type-safe loading screens with progress tracking
- Built-in debug view with performance metrics
- Fixed, deterministic timestep
- Explicit, easy to use, hardware-accelerated 2D graphics API
- Multiplatform support leveraging OpenGL, Vulkan, Metal, D3D11, and D3D12
- Explicit and efficient batched draws
- Mesh support
- Texture array support
- Off-screen rendering
- TrueType font rendering
- Gamepad support
And more! Check out the examples to see them in action.
Usage
Add coffee
as a dependency in your Cargo.toml
and enable a graphics backend
feature (opengl
, vulkan
, metal
, dx11
, or dx12
):
coffee = { version = "0.4", features = ["opengl"] }
Rust is quite slow in debug mode. If you experience performance issues when
drawing hundreds of sprites, enable compiler optimizations in your Cargo.toml
.
I recommend level 2 optimizations in order to stay closer to --release
performance:
[profile.dev]
opt-level = 2
Coffee moves fast and the master
branch can contain breaking changes! If
you want to learn about a specific release, check out the release list.
Overview
Here is a minimal example that will open a window:
use coffee::graphics::{Color, Frame, Window, WindowSettings};
use coffee::load::Task;
use coffee::{Game, Result, Timer};
fn main() -> Result<()> {
MyGame::run(WindowSettings {
title: String::from("A caffeinated game"),
size: (1280, 1024),
resizable: true,
fullscreen: false,
maximized: false,
})
}
struct MyGame {
// Your game state and assets go here...
}
impl Game for MyGame {
type Input = (); // No input data
type LoadingScreen = (); // No loading screen
fn load(_window: &Window) -> Task<MyGame> {
// Load your game assets here. Check out the `load` module!
Task::succeed(|| MyGame { /* ... */ })
}
fn draw(&mut self, frame: &mut Frame, _timer: &Timer) {
// Clear the current frame
frame.clear(Color::BLACK);
// Draw your game here. Check out the `graphics` module!
}
}
Browse the documentation and the examples to learn more!
Implementation details
Coffee builds upon
winit
for windowing and mouse/keyboard events.gfx
pre-ll for OpenGL support, based heavily on theggez
codebase.wgpu
for experimental Vulkan, Metal, D3D11 and D3D12 support.stretch
for responsive GUI layouting based on Flexbox.glyph_brush
for TrueType font rendering.gilrs
for gamepad support.nalgebra
for thePoint
,Vector
, andTransformation
types.image
for image loading and texture array building.
Contributing / Feedback
I am quite new to Rust, systems programming, and computer graphics. I am learning along the way as I build the engine for a game I am currently developing. I am always glad to to learn from anyone.
If you want to contribute, you are more than welcome to be a part of the project! Check out the current issues if you want to find something to work on. Try to share you thoughts first! Feel free to open a new issue if you want to discuss new ideas.
Any kind of feedback is welcome! You can open an issue or, if you want to talk,
you can find me (and a bunch of awesome folks) over the #games-and-graphics
channel in the Rust Community Discord. I go by @lone_scientist
there.
Credits / Thank you
ggez
, an awesome, easy-to-use, good game engine that introduced me to Rust. Its graphics implementation served me as a guide to implement OpenGL support for Coffee.- Kenney, creators of amazing free game assets with no strings attached. The built-in GUI renderer in Coffee uses a modified version of their UI sprites.
Top Related Projects
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot