Headless kiosk application
Intro
Kirby is very versatile and can be used for things that are a little out of the ordinary. Let's assume that you need to create a Kiosk application for use in a showroom or museum setting. The app should run on Desktop computers as well as Android Tablets and iPads.
The space the Kiosk will be used in has very patchy or no internet connection, so the application needs to be entirely self-contained, and make no external internet calls at all.
This recipe will cover using Kirby to handle the content and imagery, and generating a static version via 11ty. From there, we can use Electron Builder to generate the desktop versions, and Capacitor to create the mobile device apps.
Preparation
If you have not used Kirby headless before, please take a look at the Going Headless cookbook guide before continuing, as this will explain the basic principles.
To keep this guide simple, we will be using data from the Kirby KQL Sandbox which does not need any authentication. In reality, you will likely be using a local install of Kirby as a source for the data.
It would be safe to disable authentication if that is the case. If you are using a publicly accessible headless instance of Kirby, using authentication is strongly advised. Making use of DotENV is also recommended.
First steps
To begin with, we will need to set up 11ty in accordance with the documentation. You can also use the Kirby Eleventykit as a basis for this, which already has a simple connection setup. This guide assumes a basic understanding of 11ty.
With that out the way, we can make a start with getting our data from Kirby and into 11ty.
We will make a small site the pulls in the Photography section of the Starter Kit, along with the text and images to make a basic information site.
In the _data
folder, create a photography.js
file with the following code in it:
This will enable us to generate a list of the photography pages on the main index.html
file of the project. You can do this by editing the index.njk
file to contain the following:
This uses the data pulled in from Kirby to generate a list of the available Photography articles. At this point (and after a little CSS!) we should have something like this in the browser:
So far, so good. The next step is to create the individual post pages. We can do this with a little more Nunjucks in a photography subfolder. This will give us our subpages based on the data coming in from Kirby.
So there we have the basics of our little site. We have made an index page, allowing us to click through to the desired article, and we have individual pages for each item. 11ty automatically generated all this from the JSON data provided to us by Kirby.
There is just one small problem. We need this app to run offline, without making any external calls. If you take a close look at the URLs for the images, you can see they are in fact being pulled in remotely:
We need to convert these into static assets within our projects file system, so that we can reference them from our code base rather than via a URL. Let's fix that!
Creating static image assets
Setting up a custom 11ty shortcode will help us here by leaning on the eleventy-image plugin which has the ability to cache files locally. Install it via Yarn:
Next, we need to update our .eleventy.js
file too with a shortcode that will store the images locally and generate WebP & AVIF versions for us at the same time.
Moving back to the Nunjuck's template for the index page, we adjust the call on the image shortcode:
The short code expects a src
for the image, in this case we are feeding it a poster thumbnail image via item.poster.url
. Next, we can set an alt
text value. Thirdly, we can set a folder name to store the images in, using /assets/images
as a base.
In this case, the images will be generated in an /assets/images/home
folder. Finally, we can pass a set of sizes to trigger the source set images.
The loop should now look like this:
If we build the project now, and take a look at the generated HTML, we can see that we do indeed now have local images with absolute URLS:
At this stage, we currently have a site running statically, that could be deployed to even very basic web hosting. Now we can tackle the next stage - let't turn this into a desktop application!
Desktop application
Preparation
Now for the exciting stuff. We need to do a little prep before we can generate our app, since we need to create some icons, and a background for the Apple DMG file.
We need a little CLI tool to help us out here. Install it globally:
The next step is to create a 1024 x 1024 image to use as an icon. Store it in a folder called icons/src
in the root of your project. Create a folder icons/output
to store the generated icons.
We can run this through electron-icon-builder
to generate all the different sized icons and formats. Adjust the input path to match your absolute folder location on your harddisk.
For the DMG app backgrounds, we need to create two images, one at 540 x 380 with a name of background.tiff
and another at 1080 x 760 called background@x2.tiff
. The latter will be used on Retina macs, and the file names are important.
Remember to leave room at the bottom of the image, as this is where the install icons will sit. Store these images in the output folder with all the icons created in the previous step.
Configuration
Let's move on to configuring the build for the app, now that we have all of our assets ready. Install electron
, electron-builder
and electron-serve
via yarn.
In the root of your project, create a file called main.js
with the following code inside:
This is a simple configuration for electron
. The details of this code are outside the scope of this article, but can be referred to in the Electron documentation if you wish to learn more.
There are two parts of this you may wish to alter. Most browsers prevent the auto-playing of video unless it is muted. The following line removes this restriction, allowing you to autoplay video with sound on without requiring user input.
The second part that may be altered is the mainWindow
.
It is here that you can set the initial width and height of the application window, the favicon, as well as whether to show things like the address bar and status bar.
Finally, add the following to your package.json
file:
These settings control the Electron Builder build process to alter the output for various platforms. This is documented in the Electron Builder docs if you wish to alter the values.
First build
It's finally moment of truth time! Let's add a couple of NPM scripts to package.json
so that we can easily kick off the build:
Running yarn desktop
will generate a desktop app depending on the platform you are running the project on. If you are running on Windows, you will end up with a Windows installer in the dist
folder. If you are on Apple Silicon Mac you will end up with a DMG that will only run on another Apple Silicon Mac. Running yarn macuniversal
will generate an app that will work on both Apple Silicon and Intel based Macs.
Run either yarn desktop
or yarn macuniversal
depending on the platform you are running on. If all goes well, you will find an executable application inside the dist
folder. In my case, I am running on Apple Silicon and successfully get a DMG file allowing me to install the app.
After installing the app, we can finally see the result of all our hard work!
Mobile applications
So that's the desktop application finished up. Let's take things further now, and generate mobile applications for iOS and Android from the same source files.
Prerequistes
We will be using Capacitor to help us out with this, which in turn depends on Xcode and Android Studio. Please set these up in accordance with the Capacitor environment setup and installing Capacitor itself into your project before proceeding.
Secondly, we need to configure Capacitor. In the root of your project, create a capacitor.config.ts
file, containing the following:
Android application
Let's kick off with building the Android app. We need to add Capacitors Android package and the Android platform to make this happen.
You will now find that an Android
folder has been created in the root of your project, containing source code for your project. We can open this in Android Studio with the following:
The first time you do this, Android Studio should do a bunch of setting up due to the dependencies in the project. Just allow it to do its thing, which may take some time depending on your machine. However, once done, opening the project again later should be much quicker.
With an Emulator configured in Android Studio, we can go ahead and hit the green Play button on the main toolbar, which will launch the project and allow us to preview it on an emulated device.
iOS application
Next up is creating an iOS version. The process is quite similar. First we need to add the Capacitor iOS Package:
Then generate the Xcode project in a similar fashion as we did before:
Finally, we can make generating the projects simpler by adding those commands to the scripts section of package.json
:
Closing
There we have it! We now have means to create desktop and mobile devices applications, whilst leaning on the power of Kirby and 11ty to do the heavy lifting. Where to now?
Whilst out of the scope of this guide, from here you can build the distributable files in Xcode and Android Studio, and publish them via the respective app stores. I hope you found this guide useful, and I would like to see what you make with this!