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.
- Perl (any modern version — uses only core modules plus
MIME::Base64) - Unleashed firmware repo with
fbtfor building the generated project
perl fzgen.pl myapp.ini ./myappThen drop the output folder into the firmware tree and build:
cp -r ./myapp unleashed-firmware/applications_user/
cd unleashed-firmware
./fbt fap_myappmyapp/
├── 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
Running fzgen.pl on an existing project updates it without stomping your code.
| File | Behavior |
|---|---|
application.fam |
Always regenerated — never hand-edit this |
myapp_icon.png |
Created once, never overwritten — replace with your own icon |
myapp_scene_config.c |
Always regenerated — never hand-edit this |
myapp_app.h |
Marker-based updates only — your custom code is preserved |
myapp.c |
Marker-based updates only — your custom code is preserved |
scenes/myapp_scene.h |
Marker-based updates only |
scenes/myapp_scene_*.c |
Created 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.
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_enumOn regeneration, only the content between markers is replaced. Everything outside the markers — your custom includes, functions, and logic — is untouched.
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[app] — metadata written into application.fam
| Key | Description |
|---|---|
id |
Lowercase app identifier — used in filenames and function names |
name |
Human-readable name shown in the Flipper app browser |
author |
Your name or handle |
category |
App browser folder: RFID, NFC, Bluetooth, GPIO, Tools, Games, Misc |
stack_size |
Stack 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.
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_closeYour 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.
- All views are generated as
Widget*by default. If a scene needs aSubmenu,Popup, orVariableItemList, change the type inmyapp_app.hand update the alloc/free inmyapp.cmanually. - The placeholder icon is a 10x10 1-bit PNG box border embedded in the
script as base64. Replace
myapp_icon.pngwith your own icon — it will never be overwritten. scenes/myapp_scene_config.cis always regenerated since it's pure boilerplate. Never hand-edit it.
Do what you want with it.