Calamares Installer Customization Guide
This comprehensive guide provides detailed instructions for customizing the Calamares installer for your Nanite Linux distribution. It covers branding, theming, slideshow customization, and post-installation scripts.
Table of Contents
- Introduction to Calamares
- Directory Structure
- Branding Configuration
- Slideshow Customization
- Theme and Style Customization
- Module Configuration
- Post-Installation Scripts
- Integration with Live-build
- Testing and Debugging
Introduction to Calamares
Calamares is a distribution-independent system installer used by many Linux distributions. It provides a modular architecture that allows for extensive customization of both appearance and functionality.
Key components for customization:
- Branding: Controls the visual identity (logos, colors, product name)
- Slideshow: Displayed during installation
- Modules: Functional components that handle specific installation tasks
- Configuration: YAML files that control the behavior of modules
Directory Structure
The standard directory structure for Calamares customization in a Debian-based distribution:
/etc/calamares/
├── branding/
│ └── nanite/ # Your custom branding directory
│ ├── branding.desc # Branding configuration
│ ├── logo.png # Distribution logo
│ ├── show.qml # Slideshow QML file
│ ├── slide1.png # Slideshow images
│ ├── slide2.png
│ ├── slide3.png
│ └── stylesheet.qss # Optional CSS styling
├── modules/ # Module configurations
│ ├── bootloader.conf
│ ├── displaymanager.conf
│ ├── packages.conf
│ └── ...
└── settings.conf # Main configuration file
Branding Configuration
The branding.desc file is the core of your customization. It defines product information, window behavior, colors, and slideshow settings.
Creating the Branding Directory
# Create the branding directory structure
mkdir -p /etc/calamares/branding/naniteBasic branding.desc Template
Create /etc/calamares/branding/nanite/branding.desc:
# Nanite branding information
---
componentName: nanite
# Welcome screen configuration
welcomeStyleCalamares: false
welcomeExpandingLogo: true
# Window behavior and size
windowExpanding: normal
windowSize: 800px,520px
windowPlacement: center
# Navigation and sidebar
sidebar: widget
navigation: widget
# Product information strings
strings:
productName: "Nanite AI Linux"
shortProductName: "Nanite"
version: "1.0"
shortVersion: "1.0"
versionedName: "Nanite AI Linux 1.0"
shortVersionedName: "Nanite 1.0"
bootloaderEntryName: "Nanite"
productUrl: "https://nanite.ai/"
supportUrl: "https://nanite.ai/support/"
knownIssuesUrl: "https://nanite.ai/issues/"
releaseNotesUrl: "https://nanite.ai/releases/"
donateUrl: "https://nanite.ai/donate/"
# Branding images
images:
productIcon: "logo.png"
productLogo: "logo.png"
productWelcome: "welcome.png"
# productWallpaper: "wallpaper.png" # Optional
# Slideshow configuration
slideshow: "show.qml"
slideshowAPI: 2
# Colors for text and background components
style:
sidebarBackground: "#1a1a1a"
sidebarText: "#FFFFFF"
sidebarTextHighlight: "#4DB6AC"
sidebarSelect: "#4DB6AC"Detailed Color Configuration
For more detailed color customization, add these to the style section:
style:
# Sidebar colors
sidebarBackground: "#1a1a1a"
sidebarText: "#FFFFFF"
sidebarTextHighlight: "#4DB6AC"
sidebarSelect: "#4DB6AC"
# Button colors
buttonBackground: "#4DB6AC"
buttonText: "#FFFFFF"
buttonHighlightedBackground: "#80CBC4"
buttonHighlightedText: "#FFFFFF"
# Text field colors
textFieldBackground: "#2A2A2A"
textFieldText: "#FFFFFF"
# Error colors
errorBackground: "#F44336"
errorText: "#FFFFFF"
# Warning colors
warningBackground: "#FFC107"
warningText: "#000000"Slideshow Customization
The slideshow is displayed during the installation process. It can be created using QML or as a sequence of images.
Basic QML Slideshow
Create /etc/calamares/branding/nanite/show.qml:
/* Nanite Installer Slideshow */
import QtQuick 2.0;
import calamares.slideshow 1.0;
Presentation {
id: presentation
// Property to track if the slideshow is active
property bool activatedInCalamares: false
// Timer to advance slides automatically
Timer {
id: advanceTimer
interval: 20000 // 20 seconds per slide
running: false
repeat: true
onTriggered: presentation.goToNextSlide()
}
// First slide
Slide {
Image {
id: background1
source: "slide1.png"
width: 810
height: 485
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 50
font.pixelSize: 22
color: "#ffffff"
text: "Welcome to Nanite AI Linux"
wrapMode: Text.WordWrap
width: parent.width
horizontalAlignment: Text.Center
}
}
// Second slide
Slide {
Image {
id: background2
source: "slide2.png"
width: 810
height: 485
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 50
font.pixelSize: 22
color: "#ffffff"
text: "AI-Powered Computing Environment"
wrapMode: Text.WordWrap
width: parent.width
horizontalAlignment: Text.Center
}
}
// Third slide
Slide {
Image {
id: background3
source: "slide3.png"
width: 810
height: 485
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 50
font.pixelSize: 22
color: "#ffffff"
text: "Integrated AI Models and Tools"
wrapMode: Text.WordWrap
width: parent.width
horizontalAlignment: Text.Center
}
}
// Functions called by Calamares
function onActivate() {
presentation.activatedInCalamares = true;
advanceTimer.running = true;
}
function onLeave() {
presentation.activatedInCalamares = false;
advanceTimer.running = false;
}
// Start the slideshow if not started by Calamares
Component.onCompleted: {
if (!presentation.activatedInCalamares) {
advanceTimer.running = true;
}
}
}Advanced QML Slideshow with Animation
For a more dynamic slideshow, you can add animations:
/* Nanite Installer Slideshow with Animations */
import QtQuick 2.0;
import calamares.slideshow 1.0;
Presentation {
id: presentation
property bool activatedInCalamares: false
Timer {
id: advanceTimer
interval: 20000
running: false
repeat: true
onTriggered: presentation.goToNextSlide()
}
// First slide with animation
Slide {
Image {
id: background1
source: "slide1.png"
width: 810
height: 485
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
opacity: 0
// Fade in animation
NumberAnimation on opacity {
from: 0; to: 1
duration: 1000
running: true
}
}
Text {
id: slideText1
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 50
font.pixelSize: 22
color: "#ffffff"
text: "Welcome to Nanite AI Linux"
wrapMode: Text.WordWrap
width: parent.width
horizontalAlignment: Text.Center
opacity: 0
// Slide in animation
NumberAnimation on opacity {
from: 0; to: 1
duration: 1000
running: true
easing.type: Easing.InOutQuad
}
}
}
// Additional slides with similar animations...
// Functions called by Calamares
function onActivate() {
presentation.activatedInCalamares = true;
advanceTimer.running = true;
}
function onLeave() {
presentation.activatedInCalamares = false;
advanceTimer.running = false;
}
Component.onCompleted: {
if (!presentation.activatedInCalamares) {
advanceTimer.running = true;
}
}
}Image-Only Slideshow
If you prefer not to use QML, you can configure a simple image slideshow in branding.desc:
# Image slideshow configuration
slideshow: [
"slide1.png",
"slide2.png",
"slide3.png"
]Theme and Style Customization
CSS Stylesheet
Create /etc/calamares/branding/nanite/stylesheet.qss for additional styling:
/* Nanite Calamares Stylesheet */
/* Main application styling */
QWidget {
font-family: "Noto Sans";
font-size: 11pt;
}
#mainApp {
background: #1a1a1a;
color: #ffffff;
}
/* Button styling */
QPushButton {
background-color: #4DB6AC;
color: #ffffff;
border: none;
border-radius: 4px;
padding: 8px 16px;
font-weight: bold;
}
QPushButton:hover {
background-color: #80CBC4;
}
QPushButton:pressed {
background-color: #26A69A;
}
/* Progress bar styling */
QProgressBar {
border: none;
background-color: #2a2a2a;
height: 8px;
border-radius: 4px;
}
QProgressBar::chunk {
background-color: #4DB6AC;
border-radius: 4px;
}
/* Text field styling */
QLineEdit, QTextEdit {
background-color: #2a2a2a;
color: #ffffff;
border: 1px solid #444444;
border-radius: 4px;
padding: 6px;
}
QLineEdit:focus, QTextEdit:focus {
border: 1px solid #4DB6AC;
}
/* Sidebar styling */
#sidebarApp {
background-color: #1a1a1a;
color: #ffffff;
}
#sidebarMenuApp QPushButton {
background-color: transparent;
color: #ffffff;
text-align: left;
border: none;
border-radius: 0;
padding: 10px;
}
#sidebarMenuApp QPushButton:hover {
background-color: #2a2a2a;
}
#sidebarMenuApp QPushButton:checked {
background-color: #4DB6AC;
color: #ffffff;
}Module Configuration
Calamares uses modules to perform specific installation tasks. Each module has its own configuration file.
Main Configuration File
Create or modify /etc/calamares/settings.conf:
# Nanite Calamares Configuration
---
# Modules can be job modules (with no UI) and view modules.
# They can be placed in two different paths:
# - modules/ - loaded at startup
# - local/modules/ - loaded at runtime
modules-search: [ local, /usr/lib/calamares/modules ]
# Phase 1 - prepare. Run before anything else.
sequence:
- show:
- welcome
- locale
- keyboard
- partition
- users
- summary
- exec:
- partition
- mount
- unpackfs
- machineid
- fstab
- locale
- keyboard
- localecfg
- users
- displaymanager
- networkcfg
- hwclock
- services-systemd
- bootloader-config
- grubcfg
- bootloader
- packages
- luksbootkeyfile
- plymouthcfg
- initramfscfg
- initramfs
- removeuser
- nanite-post-install # Custom post-installation script
- umount
# Branding configuration
branding: nanite
# If this is set to true, the installer will show a prompt asking the user
# if they really want to quit right before quitting.
prompt-install: true
# If this is set to true, the installer will execute all target environment
# operations in the background, without blocking the UI.
dont-chroot: falseCustom Module Configurations
Users Module
Create or modify /etc/calamares/modules/users.conf:
# Users module configuration for Nanite
---
# Default username and hostname
defaultUserName: nanite
defaultHostName: nanite
# Auto-login by default
doAutoLogin: true
# Require strong passwords
requireStrongPasswords: false
# Allow weak passwords
allowWeakPasswords: true
# Allow weak passwords with warning
allowWeakPasswordsDefault: true
# Default user groups
defaultGroups:
- users
- lp
- video
- network
- storage
- wheel
- audio
- cdromPackages Module
Create or modify /etc/calamares/modules/packages.conf:
# Packages module configuration for Nanite
---
backend: apt
# Update the system database before installing packages
update_db: true
# Operations to perform before installing packages
operations:
- remove:
- calamares
- live-boot*
- live-config*
- live-tools
- install:
- nanite-branding
- nanite-welcomePost-Installation Scripts
Custom scripts can be executed after installation to perform additional setup.
Creating a Custom Module
- Create the module directory:
mkdir -p /etc/calamares/modules/nanite-post-install- Create the module descriptor:
Create /etc/calamares/modules/nanite-post-install/module.desc:
# Module metadata
---
type: "job"
name: "nanite-post-install"
interface: "python"
script: "main.py"- Create the Python script:
Create /etc/calamares/modules/nanite-post-install/main.py:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import subprocess
import libcalamares
def run():
"""
Nanite post-installation script.
This script performs additional setup tasks after the main installation.
"""
# Get the root mount point
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
# Log the start of our custom operations
libcalamares.utils.debug("Nanite post-installation: starting custom operations")
# Create a welcome message
create_welcome_message(root_mount_point)
# Configure AI services
configure_ai_services(root_mount_point)
# Set up desktop shortcuts
setup_desktop_shortcuts(root_mount_point)
# Return success
return None
def create_welcome_message(root_mount_point):
"""Create a welcome message for the user."""
try:
welcome_path = os.path.join(root_mount_point, "etc/profile.d/nanite-welcome.sh")
with open(welcome_path, "w") as welcome_file:
welcome_file.write("""#!/bin/bash
echo ""
echo -e "\033[1;36m"
echo " _ _ _ _ _ _ _ _ "
echo " | \\ | | __ _ _ __ (_) |_ ___ | | (_) | | (_)_ __ _ ___ __"
echo " | \\| |/ _\` | '_ \\| | __/ _ \\| | | | | | | | '_ \\| | | \\ \\/ /"
echo " | |\\ | (_| | | | | | || __/| |__| | | |___| | | | | |_| |> < "
echo " |_| \\_|\\__,_|_| |_|_|\\__\\___||_____/_| |_____|_| |_|\\__,_/_/\\_\\"
echo -e "\033[0m"
echo -e "\033[1;37mWelcome to Nanite AI Linux!\033[0m"
echo -e "\033[0;37mType 'nanite-help' to get started.\033[0m"
echo ""
""")
os.chmod(welcome_path, 0o755)
libcalamares.utils.debug("Created welcome message")
except Exception as e:
libcalamares.utils.debug(f"Error creating welcome message: {str(e)}")
def configure_ai_services(root_mount_point):
"""Configure AI services to start automatically."""
try:
# Enable Ollama service
subprocess.run(["chroot", root_mount_point, "systemctl", "enable", "ollama.service"])
# Enable Nanite AI assistant service
subprocess.run(["chroot", root_mount_point, "systemctl", "enable", "nanite-assistant.service"])
libcalamares.utils.debug("Configured AI services")
except Exception as e:
libcalamares.utils.debug(f"Error configuring AI services: {str(e)}")
def setup_desktop_shortcuts(root_mount_point):
"""Set up desktop shortcuts for AI tools."""
try:
# Create Desktop directory if it doesn't exist
desktop_dir = os.path.join(root_mount_point, "etc/skel/Desktop")
os.makedirs(desktop_dir, exist_ok=True)
# Copy desktop shortcuts
for app in ["nanite-assistant", "nanite-image-generator", "nanite-code-assistant"]:
src = os.path.join(root_mount_point, f"usr/share/applications/{app}.desktop")
dst = os.path.join(desktop_dir, f"{app}.desktop")
if os.path.exists(src):
subprocess.run(["cp", src, dst])
os.chmod(dst, 0o755)
libcalamares.utils.debug("Set up desktop shortcuts")
except Exception as e:
libcalamares.utils.debug(f"Error setting up desktop shortcuts: {str(e)}")Integration with Live-build
To integrate Calamares with Live-build, you need to include it in your package lists and copy your customizations into the live system.
Adding Calamares to Package Lists
Create or modify config/package-lists/installer.list.chroot:
calamares
calamares-settings-debian
Copying Custom Calamares Configuration
Create a hook to copy your custom Calamares configuration:
Create config/hooks/live/0100-calamares-customization.hook.chroot:
#!/bin/sh
set -e
# Create directories
mkdir -p /etc/calamares/branding/nanite
mkdir -p /etc/calamares/modules/nanite-post-install
# Copy branding files
cp -r /path/to/nanite_project/calamares/branding/nanite/* /etc/calamares/branding/nanite/
# Copy module configurations
cp -r /path/to/nanite_project/calamares/modules/* /etc/calamares/modules/
# Copy main configuration
cp /path/to/nanite_project/calamares/settings.conf /etc/calamares/
# Set permissions
chmod +x /etc/calamares/modules/nanite-post-install/main.py
# Update Calamares settings to use our branding
sed -i 's/^branding:.*/branding: nanite/' /etc/calamares/settings.conf
# Exit successfully
exit 0Make it executable:
chmod +x config/hooks/live/0100-calamares-customization.hook.chrootCreating Desktop Shortcut for Calamares
Create config/includes.chroot/usr/share/applications/nanite-installer.desktop:
[Desktop Entry]
Type=Application
Name=Install Nanite AI Linux
GenericName=System Installer
Comment=Install the system to your computer
Exec=sudo calamares
Icon=/etc/calamares/branding/nanite/logo.png
Terminal=false
StartupNotify=true
Categories=System;
Keywords=calamares;system;installer;
Testing and Debugging
Testing Calamares Configuration
To test your Calamares configuration without building a full ISO:
# Install Calamares
sudo apt install calamares calamares-settings-debian
# Copy your custom configuration
sudo cp -r /path/to/nanite_project/calamares/* /etc/calamares/
# Run Calamares in debug mode
sudo calamares -dTesting QML Slideshow
To test your QML slideshow without running the full installer:
# Install qmlscene
sudo apt install qtdeclarative5-dev-tools
# Test the slideshow
qmlscene -I /usr/share/calamares/qml /etc/calamares/branding/nanite/show.qmlCommon Issues and Solutions
-
Slideshow not appearing:
- Check that the path in
branding.descis correct - Verify QML syntax with
qmlscene - Check for missing image files
- Check that the path in
-
Branding not applied:
- Verify that
settings.confpoints to your branding component - Check permissions on branding files
- Verify that
-
Post-install script not running:
- Verify the module is included in the
execsequence insettings.conf - Check Python syntax and permissions
- Verify the module is included in the
-
UI styling issues:
- Check that
stylesheet.qssis properly formatted - Verify that the style rules target the correct widgets
- Check that
Complete Example
Here’s a complete example of the directory structure and files for Calamares customization:
/etc/calamares/
├── branding/
│ └── nanite/
│ ├── branding.desc
│ ├── logo.png
│ ├── show.qml
│ ├── slide1.png
│ ├── slide2.png
│ ├── slide3.png
│ ├── stylesheet.qss
│ └── welcome.png
├── modules/
│ ├── bootloader.conf
│ ├── displaymanager.conf
│ ├── packages.conf
│ ├── users.conf
│ └── nanite-post-install/
│ ├── module.desc
│ └── main.py
└── settings.conf
By following this guide, you can create a fully customized Calamares installer for your Nanite Linux distribution, complete with branded visuals, custom slideshow, and post-installation configuration.