InterfaceAPI - My First Serious Project

Hello there. I briefly mentioned this on Discord some while ago but would also like to post here. I would like to introduce my (albeit AI-assisted) InterfaceAPI project here.

It is a user interface framework (in case you didn’t guess by the name) that contains lots of different features that I myself intend to use for my own projects, mostly data-heavy or business-oriented software since that’s my domain.

A small number of features (and growing):

  • Over 40+ widgets including basic controls, list views, tree views, node panels, timelines, barcodes, video player (WIP), and more.
  • Different container types for different layout styles: dock engine, flow engine (flex-style), grid engine.
  • Built-in IME support, bidirectional text rendering, right-to-left, etc.
  • Custom Object design in the form of command lists
  • SDF-shader primitive drawing by default
  • Font families with fallback chains for automatic mixed language support
  • And more…

This MIT licensed codebase can be found on Codeberg with tutorials under the docs directory and a working demo (see screenshots below) in the test directory.

Check out the following sample code as an introduction to the kind of code you would be introduced to if you decided to pick this up:

package main

import "base:runtime"
import interface "shared:InterfaceAPI"

main :: proc() {
    options := interface.create_default_launch_options("Test App", 1600, 900)
    app := interface.create_app(options)

    interface.app_init_window(app)
    defer interface.app_close_window(app)

    app->set_font_family("Noto Sans", { "NotoSansRegular.ttf" }, 24, 400)
    app->set_font_family("Noto Mono", { "NotoSansMono.ttf" }, 24, 400)

    app.font = "Noto Sans"
    app.mono_font = "Noto Mono"
    app.font_size = 24
    app.font_weight = 400

    dark_theme := interface.create_default_dark_theme()
    interface.register_theme("Dark Theme", .Dark, &dark_theme)

    light_theme := interface.create_default_theme()
    interface.register_theme("Light Theme", .Light, &light_theme)

    interface.app_init_framework(app)
    defer interface.app_dispose_framework(app)

    root := interface.create_panel(&app.base)
    root.dock = .Fill

    menu_bar := interface.create_menu_bar(root)
    menu_bar.dock = .Top
    
    tools_menu := interface.create_menu("Tools", menu_bar)
    light_theme_option := interface.create_option("Light Theme", nil, tools_menu)
    dark_theme_option := interface.create_option("Dark Theme", nil, tools_menu)

    for app.__running {
        interface.app_update(app)

        if light_theme_option.is_clicked {
            app->set_theme(light_theme)
        }
        if dark_theme_option.is_clicked {
            app->set_theme(dark_theme)
        }

        interface.app_render(app)
    }
}

For a full introduction, see my itch.io page.

Screenshots


I will now explain my use of AI and why I decided to use it, as I am well aware of the scepticism and controversy around using it.

TL;DR I suck at programming anything useful. I’m only really good at UI design and that’s about it.

Most people get poor experiences with AI and get sceptical when software that “appears” good quality but doesn’t live up to expectations. Trust me, I feel you. I wouldn’t have chosen to use AI if I had the knowledge and the experience I needed to build something like this. However, I don’t have the years nor the knowledge required to build something as large as this, so I have used AI extensively in the building of this project.

Much of the AI results have been relatively poor in the beginning, but various refactors have made this project something I would personally now use in production and the best way to test that is to make my own software with it.

Some AI stories while designing and generating this project:

  • In the beginning, all widgets had a callback based event handling system via the -> method-like signature. This got replaced with boolean flags when I decided I didn’t like the callback approach.
  • FFMPEG was originally put in place for video rendering, but I asked for an alternative and now the following is being implemented (ongoing); OpenH264, dav1d, custom containers, minimp3 and a WIP AAC-LC decoder
  • There used to be an XML engine - that was scrapped in favour of just having a better way of constructing objects and applying them to parent objects.
  • There used to be Lua scripting for the XML engine - also removed as it was no longer needed.
  • CodeField and TextField has been reiterated multiple times. As you can imagine, AI has a hard time optimising performance for text editing, but with my fairly good understanding of how these should be structured, I have been able to iterate up to a well optimised caching system (textures + rendered line caching + layout per line).

There are possibly other stories to share, but most people probably don’t care.

Questions on my use of AI

Some people will invariably argue against my use of AI for multiple reasons and I suspect the many questions I expect will be one or more of the following.

Doesn’t AI defeat the point of learning how to solve these problems you want to learn?
Yes, and I’m not interested in learning the complicated stuff. UI isn’t exactly the most difficult thing to understand. Some things, like text rendering, is indeed very difficult to master, if not one of the most difficult things to master. There’s a reason I ship InterfaceAPI with FreeType and Harfbuzz, and various other third party libraries. I’m not interested in learning solutions that have been mostly solved by other people. Some people are okay with that, and that’s fine, but for my personal learning experience, the deep engineering problems are not something I’m capable of solving.

Why bother using AI at all if you know what the reception will be?
Because I don’t care. I realise this is ironic since I’m going on a tangent, so I must care, right? Well, yes, I care about getting the facts straight with people and I want to be honest and upfront about my use of AI, I think that’s an important policy and one that results in better trust compared with the companies that let their users find out without disclosing it.

What do you enjoy about programming if you’re going to let AI do it all for you anyway?
Here’s where the answer is not an easy answer. I enjoy programming. I’ve been at it for 20 years self-taught on and off. So, what’s the problem? The problem is my ability to focus on one project at a time. I have honestly been too ambitious for various reasons, thinking about the company I wanted to own and the software I wanted to make. I wanted it to be my livelihood. The problem is that over time my frustrations increased as I couldn’t settle for a programming language, environment or toolkit I enjoyed using. Odin + Raylib struck the chord, but too little too late. It’s only been two years since picking up Odin and it’s not easy to say to myself: “You can build anything” while at the same time we’re edging closer, politically and economically, to an “end of the world scenario,” where all of this will just end up being waste of time. I try to focus on what I want to do as much as I can, but what can you do when life obligations catch up with you and the time you have spare doesn’t give you the time you want to build something you really want to make.

But whatever. I rant too much. Thank you for reading up to this point if you made it this far.

3 Likes

Hey all. Quick update for you all.

I have managed to release version 1.0 - a “complete” version of almost all the widgets that had been planned for this release plus a few extra features I didn’t plan for.

Full feature list stands as follows:

  • 47 widgets in total with active demos in the new interactive demo release found here.
  • 25 systems in total, which includes:
    • Animation Sequences
    • Canvas for video game containers
    • CLI Hot Reload shell (built from the shell directory and reloads DLL files)
    • Custom Objects through custom draw lists and event triggers
    • Data Stores for schemas, data validation, flat databases and JSON serialization
    • Basic Download system with dependency on curl (runs as a separate process so no physical libraries required)
    • Focus & HotKey system - tab navigation with focus rings applied, deactivated on mouse interaction; hotkey system for application-level global activity, widget-level key interception for focused key consumption
    • As mentioned above, has a built-in IME system for many languages, a language indicator widget for application assignment and Ctrl+Space for switching between languages
    • Form Generator widget (layout and widget agnostic), combined with Data Stores can be used for editing singular records.
    • Generic History for custom undo/redo stacks.
    • Explanations on how the Layout & Docking systems work
    • MarkdownDocument and RichText widgets for complex static widget content. Supports SVG icons, tables, headers, lists and links. Tables are fixed width using the available width of the container (no dynamic cell resizing yet).
    • Notifications useful for creating temporary messages that float in a corner for user attention.
    • Basic PDF Writing system
    • Custom Popups for whichever scenario you need.
    • QuickJS integration (used when -define:ENABLE_JS=true is used on the command line when building your project)
    • Resource Management which uses a handle-based identifier system, allows compressing resources and making header files.
    • Scene Management for when you want app-level scene organisation without needing to manage it yourself (convenience for update callbacks without needing to write and organise the widget life-cycle yourself)
    • Spritesheets included if you want complex Backgrounds per widget or just static images (useful for Game UI).
    • SVG Icons, of course.
    • Explanations on Text Storage and how each of the three components interact
    • Explanation on Theming and widget customisation
    • Transformer, Selector and Design-Mode systems for when you want to author scenes at a high-level.
    • And finally, an explanation of how to write your own XML file for theming.

Video support with permissive library options I have deferred to a 1.1 release. The demo application was built with -define:ENABLE_VIDEO=true, so ffmpeg is required to be installed. The Windows demo comes with the DLL files supplied. On Linux, you may need to install ffmpeg system-wide (version to download is 7.0.3).

There is now also a C FFI layer with working bindings in Haxe (to be linked sometime later when I’m confident there’s no edge cases to worry about).

1 Like