diff --git a/src/app.c b/src/app.c
index 9a5d775..14b16bb 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1,20 +1,64 @@
 /*
-   app.c
-     - template app
-     - loads only stable APIs
+   example_basic_2.c
+     - demonstrates loading APIs
+     - demonstrates loading extensions
+     - demonstrates hot reloading
+     - demonstrates starter extension
+     - demonstrates basic drawing extension (2D)
+     - demonstrates basic screen log extension
+     - demonstrates basic console extension
+     - demonstrates basic UI extension
 */
 
 /*
 Index of this file:
+// [SECTION] quick notes
 // [SECTION] includes
 // [SECTION] structs
 // [SECTION] apis
-// [SECTION] helper functions forward declarations
 // [SECTION] pl_app_load
 // [SECTION] pl_app_shutdown
 // [SECTION] pl_app_resize
 // [SECTION] pl_app_update
-// [SECTION] helper functions implementations
+*/
+
+//-----------------------------------------------------------------------------
+// [SECTION] quick notes
+//-----------------------------------------------------------------------------
+
+/*
+    This example is the first to introduce extensions. Extensions are just
+    shared libraries that export a "load" and "unload" function. The default
+    being:
+
+    * void pl_load_ext  (plApiRegistryI*, bool reload)
+    * void pl_unload_ext(plApiRegistryI*, bool reload)
+    
+    Later examples will explain more about the details of creating an extension
+    but the important thing to understand now is that an extension just provides
+    an implementation of an API. The "load" function allows an extension to
+    request APIs it depends on and to register any API it provides. The unload
+    function just allows an extension the opportunity to unregister and perform
+    any required cleanup.
+
+    This example is also the first to introduce the "starter" extension. This
+    extension acts a bit as a helper extension to remove some common boilerplate
+    but is also just useful in general for most applications only needing to use
+    UI, plotting, drawing, etc. Or even to just experiment with the lower level
+    graphics extension in an isolated manner. Later examples will gradually peel
+    away at this extension and others. For this example, we will just demonstrate
+    some of the smaller helpful extensions. These include:
+
+    * log
+    * profile
+    * stat
+    * console
+    * screen log
+    * ui
+    
+    This will be very light introductions with later examples going into more
+    detail. Feel free to open the header file for the extension for more
+    information and functionality.
 */
 
 //-----------------------------------------------------------------------------
@@ -24,32 +68,22 @@ Index of this file:
 #include <stdlib.h> // malloc, free
 #include <string.h> // memset
 #include "pl.h"
-#include "pl_memory.h"
-#define PL_MATH_INCLUDE_FUNCTIONS
+
+#define PL_MATH_INCLUDE_FUNCTIONS // required to expose some of the color helpers
 #include "pl_math.h"
 
 // extensions
-#include "pl_log_ext.h"
 #include "pl_window_ext.h"
-#include "pl_shader_ext.h"
 #include "pl_draw_ext.h"
+#include "pl_starter_ext.h"
 #include "pl_ui_ext.h"
-#include "pl_graphics_ext.h"
-#include "pl_draw_backend_ext.h"
-#include "pl_profile_ext.h"
-#include "pl_stats_ext.h"
-#include "pl_job_ext.h"
-#include "pl_string_intern_ext.h"
-#include "pl_library_ext.h"
-#include "pl_rect_pack_ext.h"
-#include "pl_gpu_allocators_ext.h"
-#include "pl_image_ext.h"
-#include "pl_console_ext.h"
 #include "pl_screen_log_ext.h"
-#include "pl_tools_ext.h"
-#include "pl_platform_ext.h"
+#include "pl_profile_ext.h"
+#include "pl_log_ext.h"
+#include "pl_stats_ext.h"
+#include "pl_console_ext.h"
 
-// example extensions
+// out extension
 #include "pl_example_ext.h"
 
 //-----------------------------------------------------------------------------
@@ -61,83 +95,34 @@ typedef struct _plAppData
     // window
     plWindow* ptWindow;
 
-    // drawing stuff
-    plDrawList2D*  ptDrawlist;
-    plDrawLayer2D* ptFGLayer;
-    plDrawLayer2D* ptBGLayer;
-    plFont*        ptDefaultFont;
-
-    // ui options
-    bool  bShowUiDebug;
-    bool  bShowUiStyle;
-    bool* pbShowDeviceMemoryAnalyzer;
-    bool* pbShowMemoryAllocations;
-    bool* pbShowProfiling;
-    bool* pbShowStats;
-    bool* pbShowLogging;
-
-    // graphics & sync objects
-    plDevice*                ptDevice;
-    plSurface*               ptSurface;
-    plSwapchain*             ptSwapchain;
-    plTimelineSemaphore*     aptSemaphores[PL_MAX_FRAMES_IN_FLIGHT];
-    uint64_t                 aulNextTimelineValue[PL_MAX_FRAMES_IN_FLIGHT];
-    plCommandPool*           atCmdPools[PL_MAX_FRAMES_IN_FLIGHT];
-    plRenderPassHandle       tMainRenderPass;
-    plRenderPassLayoutHandle tMainRenderPassLayout;
+    // log channel
+    uint64_t uExampleLogChannel;
 
+    // console variable
+    bool bShowHelpWindow;
 } plAppData;
 
 //-----------------------------------------------------------------------------
 // [SECTION] apis
 //-----------------------------------------------------------------------------
 
-const plDataRegistryI*   gptDataRegistry  = NULL;
-const plMemoryI*         gptMemory        = NULL;
-const plIOI*             gptIO            = NULL;
-const plWindowI*         gptWindows       = NULL;
-const plGraphicsI*       gptGfx           = NULL;
-const plDrawI*           gptDraw          = NULL;
-const plUiI*             gptUi            = NULL;
-const plShaderI*         gptShader        = NULL;
-const plDrawBackendI*    gptDrawBackend   = NULL;
-const plProfileI*        gptProfile       = NULL;
-const plExampleI*        gptExample       = NULL;
-const plStatsI*          gptStats         = NULL;
-const plToolsI*          gptTools         = NULL;
-const plImageI*          gptImage         = NULL;
-const plGPUAllocatorsI*  gptGpuAllocators = NULL;
-const plJobI*            gptJob           = NULL;
-const plThreadsI*        gptThreads       = NULL;
-const plAtomicsI*        gptAtomics       = NULL;
-const plRectPackI*       gptRect          = NULL;
-const plFileI*           gptFile          = NULL;
-const plNetworkI*        gptNetwork       = NULL;
-const plStringInternI*   gptString        = NULL;
-const plLibraryI*        gptLibrary       = NULL;
-const plLogI*            gptLog           = NULL;
-const plVirtualMemoryI*  gptVirtualMemory = NULL;
-const plConsoleI*        gptConsole       = NULL;
-const plScreenLogI*      gptScreenLog     = NULL;
+const plIOI*        gptIO        = NULL;
+const plWindowI*    gptWindows   = NULL;
+const plDrawI*      gptDraw      = NULL;
+const plStarterI*   gptStarter   = NULL;
+const plUiI*        gptUI        = NULL;
+const plScreenLogI* gptScreenLog = NULL;
+const plProfileI*   gptProfile   = NULL;
+const plStatsI*     gptStats     = NULL;
+const plMemoryI*    gptMemory    = NULL;
+const plLogI*       gptLog       = NULL;
+const plConsoleI*   gptConsole   = NULL;
+const plExampleI*   gptExample   = NULL;
 
-// helpers
 #define PL_ALLOC(x)      gptMemory->tracked_realloc(NULL, (x), __FILE__, __LINE__)
 #define PL_REALLOC(x, y) gptMemory->tracked_realloc((x), (y), __FILE__, __LINE__)
 #define PL_FREE(x)       gptMemory->tracked_realloc((x), 0, __FILE__, __LINE__)
 
-#define PL_DS_ALLOC(x)                      gptMemory->tracked_realloc(NULL, (x), __FILE__, __LINE__)
-#define PL_DS_ALLOC_INDIRECT(x, FILE, LINE) gptMemory->tracked_realloc(NULL, (x), FILE, LINE)
-#define PL_DS_FREE(x)                       gptMemory->tracked_realloc((x), 0, __FILE__, __LINE__)
-#include "pl_ds.h"
-
-//-----------------------------------------------------------------------------
-// [SECTION] helper functions forward declarations
-//-----------------------------------------------------------------------------
-
-void pl__setup_graphics_extensions (plAppData*);
-void pl__resize_graphics_extensions(plAppData*);
-void pl__resize_graphics_extensions(plAppData*);
-
 //-----------------------------------------------------------------------------
 // [SECTION] pl_app_load
 //-----------------------------------------------------------------------------
@@ -145,13 +130,9 @@ void pl__resize_graphics_extensions(plAppData*);
 PL_EXPORT void*
 pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
 {
-    // NOTE: on first load, "ptAppData" will be NULL but on reloads
+    // NOTE: on first load, "pAppData" will be NULL but on reloads
     //       it will be the value returned from this function
 
-    // retrieve the data registry API, this is the API used for sharing data
-    // between extensions & the runtime
-    gptDataRegistry = pl_get_api_latest(ptApiRegistry, plDataRegistryI);
-
     // if "ptAppData" is a valid pointer, then this function is being called
     // during a hot reload.
     if(ptAppData)
@@ -159,140 +140,85 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
 
         // re-retrieve the apis since we are now in
         // a different dll/so
-        gptMemory        = pl_get_api_latest(ptApiRegistry, plMemoryI);
-        gptIO            = pl_get_api_latest(ptApiRegistry, plIOI);
-        gptWindows       = pl_get_api_latest(ptApiRegistry, plWindowI);
-        gptGfx           = pl_get_api_latest(ptApiRegistry, plGraphicsI);
-        gptDraw          = pl_get_api_latest(ptApiRegistry, plDrawI);
-        gptShader        = pl_get_api_latest(ptApiRegistry, plShaderI);
-        gptDrawBackend   = pl_get_api_latest(ptApiRegistry, plDrawBackendI);
-        gptUi            = pl_get_api_latest(ptApiRegistry, plUiI);
-        gptProfile       = pl_get_api_latest(ptApiRegistry, plProfileI);
-        gptStats         = pl_get_api_latest(ptApiRegistry, plStatsI);
-        gptExample       = pl_get_api_latest(ptApiRegistry, plExampleI);
-        gptTools         = pl_get_api_latest(ptApiRegistry, plToolsI);
-        gptImage         = pl_get_api_latest(ptApiRegistry, plImageI);
-        gptGpuAllocators = pl_get_api_latest(ptApiRegistry, plGPUAllocatorsI);
-        gptJob           = pl_get_api_latest(ptApiRegistry, plJobI);
-        gptThreads       = pl_get_api_latest(ptApiRegistry, plThreadsI);
-        gptAtomics       = pl_get_api_latest(ptApiRegistry, plAtomicsI);
-        gptRect          = pl_get_api_latest(ptApiRegistry, plRectPackI);
-        gptFile          = pl_get_api_latest(ptApiRegistry, plFileI);
-        gptNetwork       = pl_get_api_latest(ptApiRegistry, plNetworkI);
-        gptString        = pl_get_api_latest(ptApiRegistry, plStringInternI);
-        gptLibrary       = pl_get_api_latest(ptApiRegistry, plLibraryI);
-        gptLog           = pl_get_api_latest(ptApiRegistry, plLogI);
-        gptVirtualMemory = pl_get_api_latest(ptApiRegistry, plVirtualMemoryI);
-        gptConsole       = pl_get_api_latest(ptApiRegistry, plConsoleI);
-        gptScreenLog     = pl_get_api_latest(ptApiRegistry, plScreenLogI);
+        gptIO        = pl_get_api_latest(ptApiRegistry, plIOI);
+        gptWindows   = pl_get_api_latest(ptApiRegistry, plWindowI);
+        gptDraw      = pl_get_api_latest(ptApiRegistry, plDrawI);
+        gptStarter   = pl_get_api_latest(ptApiRegistry, plStarterI);
+        gptUI        = pl_get_api_latest(ptApiRegistry, plUiI);
+        gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
+        gptProfile   = pl_get_api_latest(ptApiRegistry, plProfileI);
+        gptStats     = pl_get_api_latest(ptApiRegistry, plStatsI);
+        gptMemory    = pl_get_api_latest(ptApiRegistry, plMemoryI);
+        gptLog       = pl_get_api_latest(ptApiRegistry, plLogI);
+        gptConsole   = pl_get_api_latest(ptApiRegistry, plConsoleI);
+        gptExample   = pl_get_api_latest(ptApiRegistry, plExampleI);
 
         return ptAppData;
     }
 
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~apis & extensions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    
     // retrieve extension registry
     const plExtensionRegistryI* ptExtensionRegistry = pl_get_api_latest(ptApiRegistry, plExtensionRegistryI);
 
     // load extensions
-    ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, false);
-    ptExtensionRegistry->load("pl_platform_ext", NULL, NULL, false);
+    //   * first argument is the shared library name WITHOUT the extension
+    //   * second & third argument is the load/unload functions names (use NULL for the default of "pl_load_ext" &
+    //     "pl_unload_ext")
+    //   * fourth argument indicates if the extension is reloadable (should we check for changes and reload if changed)
+    ptExtensionRegistry->load("pl_unity_ext", NULL, NULL, true);
+    ptExtensionRegistry->load("pl_platform_ext", NULL, NULL, false); // provides the file API used by the drawing ext
     ptExtensionRegistry->load("pl_example_ext", NULL, NULL, true);
     
-    // load apis
-    gptMemory        = pl_get_api_latest(ptApiRegistry, plMemoryI);
-    gptIO            = pl_get_api_latest(ptApiRegistry, plIOI);
-    gptWindows       = pl_get_api_latest(ptApiRegistry, plWindowI);
-    gptGfx           = pl_get_api_latest(ptApiRegistry, plGraphicsI);
-    gptDraw          = pl_get_api_latest(ptApiRegistry, plDrawI);
-    gptShader        = pl_get_api_latest(ptApiRegistry, plShaderI);
-    gptDrawBackend   = pl_get_api_latest(ptApiRegistry, plDrawBackendI);
-    gptUi            = pl_get_api_latest(ptApiRegistry, plUiI);
-    gptProfile       = pl_get_api_latest(ptApiRegistry, plProfileI);
-    gptStats         = pl_get_api_latest(ptApiRegistry, plStatsI);
-    gptExample       = pl_get_api_latest(ptApiRegistry, plExampleI);
-    gptTools         = pl_get_api_latest(ptApiRegistry, plToolsI);
-    gptImage         = pl_get_api_latest(ptApiRegistry, plImageI);
-    gptGpuAllocators = pl_get_api_latest(ptApiRegistry, plGPUAllocatorsI);
-    gptJob           = pl_get_api_latest(ptApiRegistry, plJobI);
-    gptThreads       = pl_get_api_latest(ptApiRegistry, plThreadsI);
-    gptAtomics       = pl_get_api_latest(ptApiRegistry, plAtomicsI);
-    gptRect          = pl_get_api_latest(ptApiRegistry, plRectPackI);
-    gptFile          = pl_get_api_latest(ptApiRegistry, plFileI);
-    gptNetwork       = pl_get_api_latest(ptApiRegistry, plNetworkI);
-    gptString        = pl_get_api_latest(ptApiRegistry, plStringInternI);
-    gptLibrary       = pl_get_api_latest(ptApiRegistry, plLibraryI);
-    gptLog           = pl_get_api_latest(ptApiRegistry, plLogI);
-    gptVirtualMemory = pl_get_api_latest(ptApiRegistry, plVirtualMemoryI);
-    gptConsole       = pl_get_api_latest(ptApiRegistry, plConsoleI);
-    gptScreenLog     = pl_get_api_latest(ptApiRegistry, plScreenLogI);
+    // load required apis
+    gptIO      = pl_get_api_latest(ptApiRegistry, plIOI);
+    gptWindows = pl_get_api_latest(ptApiRegistry, plWindowI);
+
+    // load required apis (these are provided though extensions)
+    gptDraw      = pl_get_api_latest(ptApiRegistry, plDrawI);
+    gptStarter   = pl_get_api_latest(ptApiRegistry, plStarterI);
+    gptUI        = pl_get_api_latest(ptApiRegistry, plUiI);
+    gptScreenLog = pl_get_api_latest(ptApiRegistry, plScreenLogI);
+    gptProfile   = pl_get_api_latest(ptApiRegistry, plProfileI);
+    gptStats     = pl_get_api_latest(ptApiRegistry, plStatsI);
+    gptMemory    = pl_get_api_latest(ptApiRegistry, plMemoryI);
+    gptLog       = pl_get_api_latest(ptApiRegistry, plLogI);
+    gptConsole   = pl_get_api_latest(ptApiRegistry, plConsoleI);
+
+    // out extension
+    gptExample = pl_get_api_latest(ptApiRegistry, plExampleI);
+
+    gptExample->print_to_console("Hello from example extension");
 
     // this path is taken only during first load, so we
     // allocate app memory here
     ptAppData = PL_ALLOC(sizeof(plAppData));
     memset(ptAppData, 0, sizeof(plAppData));
 
-    // add console variables
-    gptConsole->initialize((plConsoleSettings){.tFlags = PL_CONSOLE_FLAGS_POPUP});
+    // default values
+    ptAppData->bShowHelpWindow = true;
 
     // use window API to create a window
     plWindowDesc tWindowDesc = {
-        .pcTitle = "App Template",
+        .pcTitle = "Template App",
         .iXPos   = 200,
         .iYPos   = 200,
-        .uWidth  = 500,
-        .uHeight = 500,
+        .uWidth  = 600,
+        .uHeight = 600,
     };
     gptWindows->create_window(tWindowDesc, &ptAppData->ptWindow);
 
-    // setup graphics extension
-    pl__setup_graphics_extensions(ptAppData);
+    // initialize the starter API (handles alot of boilerplate)
+    plStarterInit tStarterInit = {
+        .tFlags   = PL_STARTER_FLAGS_ALL_EXTENSIONS,
+        .ptWindow = ptAppData->ptWindow
+    };
+    gptStarter->initialize(tStarterInit);
+    gptStarter->finalize();
 
-    // initialize APIs that require it
-    gptTools->initialize((plToolsInit){.ptDevice = ptAppData->ptDevice});
+    // add a log channel
+    ptAppData->uExampleLogChannel = gptLog->add_channel("Example 2", (plLogExtChannelInit){.tType = PL_LOG_CHANNEL_TYPE_BUFFER});
 
-    // retrieve some console variables
-    ptAppData->pbShowLogging              = (bool*)gptConsole->get_variable("t.LogTool", NULL, NULL);
-    ptAppData->pbShowStats                = (bool*)gptConsole->get_variable("t.StatTool", NULL, NULL);
-    ptAppData->pbShowProfiling            = (bool*)gptConsole->get_variable("t.ProfileTool", NULL, NULL);
-    ptAppData->pbShowMemoryAllocations    = (bool*)gptConsole->get_variable("t.MemoryAllocationTool", NULL, NULL);
-    ptAppData->pbShowDeviceMemoryAnalyzer = (bool*)gptConsole->get_variable("t.DeviceMemoryAnalyzerTool", NULL, NULL);
-
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~setup draw extensions~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    // initialize
-    gptDraw->initialize(NULL);
-    gptDrawBackend->initialize(ptAppData->ptDevice);
-
-    // create font atlas
-    plFontAtlas* ptAtlas = gptDraw->create_font_atlas();
-    gptDraw->set_font_atlas(ptAtlas);
-    ptAppData->ptDefaultFont = gptDraw->add_default_font(ptAtlas);
-    
-    // build font atlas
-    plCommandPool* ptCmdPool = ptAppData->atCmdPools[gptGfx->get_current_frame_index()];
-    plCommandBuffer* ptCmdBuffer = gptGfx->request_command_buffer(ptCmdPool);
-    gptDrawBackend->build_font_atlas(ptCmdBuffer, ptAtlas);
-    gptGfx->return_command_buffer(ptCmdBuffer);
-    
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~message extension~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    
-    gptScreenLog->initialize((plScreenLogSettings){.ptFont = ptAppData->ptDefaultFont});
-
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ui extension~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    gptUi->initialize();
-    gptUi->set_default_font(ptAppData->ptDefaultFont);
-
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~app stuff~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    // create drawlist and some layers to draw to
-    ptAppData->ptDrawlist = gptDraw->request_2d_drawlist();
-    ptAppData->ptFGLayer = gptDraw->request_2d_layer(ptAppData->ptDrawlist);
-    ptAppData->ptBGLayer = gptDraw->request_2d_layer(ptAppData->ptDrawlist);
-
-    // demonstrate example extension
-    gptExample->print_to_console("From example extension!");
+    // add a console variable
+    gptConsole->add_toggle_variable("a.HelpWindow", &ptAppData->bShowHelpWindow, "toggle help window", PL_CONSOLE_VARIABLE_FLAGS_NONE);
 
     // return app memory
     return ptAppData;
@@ -305,22 +231,7 @@ pl_app_load(plApiRegistryI* ptApiRegistry, plAppData* ptAppData)
 PL_EXPORT void
 pl_app_shutdown(plAppData* ptAppData)
 {
-    // ensure GPU is finished before cleanup
-    gptGfx->flush_device(ptAppData->ptDevice);
-    for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++)
-    {
-        gptGfx->cleanup_command_pool(ptAppData->atCmdPools[i]);
-        gptGfx->cleanup_semaphore(ptAppData->aptSemaphores[i]);
-    }
-    gptDrawBackend->cleanup_font_atlas(NULL);
-    gptUi->cleanup();
-    gptDrawBackend->cleanup();
-    gptScreenLog->cleanup();
-    gptConsole->cleanup();
-    gptGfx->cleanup_swapchain(ptAppData->ptSwapchain);
-    gptGfx->cleanup_surface(ptAppData->ptSurface);
-    gptGfx->cleanup_device(ptAppData->ptDevice);
-    gptGfx->cleanup();
+    gptStarter->cleanup();
     gptWindows->destroy_window(ptAppData->ptWindow);
     PL_FREE(ptAppData);
 }
@@ -332,7 +243,7 @@ pl_app_shutdown(plAppData* ptAppData)
 PL_EXPORT void
 pl_app_resize(plAppData* ptAppData)
 {
-    pl__resize_graphics_extensions(ptAppData);
+    gptStarter->resize();
 }
 
 //-----------------------------------------------------------------------------
@@ -342,284 +253,88 @@ pl_app_resize(plAppData* ptAppData)
 PL_EXPORT void
 pl_app_update(plAppData* ptAppData)
 {
-    gptProfile->begin_frame();
-    pl_begin_cpu_sample(gptProfile, 0, __FUNCTION__);
-
-    // for convience
-    plIO* ptIO = gptIO->get_io();
-
-    // new frame stuff
-    gptIO->new_frame();
-    gptDrawBackend->new_frame();
-    gptUi->new_frame();
-    gptStats->new_frame();
-    gptGfx->begin_frame(ptAppData->ptDevice);
-    plCommandPool* ptCmdPool = ptAppData->atCmdPools[gptGfx->get_current_frame_index()];
-    gptGfx->reset_command_pool(ptCmdPool, 0);
-
-    // update statistics
-    static double* pdFrameTimeCounter = NULL;
-    if(!pdFrameTimeCounter)
-        pdFrameTimeCounter = gptStats->get_counter("frametime (ms)");
-    *pdFrameTimeCounter = (double)ptIO->fDeltaTime * 1000.0;
-
-    // acquire swapchain image
-    if(!gptGfx->acquire_swapchain_image(ptAppData->ptSwapchain))
-    {
-        pl_app_resize(ptAppData);
-        pl_end_cpu_sample(gptProfile, 0);
-        gptProfile->end_frame();
+    // this needs to be the first call when using the starter
+    // extension. You must return if it returns false (usually a swapchain recreation).
+    if(!gptStarter->begin_frame())
         return;
-    }
 
-    // just some drawing
-    gptDraw->add_circle(ptAppData->ptFGLayer, (plVec2){100.0f, 100.0f}, 50.0f, 12, (plDrawLineOptions){.fThickness = 2.0f, .uColor = PL_COLOR_32_RGBA(1.0f, 0.0f, 1.0f, 1.0f)});
-
-    if(gptIO->is_key_pressed(PL_KEY_F1, false))
-        gptConsole->open();
-
-    gptConsole->update();
-
-    if(gptUi->begin_window("Pilot Light", NULL, false))
-    {
-
-        const float pfRatios[] = {1.0f};
-        gptUi->layout_row(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, 0.0f, 1, pfRatios);
-        if(gptUi->begin_collapsing_header("Information", 0))
-        {
-            
-            gptUi->text("Pilot Light %s", PILOT_LIGHT_VERSION_STRING);
-            gptUi->end_collapsing_header();
-        }
-        if(gptUi->begin_collapsing_header("Tools", 0))
-        {
-            gptUi->checkbox("Device Memory Analyzer", ptAppData->pbShowDeviceMemoryAnalyzer);
-            gptUi->checkbox("Memory Allocations", ptAppData->pbShowMemoryAllocations);
-            gptUi->checkbox("Profiling", ptAppData->pbShowProfiling);
-            gptUi->checkbox("Statistics", ptAppData->pbShowStats);
-            gptUi->checkbox("Logging", ptAppData->pbShowLogging);
-            gptUi->end_collapsing_header();
-        }
-        if(gptUi->begin_collapsing_header("User Interface", 0))
-        {
-            gptUi->checkbox("UI Debug", &ptAppData->bShowUiDebug);
-            gptUi->checkbox("UI Style", &ptAppData->bShowUiStyle);
-            gptUi->end_collapsing_header();
-        }
-        gptUi->end_window();
-    }
-        
-    if(ptAppData->bShowUiStyle)
-        gptUi->show_style_editor_window(&ptAppData->bShowUiStyle);
-
-    if(ptAppData->bShowUiDebug)
-        gptUi->show_debug_window(&ptAppData->bShowUiDebug);
-
-    gptTools->update();
-
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~graphics work~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    const uint32_t uCurrentFrameIndex = gptGfx->get_current_frame_index();
-
-    plCommandBuffer* ptCommandBuffer = gptGfx->request_command_buffer(ptCmdPool);
-
-    const plBeginCommandInfo tBeginInfo = {
-        .uWaitSemaphoreCount   = 1,
-        .atWaitSempahores      = {ptAppData->aptSemaphores[uCurrentFrameIndex]},
-        .auWaitSemaphoreValues = {ptAppData->aulNextTimelineValue[uCurrentFrameIndex]},
-    };
-    gptGfx->begin_command_recording(ptCommandBuffer, &tBeginInfo);
-
-    // begin main renderpass (directly to swapchain)
-    plRenderEncoder* ptEncoder = gptGfx->begin_render_pass(ptCommandBuffer, ptAppData->tMainRenderPass, NULL);
-
-    // submit our layers & drawlist
-    gptDraw->submit_2d_layer(ptAppData->ptBGLayer);
-    gptDraw->submit_2d_layer(ptAppData->ptFGLayer);
-    gptDrawBackend->submit_2d_drawlist(ptAppData->ptDrawlist, ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stats API~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     
-    // submits UI layers
-    gptUi->end_frame();
+    // rather than have to lookup the counter every frame, its best to "store" it
+    // like this. To update it, just deference it and set the value.
+    static double* pdExample2Counter = NULL;
+    if(!pdExample2Counter)
+        pdExample2Counter = gptStats->get_counter("example 2 counter");
 
-    // submit UI drawlists
-    gptDrawBackend->submit_2d_drawlist(gptUi->get_draw_list(), ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
-    gptDrawBackend->submit_2d_drawlist(gptUi->get_debug_draw_list(), ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~drawing & profile API~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    plDrawList2D* ptMessageDrawlist = gptScreenLog->get_drawlist(ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y);
-    gptDrawBackend->submit_2d_drawlist(ptMessageDrawlist, ptEncoder, ptIO->tMainViewportSize.x, ptIO->tMainViewportSize.y, gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount);
+    gptProfile->begin_sample(0, "example drawing");
+    
+    plDrawLayer2D* ptFGLayer = gptStarter->get_foreground_layer();
+    gptDraw->add_line(ptFGLayer,
+        (plVec2){0.0f, 0.0f},
+        (plVec2){500.0f, 500.0f}, (plDrawLineOptions){ .fThickness = 1.0f, .uColor = PL_COLOR_32_MAGENTA});
 
+    plDrawLayer2D* ptBGLayer = gptStarter->get_background_layer();
+    gptDraw->add_triangle_filled(ptBGLayer,
+        (plVec2){50.0f, 100.0f},
+        (plVec2){200.0f},
+        (plVec2){100.0f, 200.0f}, (plDrawSolidOptions){.uColor = PL_COLOR_32_RGBA(0.0f, 0.5f, 1.0f, 0.5f)});
 
-    // end render pass
-    gptGfx->end_render_pass(ptEncoder);
+    gptProfile->end_sample(0);
 
-    // end recording
-    gptGfx->end_command_recording(ptCommandBuffer);
+    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~UI & Screen Log API~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    //~~~~~~~~~~~~~~~~~~~~~~~~~~submit work to GPU & present~~~~~~~~~~~~~~~~~~~~~~~
-
-    const plSubmitInfo tSubmitInfo = {
-        .uSignalSemaphoreCount   = 1,
-        .atSignalSempahores      = {ptAppData->aptSemaphores[uCurrentFrameIndex]},
-        .auSignalSemaphoreValues = {++ptAppData->aulNextTimelineValue[uCurrentFrameIndex]},
-    };
-
-    if(!gptGfx->present(ptCommandBuffer, &tSubmitInfo, &ptAppData->ptSwapchain, 1))
-        pl_app_resize(ptAppData);
-
-    gptGfx->return_command_buffer(ptCommandBuffer);
-
-    pl_end_cpu_sample(gptProfile, 0);
-    gptProfile->end_frame();
-}
-
-//-----------------------------------------------------------------------------
-// [SECTION] helper functions implementations
-//-----------------------------------------------------------------------------
-
-void
-pl__setup_graphics_extensions(plAppData* ptAppData)
-{
-    // initialize shader extension (shader compiler)
-    static const plShaderOptions tDefaultShaderOptions = {
-        .apcIncludeDirectories = {
-            "../shaders/"
-        },
-        .apcDirectories = {
-            "../shaders/"
-        },
-        .tFlags = PL_SHADER_FLAGS_AUTO_OUTPUT
-    };
-    gptShader->initialize(&tDefaultShaderOptions);
-
-    // initialize graphics system
-    const plGraphicsInit tGraphicsInit = {
-        .tFlags = PL_GRAPHICS_INIT_FLAGS_VALIDATION_ENABLED | PL_GRAPHICS_INIT_FLAGS_SWAPCHAIN_ENABLED 
-    };
-    gptGfx->initialize(&tGraphicsInit);
-    ptAppData->ptSurface = gptGfx->create_surface(ptAppData->ptWindow);
-
-    // find suitable device
-    uint32_t uDeviceCount = 16;
-    plDeviceInfo atDeviceInfos[16] = {0};
-    gptGfx->enumerate_devices(atDeviceInfos, &uDeviceCount);
-
-    // we will prefer discrete, then integrated
-    int iBestDvcIdx = 0;
-    int iDiscreteGPUIdx   = -1;
-    int iIntegratedGPUIdx = -1;
-    for(uint32_t i = 0; i < uDeviceCount; i++)
+    // creating a window
+    if(ptAppData->bShowHelpWindow)
     {
-        
-        if(atDeviceInfos[i].tType == PL_DEVICE_TYPE_DISCRETE)
-            iDiscreteGPUIdx = i;
-        else if(atDeviceInfos[i].tType == PL_DEVICE_TYPE_INTEGRATED)
-            iIntegratedGPUIdx = i;
-    }
-
-    if(iDiscreteGPUIdx > -1)
-        iBestDvcIdx = iDiscreteGPUIdx;
-    else if(iIntegratedGPUIdx > -1)
-        iBestDvcIdx = iIntegratedGPUIdx;
-
-    // create device
-    const plDeviceInit tDeviceInit = {
-        .uDeviceIdx = iBestDvcIdx,
-        .ptSurface = ptAppData->ptSurface
-    };
-    ptAppData->ptDevice = gptGfx->create_device(&tDeviceInit);
-
-    // create command pools
-    for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++)
-        ptAppData->atCmdPools[i] = gptGfx->create_command_pool(ptAppData->ptDevice, NULL);
-
-    // create swapchain
-    plSwapchainInit tSwapInit = {
-        .tSampleCount = PL_SAMPLE_COUNT_1
-    };
-    ptAppData->ptSwapchain = gptGfx->create_swapchain(ptAppData->ptDevice, ptAppData->ptSurface, &tSwapInit);
-
-    uint32_t uImageCount = 0;
-    plTextureHandle* atSwapchainImages = gptGfx->get_swapchain_images(ptAppData->ptSwapchain, &uImageCount);
-
-    // create main render pass layout
-    const plRenderPassLayoutDesc tMainRenderPassLayoutDesc = {
-        .atRenderTargets = {
-            { .tFormat = gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tFormat }, // swapchain
-        },
-        .atSubpasses = {
-            {
-                .uRenderTargetCount = 1,
-                .auRenderTargets = {0}
-            }
-        },
-        .atSubpassDependencies = {
-            {
-                .uSourceSubpass = UINT32_MAX,
-                .uDestinationSubpass = 0,
-                .tSourceStageMask = PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS | PL_PIPELINE_STAGE_COMPUTE_SHADER,
-                .tDestinationStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS,
-                .tSourceAccessMask = PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
-                .tDestinationAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
-            },
-            {
-                .uSourceSubpass = 0,
-                .uDestinationSubpass = UINT32_MAX,
-                .tSourceStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS,
-                .tDestinationStageMask = PL_PIPELINE_STAGE_FRAGMENT_SHADER | PL_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT | PL_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS | PL_PIPELINE_STAGE_LATE_FRAGMENT_TESTS | PL_PIPELINE_STAGE_COMPUTE_SHADER,
-                .tSourceAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
-                .tDestinationAccessMask = PL_ACCESS_SHADER_READ | PL_ACCESS_COLOR_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE | PL_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ,
-            },
+        if(gptUI->begin_window("Help", NULL, PL_UI_WINDOW_FLAGS_AUTO_SIZE | PL_UI_WINDOW_FLAGS_NO_COLLAPSE))
+        {
+            gptUI->layout_static(0.0f, 500.0f, 1);
+            gptUI->text("Press F1 to bring up console.");
+            gptUI->text("Look for t.StatsTool (we added a stat)");
+            gptUI->text("Look for t.LogTool (we added a log channel)");
+            gptUI->text("Look for t.ProfileTool");
+            gptUI->text("Look for t.MemoryAllocationTool and look for example 2!");
+            gptUI->text("Look for a.HelpWindow (console variable we added)");
+            gptUI->end_window();
         }
-    };
-    ptAppData->tMainRenderPassLayout = gptGfx->create_render_pass_layout(ptAppData->ptDevice, &tMainRenderPassLayoutDesc);
-
-    // create main render pass
-    const plRenderPassDesc tMainRenderPassDesc = {
-        .tLayout = ptAppData->tMainRenderPassLayout,
-        .atColorTargets = {
-            {
-                .tLoadOp       = PL_LOAD_OP_CLEAR,
-                .tStoreOp      = PL_STORE_OP_STORE,
-                .tCurrentUsage = PL_TEXTURE_USAGE_UNSPECIFIED,
-                .tNextUsage    = PL_TEXTURE_USAGE_PRESENT,
-                .tClearColor   = {0.0f, 0.0f, 0.0f, 1.0f}
-            }
-        },
-        .tDimensions = {(float)gptGfx->get_swapchain_info(ptAppData->ptSwapchain).uWidth, (float)gptGfx->get_swapchain_info(ptAppData->ptSwapchain).uHeight},
-        .ptSwapchain = ptAppData->ptSwapchain
-    };
-
-    plRenderPassAttachments atMainAttachmentSets[16] = {0};
-    for(uint32_t i = 0; i < uImageCount; i++)
-    {
-        atMainAttachmentSets[i].atViewAttachments[0] = atSwapchainImages[i];
     }
-    ptAppData->tMainRenderPass = gptGfx->create_render_pass(ptAppData->ptDevice, &tMainRenderPassDesc, atMainAttachmentSets);
 
-    // create timeline semaphores to syncronize GPU work submission
-    for(uint32_t i = 0; i < gptGfx->get_frames_in_flight(); i++)
-        ptAppData->aptSemaphores[i] = gptGfx->create_semaphore(ptAppData->ptDevice, false);
-}
-
-void
-pl__resize_graphics_extensions(plAppData* ptAppData)
-{
-    plIO* ptIO = gptIO->get_io();
-    plSwapchainInit tDesc = {
-        .bVSync  = true,
-        .uWidth  = (uint32_t)ptIO->tMainViewportSize.x,
-        .uHeight = (uint32_t)ptIO->tMainViewportSize.y,
-        .tSampleCount = gptGfx->get_swapchain_info(ptAppData->ptSwapchain).tSampleCount,
-    };
-    gptGfx->recreate_swapchain(ptAppData->ptSwapchain, &tDesc);
-
-    uint32_t uImageCount = 0;
-    plTextureHandle* atSwapchainImages = gptGfx->get_swapchain_images(ptAppData->ptSwapchain, &uImageCount);
-
-    plRenderPassAttachments atMainAttachmentSets[16] = {0};
-    for(uint32_t i = 0; i < uImageCount; i++)
+    // creating another window
+    if(gptUI->begin_window("Pilot Light", NULL, PL_UI_WINDOW_FLAGS_NONE))
     {
-        atMainAttachmentSets[i].atViewAttachments[0] = atSwapchainImages[i];
+        gptUI->text("Pilot Light %s", PILOT_LIGHT_VERSION_STRING);
+
+        if(gptUI->button("Log"))
+        {
+            gptLog->trace(ptAppData->uExampleLogChannel, "Log");
+            gptLog->debug(ptAppData->uExampleLogChannel, "Log");
+            gptLog->info(ptAppData->uExampleLogChannel, "Log");
+            gptLog->warn(ptAppData->uExampleLogChannel, "Log");
+            gptLog->error(ptAppData->uExampleLogChannel, "Log");
+            gptLog->fatal(ptAppData->uExampleLogChannel, "Log");
+        }
+
+        static int iCounter = 0;
+        gptUI->slider_int("Stat Counter Example", &iCounter, -10, 10, 0);
+        *pdExample2Counter = iCounter; // setting our stat variable
+
+        gptUI->layout_row_begin(PL_UI_LAYOUT_ROW_TYPE_DYNAMIC, 0.0f, 2); // got to pl_ui_ext.h to see layout systems
+        
+        gptUI->layout_row_push(0.3f);
+        if(gptUI->button("Log To Screen"))
+            gptScreenLog->add_message(5.0, "Cool Message!");
+
+        gptUI->layout_row_push(0.3f);
+        if(gptUI->button("Big Log To Screen"))
+            gptScreenLog->add_message_ex(0, 5, PL_COLOR_32_GREEN, 3.0f, "%s", "Bigger & Greener!");
+
+        gptUI->layout_row_end();
+
+        gptUI->end_window();
     }
-    gptGfx->update_render_pass_attachments(ptAppData->ptDevice, ptAppData->tMainRenderPass, gptIO->get_io()->tMainViewportSize, atMainAttachmentSets);
+
+    // must be the last function called when using the starter extension
+    gptStarter->end_frame(); 
 }