Quick Start
This guide will walk you through creating your first Fern application - a simple click counter with buttons. You’ll learn the fundamentals of building UIs with Fern’s widget system.
Prerequisites
Before starting, make sure you have:
C++17 compiler (g++ or clang++)
CMake 3.10+
Fern installed globally (see Installation Guide )
Create Your First Project
Create a new project
Use the Fern CLI to scaffold a new project: fern sprout my-counter
cd my-counter
This creates a new directory with the basic project structure: my-counter/
├── lib/
│ └── main.cpp
├── fern.yaml
└── README.md
Write your first app
Open lib/main.cpp and replace its contents with this click counter example: #include <fern/fern.hpp>
#include <iostream>
using namespace Fern ;
static int clickCount = 0 ;
static std ::shared_ptr < TextWidget > counterDisplay;
void setupUI () {
// Counter display
counterDisplay = Text ( Point ( 0 , 0 ), "Clicks: 0" , 3 , Colors ::White);
// Click button
auto button = Button (
ButtonConfig ( 0 , 0 , 150 , 50 , "Click Me!" )
. style ( ButtonStyle ()
. normalColor ( Colors ::Blue)
. hoverColor ( Colors ::LightBlue)
. pressColor ( Colors ::DarkBlue)
. textColor ( Colors ::White)
. textScale ( 2 )
)
);
button -> onClick . connect ([]() {
clickCount ++ ;
counterDisplay -> setText ( "Clicks: " + std :: to_string (clickCount));
std ::cout << "Button clicked " << clickCount << " times!" << std ::endl;
});
// Reset button
auto resetButton = Button (
ButtonConfig ( 0 , 0 , 100 , 40 , "Reset" )
. style ( ButtonStyle ()
. normalColor ( Colors ::Red)
. hoverColor ( Colors ::LightRed)
. pressColor ( Colors ::DarkRed)
. textColor ( Colors ::White)
. textScale ( 2 )
)
);
resetButton -> onClick . connect ([]() {
clickCount = 0 ;
counterDisplay -> setText ( "Clicks: 0" );
std ::cout << "Counter reset!" << std ::endl;
});
// Layout
std ::vector < std ::shared_ptr < Widget >> children = {
counterDisplay,
SizedBox ( 0 , 30 ),
button,
SizedBox ( 0 , 20 ),
resetButton
};
addWidget ( Center ( Column (children)));
}
void draw () {
Draw :: fill ( Colors ::DarkBlue);
}
int main () {
Fern :: initialize ();
setupUI ();
Fern :: setDrawCallback (draw);
Fern :: startRenderLoop ();
return 0 ;
}
Run your app
Build and run your application: Your app will compile and launch in a new window!
Understanding the Code
Let’s break down the key components of your first Fern app:
1. State Management
static int clickCount = 0 ;
static std ::shared_ptr < TextWidget > counterDisplay;
We use static variables to maintain state across function calls. The counterDisplay stores a reference to the text widget so we can update it later.
counterDisplay = Text ( Point ( 0 , 0 ), "Clicks: 0" , 3 , Colors ::White);
The Text widget displays text. Parameters are: position, text content, font size, and color.
auto button = Button (
ButtonConfig ( 0 , 0 , 150 , 50 , "Click Me!" )
. style ( ButtonStyle ()
. normalColor ( Colors ::Blue)
. hoverColor ( Colors ::LightBlue)
. pressColor ( Colors ::DarkBlue)
. textColor ( Colors ::White)
. textScale ( 2 )
)
);
The Button widget uses a builder pattern with ButtonConfig and ButtonStyle to configure appearance and behavior.
3. Event Handling
button -> onClick . connect ([]() {
clickCount ++ ;
counterDisplay -> setText ( "Clicks: " + std :: to_string (clickCount));
});
Fern uses a signal-slot system for events. Connect lambda functions to handle clicks and update the UI dynamically.
4. Layout System
std ::vector < std ::shared_ptr < Widget >> children = {
counterDisplay,
SizedBox ( 0 , 30 ), // Vertical spacing
button,
SizedBox ( 0 , 20 ),
resetButton
};
addWidget ( Center ( Column (children)));
Column : Arranges widgets vertically
SizedBox : Adds spacing between widgets
Center : Centers the entire column on screen
5. Rendering Loop
void draw () {
Draw :: fill ( Colors ::DarkBlue);
}
int main () {
Fern :: initialize ();
setupUI ();
Fern :: setDrawCallback (draw);
Fern :: startRenderLoop ();
return 0 ;
}
Fern::initialize(): Initializes the window (default 800x600)
setupUI(): Creates and positions widgets
setDrawCallback(): Registers the background drawing function
startRenderLoop(): Begins the event loop
Next Steps
Explore Widgets Learn about Text, Button, Slider, Progress Bar, and more
Master Layouts Create complex UIs with Row, Column, Padding, and Expanded
Creating Widgets Build custom widgets for your application
Deploy to Web Compile your app to WebAssembly for browser deployment
Pro Tips
Hot Reload : During development, use fern fire to automatically rebuild when you save changes.
Window Size : Pass dimensions to Fern::initialize() to customize window size:Fern :: initialize ( 900 , 700 ); // 900x700 window
Always store widget references (like counterDisplay) as std::shared_ptr<Widget> to ensure proper memory management.
Common Patterns
ButtonStyle createModernButton ( uint32_t color ) {
ButtonStyle style;
style . normalColor (color)
. hoverColor (color + 0x 00202020 ) // Slightly lighter
. pressColor (color - 0x 00202020 ) // Slightly darker
. textColor ( Colors ::White)
. textScale ( 2 )
. borderRadius ( 12 );
return style;
}
Custom Colors
const uint32_t MyBlue = 0x FF3B82F6 ; // ARGB format
const uint32_t MyGreen = 0x FF10B981 ;
const uint32_t MyRed = 0x FFEF4444 ;
Responsive Layouts
int width = Fern :: getWidth ();
int height = Fern :: getHeight ();
auto centerWidget = std :: make_shared < CenterWidget >( 0 , 0 , width, height);
Congratulations! You’ve built your first Fern application. Continue exploring the documentation to learn more advanced features.