.deskin format reference
A .deskin file is a ZIP archive containing a skin.json manifest and, optionally, image assets. Audeeport loads .deskin files (and plain .zip files) from ~/.audeeport/skins/.
Package structure
my-skin.deskin ← ZIP archive, .deskin extension
├── skin.json ← required, manifest
├── preview.png ← recommended, preview shown in the gallery
├── index.html ← required for web skins only (see below)
└── assets/ ← optional, custom images
├── np_bg.png
├── btn_play.png
├── btn_pause.png
├── no_art.png
└── ...
The assets/ folder can contain subdirectories. Reference each asset by relative path from the package root (for example assets/btn_play.png).
skin.json reference
{
"meta": {
"id": "unique-skin-id",
"name": "My Cool Skin",
"author": "YourName",
"version": "1.0",
"description": "A description of this skin",
"website": "https://example.com",
"isDark": true,
"previewImage": "preview.png"
},
"colors": {
"background": "#0D0D0F",
"surface": "#161618",
"surfaceVariant": "#1E1F22",
"surfaceContainer": "#222326",
"surfaceBright": "#2A2B2F",
"onBackground": "#E4E4E6",
"onSurface": "#E4E4E6",
"onSurfaceVariant": "#9A9A9E",
"onSurfaceMuted": "#6A6A6E",
"outline": "#32333A",
"accent": "#D4A574",
"accentVariant": "#E8C49A",
"onAccent": "#1A1A1A",
"nowPlayingBackground": "#080808",
"miniPlayerBackground": "#1A1A1E",
"bottomBarBackground": "#121214"
},
"typography": {
"headlineWeight": 600,
"bodyWeight": 400,
"scaleFactor": 1.0
},
"shapes": {
"artRadiusSmall": 6,
"artRadiusMedium": 8,
"artRadiusLarge": 12,
"cardRadius": 12,
"buttonRadius": 22,
"seekbarHeight": 3
},
"assets": {
"nowPlayingBackground": "assets/np_bg.png",
"libraryBackground": "assets/library_bg.png",
"bottomBarBackground": "assets/bar_bg.png",
"miniPlayerBackground": "assets/mini_bg.png",
"buttonPlay": "assets/btn_play.png",
"buttonPause": "assets/btn_pause.png",
"buttonStop": "assets/btn_stop.png",
"buttonNext": "assets/btn_next.png",
"buttonPrevious": "assets/btn_prev.png",
"buttonShuffle": "assets/btn_shuffle.png",
"buttonRepeat": "assets/btn_repeat.png",
"seekbarTrack": "assets/seek_track.png",
"seekbarFill": "assets/seek_fill.png",
"seekbarThumb": "assets/seek_thumb.png",
"eqSliderTrack": "assets/eq_track.png",
"eqSliderThumb": "assets/eq_thumb.png",
"albumArtPlaceholder": "assets/no_art.png",
"appLogo": "assets/logo.png",
"iconLibrary": "assets/ic_library.png",
"iconEq": "assets/ic_eq.png",
"iconBitacora": "assets/ic_journal.png",
"iconEchoes": "assets/ic_echoes.png"
},
"layout": {
"nowPlayingArtSize": 0.78,
"nowPlayingArtShadow": true,
"nowPlayingShowAlbumName": true,
"nowPlayingControlsSize": 1.0,
"albumGridMinSize": 160,
"albumGridSpacingH": 16,
"albumGridSpacingV": 20,
"trackRowShowArt": true,
"trackRowArtSize": 44,
"trackRowDividers": true,
"bottomBarShowLabels": true,
"miniPlayerHeight": 56,
"miniPlayerShowProgress": true
}
}
Everything except meta.id, meta.name, and meta.author is optional. Missing values fall back to the Midnight (default) skin.
meta (required)
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Must be unique across installed skins. |
name | string | yes | Shown in the gallery. |
author | string | yes | |
version | string | no | Defaults to 1.0. |
description | string | no | One- to two-sentence summary. |
website | URL | no | Link from the gallery. |
isDark | boolean | no | true for dark skins, false for light. Defaults to true. Affects system UI integration. |
previewImage | string | no | Relative path to a preview image (for example preview.png). |
colors
Overrides Audeeport’s theme palette. Every key is optional, and any you omit falls back to the default skin. Available keys: background, surface, surfaceVariant, surfaceContainer, surfaceBright, onBackground, onSurface, onSurfaceVariant, onSurfaceMuted, outline, accent, accentVariant, onAccent, nowPlayingBackground, miniPlayerBackground, bottomBarBackground.
Colors use hex format: #RRGGBB (opaque) or #AARRGGBB (with alpha).
typography
| Field | Type | Notes |
|---|---|---|
headlineWeight | int | Font weight for headings (for example 600). |
bodyWeight | int | Font weight for body text (for example 400). |
scaleFactor | float | Multiplies the base text scale (1.0 is default). |
shapes
Overrides corner radii and the seek bar thickness. Keys: artRadiusSmall, artRadiusMedium, artRadiusLarge, cardRadius, buttonRadius, seekbarHeight (all integers, in dp).
assets
Optional images applied to native UI elements. Keys: nowPlayingBackground, libraryBackground, bottomBarBackground, miniPlayerBackground, buttonPlay, buttonPause, buttonStop, buttonNext, buttonPrevious, buttonShuffle, buttonRepeat, seekbarTrack, seekbarFill, seekbarThumb, eqSliderTrack, eqSliderThumb, albumArtPlaceholder, appLogo, iconLibrary, iconEq, iconBitacora, iconEchoes.
layout
Fine-tunes sizing and toggles for the Now Playing screen, album grid, track rows, bottom bar, and mini player. Keys: nowPlayingArtSize, nowPlayingArtShadow, nowPlayingShowAlbumName, nowPlayingControlsSize, albumGridMinSize, albumGridSpacingH, albumGridSpacingV, trackRowShowArt, trackRowArtSize, trackRowDividers, bottomBarShowLabels, miniPlayerHeight, miniPlayerShowProgress.
Asset guidelines
| Asset | Recommended size | Format |
|---|---|---|
previewImage | 400x300 | PNG |
nowPlayingBackground / libraryBackground | 1080x1920 or tileable | PNG/JPG |
buttonPlay / buttonPause / buttonNext / buttonPrevious | 64x64 | PNG (transparent bg) |
seekbarTrack / seekbarFill | 800x8 | PNG |
seekbarThumb | 24x24 | PNG (transparent bg) |
eqSliderTrack | 8x200 | PNG |
eqSliderThumb | 24x24 | PNG (transparent bg) |
albumArtPlaceholder | 400x400 | PNG |
| Bottom bar icons | 24x24 | PNG (transparent bg) |
Monochrome icons with transparency work best, since they adapt to the accent color.
Web skins
A web skin is a .deskin package with an index.html at its root (plus any CSS, JS, and image assets it needs). Audeeport detects the index.html and loads it in a JavaFX WebView in its own focused window when the user switches to that skin. The skin draws the entire player interface.
The JavaScript bridge
When the page loads, Audeeport injects a window.Audeeport object and fires an audeeport-ready event. Listen for it before you assume the bridge is present:
document.addEventListener('audeeport-ready', () => {
// window.Audeeport is now available.
})
Inbound: audeeport-state events
State updates arrive as an audeeport-state CustomEvent. The latest state is also always available as window.Audeeport.state, and you can assign a function to Audeeport.onStateChange to receive the same payload.
document.addEventListener('audeeport-state', (e) => {
const {
title, // current track title
artist, // current track artist
album, // current track album
albumArt, // data: URL for the cover, or null
isPlaying, // boolean
progressMs, // playback position in milliseconds
durationMs, // track duration in milliseconds
progress, // position as a 0.0 to 1.0 fraction
volume, // 0.0 to 1.0
shuffle, // boolean
repeat, // 'off' | 'all' | 'one'
queue, // array of { id, title, artist, durationMs, albumArt }
currentTrackId // id of the playing queue row
} = e.detail
// Update your UI here.
})
Inbound: audeeport-palette events
When the user’s color theme changes, Audeeport fires an audeeport-palette CustomEvent and updates window.Audeeport.palette. Use it so a single web skin adapts to Midnight, Arctic, and the rest without shipping multiple copies.
document.addEventListener('audeeport-palette', (e) => {
const { skinId, accent, accentVariant, onAccent, background, surface,
surfaceVariant, surfaceContainer, surfaceBright, onSurface,
onSurfaceVariant, onSurfaceMuted, outline, isDark } = e.detail
})
Outbound: Audeeport.* methods
Audeeport.play()
Audeeport.pause()
Audeeport.togglePlayPause()
Audeeport.stop()
Audeeport.next()
Audeeport.previous()
Audeeport.seek(fraction) // 0.0 to 1.0, not seconds
Audeeport.setVolume(fraction) // 0.0 to 1.0
Audeeport.toggleShuffle()
Audeeport.cycleRepeat()
Audeeport.playAtIndex(index) // play a queue row by index
Audeeport.dismiss() // close the skin and return to the desktop window
Audeeport.dragWindow(dx, dy) // move the chromeless skin window
There is also a helper, Audeeport.formatTime(ms), which returns a m:ss string.
Notes for web-skin authors
- Cover art arrives as a
data:URL in thealbumArtfield, so<img src={albumArt}>works directly. - The skin window is chromeless. Audeeport forces the page background transparent so only your painted elements show against the desktop. Clicking any non-interactive area drags the window (interactive elements like
a,button,input, or anything withdata-no-dragare excluded), so you do not need to build your own title bar.
Minimal example: color-only skin
{
"meta": {
"id": "neon-pink",
"name": "Neon Pink",
"author": "Community",
"isDark": true
},
"colors": {
"background": "#0A0A0A",
"surface": "#141414",
"surfaceVariant": "#1E1E1E",
"accent": "#FF1493",
"onBackground": "#FFFFFF",
"onSurface": "#FFFFFF",
"onSurfaceVariant": "#AAAAAA",
"onAccent": "#000000"
}
}
ZIP this single file (no assets/ folder needed for a color-only skin) and rename it to neon-pink.deskin.
Install path
~/.audeeport/skins/ on macOS and Linux.
%USERPROFILE%\.audeeport\skins\ on Windows.
Drop the .deskin file into the folder and refresh the gallery. No restart required.
Tips
- Validate your JSON before packaging. A malformed
skin.jsonis skipped on load and logged. - Start simple. A skin with just
metaandcolorsis valid; everything else has sensible defaults. - Test with a range of album covers. Your skin should stay legible over both bright and dark art.
- Keep the package small for fast load. Skins that take seconds to extract feel sluggish.
Where to go next
- Skins overview. The user-facing side.
- Audio engine. For what’s behind the visuals.