Skip to main content

Theme Manifest

Themes require two files: manifest.json for marketplace metadata and theme.config.json for the runtime contract.


manifest.json

This file is read at install time by the marketplace.

Required Fields

FieldRequiredPurpose
nameYesTheme name shown in the marketplace
versionYesSemver version string, e.g. 1.0.0
entryYesRuntime entry file inside the bundle
typeRecommendedSet to "theme"
privacyStrongly recommendedThird-party and consent declaration

Full Example

{
"name": "My Theme",
"version": "1.0.0",
"entry": "index.html",
"type": "theme",
"privacy": {
"collects_pii": false,
"collects_visitor_data": false,
"third_party_transfers": [],
"third_party_embeds": []
}
}

If your theme loads external fonts, analytics, or any third-party resource, declare those origins in the privacy block exactly as you would for an app. Read App Manifest — privacy for the full privacy field reference.


theme.config.json

This is the runtime contract Shuuka reads to configure the theme at load time and in the live preview.

Top-Level Fields

FieldRequiredPurpose
typeYesRuntime type: "html" or "react"
entryYesRuntime entry file path inside the bundle
mountSelectorNoDOM selector Shuuka mounts into. Default #app
supportsThemeSettingsNotrue if the theme exposes dashboard settings
metaStrongly recommendedTheme metadata object
meta.nameRecommendedTheme display name
meta.versionRecommendedTheme version
meta.color_schemeStrongly recommended"dark" or "light"
configStrongly recommendedCard and link visual defaults
config.iframeStrongly recommendedApp card visual defaults
config.linksStrongly recommendedLink icon grid defaults
defaultsNoTheme-owned default config values
overridableKeysNoKeys the profile owner may change from the dashboard
htmlNoHTML-only runtime options
html.placeholdersNoNamed placeholder definitions for HTML helpers
reactNoReact-only runtime options
react.hydrateSelectorNoReact hydration selector

meta

{
"meta": {
"name": "My Theme",
"version": "1.0.0",
"color_scheme": "dark"
}
}

color_scheme propagates to every installed app iframe. When set to "dark", the platform adds <html class="dark"> to each app document. Apps that respect the .dark class will render correctly in your dark theme.

If color_scheme is missing, all app iframes default to light mode regardless of how dark your theme background is.


config.iframe

Controls the default visual appearance of app cards on the profile.

KeyTypeDescription
backgroundstringCSS background value, e.g. "rgba(0,0,0,0.5)" or "transparent"
border_radiusnumberBorder radius in pixels, e.g. 16
shadowstringShadow preset key ("none", "sm", "md", "lg", "xl") or CSS shadow value
border_stylestringCSS border style: "solid", "dashed", "none"
border_widthnumberBorder width in pixels, e.g. 1
border_colorstringCSS color for the border, e.g. "rgba(255,255,255,0.12)"
paddingnumberInner padding in pixels, e.g. 0
text_colorstringFallback text color inside app cards

Why this matters: When a theme is loaded in dev preview mode (?dev_theme={id}), the platform replaces config.iframe in the merged payload with the dev theme's own iframe section. Without this section, no inline card CSS variables are emitted and only your SCSS fallbacks apply.

Example:

{
"config": {
"iframe": {
"background": "rgba(10, 10, 20, 0.70)",
"border_radius": 18,
"shadow": "lg",
"border_style": "solid",
"border_width": 1,
"border_color": "rgba(255, 255, 255, 0.10)",
"padding": 0,
"text_color": "#ffffff"
}
}
}

Controls the default appearance of the social link icon grid.

KeyTypeDescription
visiblebooleanWhether the links section is visible by default
alignmentstringGrid alignment: "center", "left", "right"
wrapbooleanWhether icons wrap to multiple rows
item_sizenumberIcon size in pixels, e.g. 48
spacingnumberGap between icons in pixels, e.g. 8

Example:

{
"config": {
"links": {
"visible": true,
"alignment": "center",
"wrap": true,
"item_size": 52,
"spacing": 10
}
}
}

defaults

defaults defines the theme's starting visual configuration. These values are merged as the theme layer in the settings resolution chain:

platform defaults → theme defaults → user overrides

The keys in defaults should mirror the settings schema the theme exposes.

Example:

{
"defaults": {
"background": {
"mode": "solid",
"color": "#0a0a0f"
},
"layout": {
"structure": "centered",
"max_width": 560
},
"header": {
"show_image": false
}
}
}

overridableKeys

overridableKeys lists the keys the profile owner is allowed to change from the theme settings panel. If a key is not listed here, the user cannot override it.

{
"overridableKeys": [
"background.color",
"background.mode",
"layout.structure"
]
}

html.placeholders

Optional. Defines named placeholder sections in the HTML template for use with the SDK render helpers.

{
"html": {
"placeholders": {
"header": "#theme-header",
"footer": "#theme-footer"
}
}
}

Runtime Rules

typeentry must be
htmlAn .html file
reactA .js, .mjs, .jsx, .ts, or .tsx file

Complete theme.config.json Example

This is the minimum viable config for a properly working theme that supports dev preview and app-card broadcasting:

{
"type": "html",
"entry": "index.html",
"supportsThemeSettings": true,
"meta": {
"name": "My Theme",
"version": "1.0.0",
"color_scheme": "dark"
},
"config": {
"iframe": {
"background": "rgba(255, 255, 255, 0.05)",
"border_radius": 16,
"shadow": "md",
"border_style": "solid",
"border_width": 1,
"border_color": "rgba(255, 255, 255, 0.10)",
"padding": 0,
"text_color": "#ffffff"
},
"links": {
"visible": true,
"alignment": "center",
"wrap": true,
"item_size": 48,
"spacing": 8
}
},
"defaults": {
"background": {
"mode": "solid",
"color": "#0a0a0f"
}
},
"overridableKeys": [
"background.color",
"background.mode"
]
}

Settings Strategy

  • defaults defines the theme's intended look out-of-the-box.
  • overridableKeys defines what the profile owner can personalize.
  • Platform defaults cover any missing values.

Do not blur these layers. A theme that overrides everything in defaults but lists nothing in overridableKeys gives the user zero customization power. A theme that lists keys in overridableKeys but has no defaults risks missing values breaking the layout.


Next Step

Read Theme Platform Values for all template variables, Theme App-Card Integration for the card-style broadcast protocol, and HTML Theme Guide for a complete working example.