How does "Hello triangle" look in your abstraction layer?

Here is mine (~100 LOC)

link: lum-al

Renderer render = {};
int main(){
    Settings settings = {};
        settings.vsync = false;
        settings.fullscreen = false;
        settings.debug = false; //Validation Layers
        settings.timestampCount = 128;
        settings.profile = false; //timestamps
        settings.fif = 2;
    render.init(settings);

    RasterPipe simple_raster_pipe = {};
    RasterPipe simple_posteffect_pipe = {};

    ring<Image> simple_inter_image; 

    render.createImageStorages(&simple_inter_image,
        VK_IMAGE_TYPE_2D,
        VK_FORMAT_R8G8B8A8_UNORM,
        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
        VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
        VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
        VK_IMAGE_ASPECT_COLOR_BIT,
    {render.swapChainExtent.width, render.swapChainExtent.height, 1});
    for(auto img : simple_inter_image){
        render.transitionImageLayoutSingletime(&img, VK_IMAGE_LAYOUT_GENERAL);
    }

    render.descriptorBuilder
        .setLayout(&simple_raster_pipe.setLayout)
        .setDescriptorSets(&simple_raster_pipe.sets)
        .defer();
    render.descriptorBuilder
        .setLayout(&simple_posteffect_pipe.setLayout)
        .setDescriptorSets(&simple_posteffect_pipe.sets)
        .setDescriptions({
            {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, RD_FIRST, {/*empty*/}, {simple_inter_image}, NO_SAMPLER, VK_IMAGE_LAYOUT_GENERAL, VK_SHADER_STAGE_FRAGMENT_BIT}
        })
        .defer();
    render.flushDescriptorSetup();

    RenderPass simple_rpass = {};
    render.renderPassBuilder.setAttachments({
            {&simple_inter_image,   DontCare, DontCare, DontCare, DontCare, {}, VK_IMAGE_LAYOUT_GENERAL},
            {&render.swapchainImages, DontCare, Store,    DontCare, DontCare, {}, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR},
        }).setSubpasses({
            {{&simple_raster_pipe},     {},                     {&simple_inter_image},   {}},
            {{&simple_posteffect_pipe}, {&simple_inter_image}, {&render.swapchainImages}, {}}
        }).build(&simple_rpass);

    render.pipeBuilder.setStages({
            {"examples/vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
            {"examples/frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
        }).setExtent(render.swapChainExtent).setBlends({NO_BLEND})
        .buildRaster(&simple_raster_pipe);
    render.pipeBuilder.setStages({
            {"examples/vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
            {"examples/posteffect.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
        }).setExtent(render.swapChainExtent).setBlends({NO_BLEND})
        .buildRaster(&simple_posteffect_pipe);

    ring<VkCommandBuffer> mainCommandBuffers;
    ring<VkCommandBuffer> extraCommandBuffers; //runtime copies. Also does first frame resources

    //you typically want to have FIF'count command buffers in their ring
    //but if you only need like 1 "baked" command buffer, just use 1
    render.createCommandBuffers ( &mainCommandBuffers, render.settings.fif);
    render.createCommandBuffers (&extraCommandBuffers, render.settings.fif);

    //you have to set this if you want to use builtin profiler
    render.mainCommandBuffers = &mainCommandBuffers;

    while(!glfwWindowShouldClose(render.window.pointer) && (glfwGetKey(render.window.pointer, GLFW_KEY_ESCAPE) != GLFW_PRESS)){
        glfwPollEvents();
        render.start_frame({mainCommandBuffers.current()});                
            render.cmdBeginRenderPass(mainCommandBuffers.current(), &simple_rpass);
                render.cmdBindPipe(mainCommandBuffers.current(), simple_raster_pipe);
                   render.cmdDraw(mainCommandBuffers.current(), 3, 1, 0, 0);
            render.cmdNextSubpass(mainCommandBuffers.current(), &simple_rpass);
                render.cmdBindPipe(mainCommandBuffers.current(), simple_posteffect_pipe);
                   render.cmdDraw(mainCommandBuffers.current(), 3, 1, 0, 0);
            render.cmdEndRenderPass(mainCommandBuffers.current(), &simple_rpass);
        render.end_frame({mainCommandBuffers.current()});
        //you are the one responsible for this, because using "previous" command buffer is quite common
        mainCommandBuffers.move();
    }
    render.deviceWaitIdle();
    render.destroyRenderPass(&simple_rpass);
    render.destroyRasterPipeline(&simple_raster_pipe);
    render.destroyRasterPipeline(&simple_posteffect_pipe);
    render.deleteImages(&simple_inter_image);
    render.cleanup();
}