fzgen

May 28, 2026 · View on GitHub

A Perl script that scaffolds Flipper Zero external application (FAP) projects from a simple INI config file. Generates all the boilerplate — app header, main C file, scene manager wiring, scene stubs — so you can start writing actual logic immediately.

Designed to work with Unleashed firmware but compatible with stock firmware and other forks.


Requirements

  • Perl (any modern version — uses only core modules plus MIME::Base64)
  • Unleashed firmware repo with fbt for building the generated project

Usage

perl fzgen.pl myapp.ini ./myapp

Then drop the output folder into the firmware tree and build:

cp -r ./myapp unleashed-firmware/applications_user/
cd unleashed-firmware
./fbt fap_myapp

What gets generated

myapp/
├── application.fam              — FAP manifest (appid, name, category, etc.)
├── myapp_icon.png               — Placeholder 10x10 1-bit icon (box border)
├── myapp_app.h                  — App struct, scene/view/event enums
├── myapp.c                      — Entry point, alloc/free, view dispatcher
└── scenes/
    ├── myapp_scene.h            — Forward declarations for all scenes
    ├── myapp_scene_config.c     — Handler array table (wires scenes together)
    ├── myapp_scene_splash.c     — Scene stub (on_enter / on_event / on_exit)
    ├── myapp_scene_menu.c       — Scene stub
    └── myapp_scene_*.c          — One stub per scene in your config

Regeneration — safe by design

Running fzgen.pl on an existing project updates it without stomping your code.

FileBehavior
application.famAlways regenerated — never hand-edit this
myapp_icon.pngCreated once, never overwritten — replace with your own icon
myapp_scene_config.cAlways regenerated — never hand-edit this
myapp_app.hMarker-based updates only — your custom code is preserved
myapp.cMarker-based updates only — your custom code is preserved
scenes/myapp_scene.hMarker-based updates only
scenes/myapp_scene_*.cCreated once, never overwritten — you own these

Adding a new scene to the config creates only the new scene file. Existing scene files are skipped entirely.

Marker system

Generated sections in .h and main .c files are wrapped in markers:

// @FZGEN_BEGIN scene_enum
typedef enum {
    MyappSceneSplash,
    MyappSceneMenu,
    MyappSceneCount,
} MyappScene;
// @FZGEN_END scene_enum

On regeneration, only the content between markers is replaced. Everything outside the markers — your custom includes, functions, and logic — is untouched.


Config file format

See framework.ini for a fully commented template. The short version:

[app]
id = myapp
name = My App
author = YourName
category = Misc
stack_size = 2 * 1024

[scenes]
Splash = default    # must have exactly one default
Menu
Detail
Result

[struct]
bool show_hints
uint8_t selected_index

[events]
AppExit
SplashNext
MenuSelect

Sections

[app] — metadata written into application.fam

KeyDescription
idLowercase app identifier — used in filenames and function names
nameHuman-readable name shown in the Flipper app browser
authorYour name or handle
categoryApp browser folder: RFID, NFC, Bluetooth, GPIO, Tools, Games, Misc
stack_sizeStack in bytes — 2 * 1024 for simple apps, 4 * 1024 for heavier work

[scenes] — one scene per line in PascalCase, exactly one marked = default

[struct] — extra fields added to the app struct, written as C declarations without the semicolon

[events] — custom event names added to the CustomEvent enum

Comments (#) are supported anywhere.


Generated scene stub

Each scene file starts as:

#include "myapp_scene.h"

// @FZGEN_BEGIN splash_on_enter
void myapp_scene_splash_on_enter(void* context) {
    furi_assert(context);
    MyappApp* app = context;
    UNUSED(app);
// @FZGEN_END splash_on_enter
    // TODO: add your on_enter logic here
// @FZGEN_BEGIN splash_on_enter_close
    view_dispatcher_switch_to_view(app->view_dispatcher, MyappViewSplash);
}
// @FZGEN_END splash_on_enter_close

Your logic goes in the // TODO sections. The markers at the top and bottom of each function allow the generator to update the function signature if needed without touching your implementation.


Notes

  • All views are generated as Widget* by default. If a scene needs a Submenu, Popup, or VariableItemList, change the type in myapp_app.h and update the alloc/free in myapp.c manually.
  • The placeholder icon is a 10x10 1-bit PNG box border embedded in the script as base64. Replace myapp_icon.png with your own icon — it will never be overwritten.
  • scenes/myapp_scene_config.c is always regenerated since it's pure boilerplate. Never hand-edit it.

License

Do what you want with it.