Create
Your first build
Build a program that puts text on the Kode Dot's screen and follows your finger, then flash it over USB-C. The whole loop once, end to end.
What it is
The loop you will repeat for every app: write C, build it into an image, write the image onto the Kode Dot over the USB-C cable, watch the log. This page runs it once with a program that shows text on the screen and moves it to wherever you touch, so you see the screen, the touch and the toolchain work in one go.
With the toolchain from build/setup, it takes five minutes. Without it,
the play button on the code below installs the same program on a Kode Dot
from Chrome or Edge, so you can see it run before you install anything. It
goes on as an app, next to the ones the Kode Dot has, and kodeOS stays.
How to run it
- Create a project from the template, as
build/setupshows, and put the code below inmain/app_main.c. - Build it:
idf.py build. - Plug the Kode Dot in over USB-C and find its port: on macOS
ls /dev/cu.usbmodem*. - Flash it and stay on the log:
idf.py -p <port> flash monitor. - Touch the screen. The text follows your finger, and the log shows the board coming up.
Gotchas
Example code
Text in the middle of the screen that moves to wherever you touch. The play button writes this exact program onto a Kode Dot on the cable.
/*
* first_build.c - 2026-09-18 - from Kode with love
*
* Draws a label in the middle of the Kode Dot's screen and moves it to the
* last point touched. Brings the board up, which starts LVGL and the touch
* controller, then creates the label and a timer that reads the touch state
* thirty times a second. The text follows your finger.
*/
#include "kode.h"
static lv_obj_t *s_label;
/* Runs inside the LVGL task: read the one input device and move the label to it. */
static void follow_touch(lv_timer_t *timer)
{
(void)timer;
lv_indev_t *touch = lv_indev_get_next(NULL);
if (!touch || lv_indev_get_state(touch) != LV_INDEV_STATE_PRESSED) return;
lv_point_t p;
lv_indev_get_point(touch, &p);
lv_obj_set_pos(s_label, p.x - lv_obj_get_width(s_label) / 2, p.y - 12);
}
/* Board and LVGL, then the label and its timer, under the LVGL lock. */
void app_main(void)
{
ESP_ERROR_CHECK(kode_bsp_init());
kode_bsp_lvgl_lock();
s_label = lv_label_create(lv_display_get_screen_active(kode_bsp_display()));
lv_label_set_text(s_label, "Hello, Kode Dot");
lv_obj_set_style_text_font(s_label, &lv_font_montserrat_16, 0);
lv_obj_center(s_label);
lv_timer_create(follow_touch, 33, NULL);
kode_bsp_lvgl_unlock();
}Compiled on the date in the header against the kode component with
ESP-IDF v6.1, and that build is what the play button installs. TBD: a run
on a V1 board from this page.
In the SDK
templates: the project this one starts from, inkode-sdk.