Skip to content

Create Custom Themes (AI Reference) ​

This guide describes the file structure, configuration fields, and CSS used by custom themes in WonderPen for desktop. It helps AI assistants generate importable .wptheme files from user requirements and also supports manual theme creation. For theme controls in the app, see Themes.

Start by choosing a light or dark appearance, a color palette, a background image, and text reading styles. Then create the configuration and CSS, package the files, and check the result in WonderPen. Theme CSS mainly controls the application interface; styles for exported documents must be configured separately through Custom CSS.

Theme Package Structure ​

A .wptheme file is a ZIP archive with a different extension. Use this flat structure:

text
My Theme.wptheme
├── config.json
├── style.css
└── background.jpg
  • config.json: required; defines the theme's identity, name, base theme, and default settings.
  • style.css: optional; defines custom styles.
  • background.jpg: optional; the theme's background image. Its name and format can differ.

Place these files directly at the root of the archive, without an enclosing folder or image subdirectories; the current importer does not create parent directories for packaged files. Use UTF-8 for config.json and style.css. Include only files the theme uses, excluding local settings, temporary files, old images, and system-generated directories such as __MACOSX. No HTML, JavaScript, or build tools are needed.

Configuration File ​

config.json uses standard JSON, without comments or trailing commas. The following configuration works with the Basic CSS Example later in this guide:

json
{
  "id": "lake-light-6b6f66d3-604c-4c22-8537-22ba2a2723fa",
  "title": {
    "zh": "湖光",
    "en": "Lake Light"
  },
  "theme_mode": "light",
  "base_style": "light",
  "bg_color": "#eef4f1",
  "bd_color": "rgba(38, 59, 53, 0.12)",
  "settings": {
    "font_family": [],
    "editor_font_family": [],
    "editor_font_size": 18,
    "editor_font_color": "auto",
    "editor_width": 720,
    "editor_line_height": 1.8,
    "editor_paragraph_spacing": 0,
    "editor_page_padding_h": 48,
    "editor_page_padding_v": 30,
    "editor_background_opacity": 1,
    "editor_line_bg_show": false
  }
}

Generate a new unique id when creating a new theme. Do not copy the example ID.

Core Fields ​

FieldTypeRequiredDescription
idStringYesUnique theme identifier
titleString or objectYesNonempty theme name; a multilingual object can include en, zh, and zh_tw
theme_modeStringNo; explicit value recommended"light" or "dark"; keep it consistent with the styles. See below for actual light/dark detection
base_styleStringNoBuilt-in theme to inherit; omit or use an empty string for no base
background_imageStringNoBackground image filename in the package, such as "background.jpg"; set when using a theme background image
background_image_blurNumberNoBlur radius in px; the current settings UI allows 0–50
background_overlay_bgStringNoBackground overlay, usually a CSS color with transparency
settingsObjectNoDefault interface font and editor settings
bg_colorStringNo; recommendedBackground color for the theme list preview
bd_colorStringNo; recommendedBorder color for the theme list preview

title can be a simple string such as "Lake Light". For a multilingual object, provide a nonempty en fallback name and add zh and zh_tw as needed. “Required” in the table refers to fields needed for a theme package that can be displayed, edited, and distributed correctly. The importer does not fully validate all fields, so a successful import does not prove the configuration is valid.

bg_color and bd_color do not set the actual interface colors. Both should be concrete color values, not complete border declarations or var(...) references to theme variables. When generating a package directly, include them as shown in the example so the theme list displays the intended palette; importing does not calculate them from CSS. Saving in the theme editor attempts to update the preview from CSS, but the result is not the browser's final computed color.

Do not distribute the runtime-generated bg_image field or duplicate the CSS in JSON. Keep styles in style.css.

Theme IDs and Updates ​

WonderPen identifies a theme by its id, not by its name or .wptheme filename.

  • For a new, independent theme, generate a new ID.
  • For an update to an existing theme, keep its ID.
  • For variants that should coexist, use different IDs.

When importing a theme with an existing ID, WonderPen asks whether to overwrite it. After confirmation, the new package replaces the old theme directory. This is a full replacement, not a field-by-field merge; local theme settings in that directory are not retained either. The app does not compare version numbers or automatically keep multiple versions with the same ID.

Prefer an ID containing only lowercase ASCII letters, digits, and hyphens, such as a UUID or a name prefix followed by a UUID, to work with directory names and the app's generated CSS classes. Do not add the internal custom-- prefix or use whitespace, path separators, ., .., or a built-in theme name as the ID.

Inherit a Base Theme ​

base_style specifies a built-in theme to inherit. For example, "base_style": "light" starts from the Light theme.

WonderPen loads the base theme's styles first, then appends style.css. Custom rules can override the base styles according to the CSS cascade. Usually, you only need to override the variables you want to change, without copying the entire built-in theme.

base_style inherits the base theme's CSS, not all of the application states associated with that built-in theme. For example, a high contrast base provides its palette and CSS, but some components also rely on the app's high contrast state to enable borders or special styles. Those effects are not necessarily enabled by inheritance. Inspect the actual interface and add rules with confirmed selectors as needed, rather than changing the theme ID to imitate those states.

The following built-in themes are currently available. Set base_style to the identifier in the first column, not the display name:

IdentifierBuilt-in theme nameDescription
lightLightLight theme with a pale gray interface, white paper, dark text, and blue accents.
darkDarkDark theme with a charcoal background, light text, and blue accents.
grayGrayDark theme with gray backgrounds lighter than Dark and cyan accents.
draculaDraculaDark theme with a deep blue-purple background, light text, and purple accents.
greenGreenLight theme with a soft gray-green interface and pale green paper.
green2Green 2Light theme with a pale green interface, white paper, and green accents.
cyanCyanLight theme with a pale blue interface, nearly white paper, and cyan-blue accents.
yellowYellowLight theme with warm yellow backgrounds and paper, paired with dark brown text.
pinkPinkLight theme with pale pink backgrounds and paper, paired with pink accents.
peach_fuzzPeach FuzzLight theme with a soft peach interface, pale peach paper, and brown text.
light_redLight RedLight theme with a nearly white, pale red background, white paper, and orange accents.
silverSilverLight theme with a simple neutral palette of white, pale gray, and black.
mocha_mousseMocha MousseDark theme with coffee-brown backgrounds and paper, paired with warm white text.
mocha_lightMocha LightLight theme with a beige interface, warm white paper, and dark brown text.
high_contrast_lightLightHigh contrast light theme with black text on white and distinct borders.
high_contrast_darkDarkHigh contrast dark theme with white text on black and distinct borders.
high_contrast_dark_greenDark 2High contrast dark theme with bright green text and borders on black.
high_contrast_dark_yellowDark 3High contrast dark theme with bright yellow text and borders on a nearly black background.

To start without a base theme, omit base_style or set it to "". Omitting it is recommended. Do not use "none" or a custom theme ID.

Without a base theme, you need to provide enough theme variables to cover text, backgrounds, inputs, menus, selection states, and other interface elements. Starting with a base theme close to the desired appearance is usually easier.

theme_mode does not generate a color palette. The app determines light or dark appearance from the CSS variable --wp-dark:

css
.theme-custom {
  --wp-dark: light;
}

For dark themes, use --wp-dark: dark. Keep this value consistent with theme_mode and the overall colors.

Default Editor Settings ​

Prefer settings for fonts, font size, line height, paper opacity, and similar options. The app generates runtime styles from these settings; overriding the corresponding values directly in CSS can interfere with user adjustments. Omitted settings start with app defaults, followed by local adjustments and settings kept consistent across themes. They do not inherit local editor settings from the base theme.

The table below lists the settings currently applied with a theme. Do not add arbitrary app settings to settings: for example, editor_letter_spacing and editor_text_align are outside this list. Putting such fields at the top level does not make them take effect either.

FieldValue and units
font_familyArray of interface font names
editor_font_familyArray of editor font names, with the primary font first and the fallback font second
editor_font_sizeFont size, number, px
editor_font_color"auto" or a CSS color
editor_widthEditor width, number, px
editor_line_heightLine height, number, used as em
editor_paragraph_spacingParagraph spacing, number, used as em
editor_page_padding_hHorizontal page padding, number, px
editor_page_padding_vVertical page padding, number, px
editor_background_opacityPaper opacity, from 0 to 1
editor_line_bg_showWhether to show ruled lines, boolean
editor_line_bg_use_custom_colorWhether to use a custom ruled-line color, boolean
editor_line_bg_colorRuled-line color
editor_background_type"auto", "color", or "image"
editor_background_colorCustom background color
editor_background_imageBackground image URL used at runtime

Do not append units to numbers: write 18 for font size, not "18px". Use [] when no font is specified, without null or meaningless blank entries. Listing font names does not install those fonts with the theme.

editor_background_opacity controls the paper background: 0 is fully transparent and 1 is fully opaque. It does not change text opacity.

Prefer values within the current theme editor's input ranges: font size 10–100 px, line height 0.5–4, paragraph spacing 0–4, and horizontal and vertical page padding 0–200 px. Editor width starts at 400 px, with an upper limit based on screen width. These are UI ranges, not a guarantee that importing will validate or correct out-of-range values.

Reference a bundled background image through the top-level background_image field so the app can generate its actual URL. Do not put a package filename directly in settings.editor_background_image.

Background settings have additional application logic. Without local background overrides or rules keeping settings consistent across themes, a top-level background_image sets the background type to image. Without that field, the type resets to auto and the image URL is cleared. Therefore, setting only settings.editor_background_type: "color" and editor_background_color does not create a solid-color theme. Use --wp-base-bg, --wp-paper-bg, and panel background variables for solid colors; use the top-level background_image for an image theme.

CSS Scope and Writing Rules ​

When a custom theme is applied, WonderPen adds .theme-custom to body. Define shared theme variables there, and prefer meaningful data-* attributes for specific interface adjustments:

css
.theme-custom {
  --wp-primary-color: #397d75;
}

.theme-custom [data-role='editor-nav-bar'] {
  background: rgba(230, 240, 233, 0.8);
}

Follow these rules:

  • Override existing theme variables first, then style specific elements as needed.
  • Keep the .theme-custom scope. Set local variables on the relevant region and global colors on .theme-custom, so floating elements such as menus can inherit them too.
  • Prefer confirmed [data-role="..."] selectors and other state attributes.
  • Avoid generated class names, complex DOM hierarchies, and unverified selectors.
  • Use plain CSS. Theme CSS is not compiled with Sass and does not support Sass variables or mixins.
  • Use expanded selectors by default to simplify review and maintenance.
  • Use !important only where necessary, on specific declarations.
  • Use colors such as rgba() for transparent backgrounds. Setting opacity on a whole panel also fades its text and buttons.

CSS can include gradients, pseudo-classes, pseudo-elements, shadows, filters, and animations. Give animations distinctive names and consider disabling or reducing motion with prefers-reduced-motion.

Both data-* attributes and theme variables may change between versions. To find additional selectors, inspect the target element in the app's developer tools instead of guessing attribute names. Check the actual result in the target version.

CSS Variables You Can Override ​

The table below lists common variables. For the complete variable listings and default values of the Light and Dark themes, see Built-in Theme Styles.

PurposeCommon variables
Light or dark appearance--wp-dark
Primary color and text on it--wp-primary-color, --wp-on-primary-color
Primary and secondary text--wp-text-color, --wp-text-color-2
Links--wp-link-color, --wp-link-hover-color
Text highlighting--wp-text-highlight-color, --wp-text-highlight-bg, --wp-text-highlight-border
Base background and text--wp-base-bg, --wp-on-base-bg, --wp-on-base-bg2
Paper backgrounds--wp-paper-bg, --wp-paper-bg-alpha
Inputs--wp-input-bg, --wp-input-bg-disabled
Selection--wp-selected-bg, --wp-on-selected-bg
Unfocused selection--wp-selected-bg-blur, --wp-on-selected-bg-blur
Secondary selection and hover--wp-selected-bg2, --wp-on-selected-bg2, --wp-hover-bg
General border colors--wp-border-color, --wp-border-color-2, --wp-border-color-3
Frame separators--wp-frame-border-color (a complete border declaration, not just a color)
Left panel--wp-left-panel-bg, --wp-left-panel-border, --wp-left-panel-backdrop-filter
Main panel--wp-main-panel-bg, --wp-main-panel-border, --wp-main-panel-backdrop-filter
Right panel--wp-right-panel-bg, --wp-right-panel-border, --wp-right-panel-backdrop-filter
Title and status bars--wp-title-bar-bg, --wp-status-bar-bg
Memos--wp-memo-bg
Popups--wp-popup-bg, --wp-popup-border, --wp-popup-backdrop-filter
Page overlay and filter--wp-page-wrapper-bg, --wp-page-wrapper-backdrop-filter
Shadows--wp-shadow, --wp-shadow-sm, --wp-shadow-lg, --wp-shadow-float
Caret and focus outline--wp-caret-color, --wp-focus-outline-color
Scrollbars--wp-scrollbar-thumb, --wp-scrollbar-thumb-hover, --wp-scrollbar-track

Use the value type expected by each variable. For example, a border color differs from a complete border declaration:

css
.theme-custom {
  --wp-border-color: rgba(38, 59, 53, 0.12);
  --wp-left-panel-border: 1px solid rgba(38, 59, 53, 0.12);
  --wp-left-panel-backdrop-filter: blur(8px);
}

--wp-paper-bg is used to calculate paper color and opacity. Supply a color, not a gradient or url(...). For gradients, use panel variables that accept background values, or set background on a confirmed target element.

When changing a background, check its corresponding text color too. For example, after changing --wp-selected-bg, also check --wp-on-selected-bg.

The reference page uses .theme-light and .theme-dark for built-in themes. When reusing their variables in a custom theme, place the declarations inside .theme-custom.

Island Layout and Borders ​

The main window's island layout separates rounded panels with empty space. Frame separators between panels and the outline of each island are different borders; do not hide them together. When creating a theme, preserve the built-in layout and adjust only the colors you need:

  • --wp-frame-border-color controls frame separators below the main window's top toolbar and between the side panels and the central workspace. The built-in Light theme uses 1px solid transparent; an opaque color adds lines in the existing gaps. Despite ending in color, this variable takes a complete border declaration.
  • --wp-left-panel-border, --wp-main-panel-border, and --wp-right-panel-border control panel and editor outlines. Components such as navigation bars and stacked panels also use them for necessary internal boundaries. Keep these borders visible and adjust their colors to suit the theme. Do not set them all to none or transparent to remove frame separators.
  • General border colors such as --wp-border-color are also used by other components. Do not make them globally transparent to remove a line in one location.

For example, this preserves pale gray-green island outlines while keeping frame separators transparent:

css
.theme-custom {
  --wp-frame-border-color: 1px solid transparent;
  --wp-border-color: #c7d5cc;
  --wp-left-panel-border: 1px solid var(--wp-border-color);
  --wp-main-panel-border: 1px solid var(--wp-border-color);
  --wp-right-panel-border: 1px solid var(--wp-border-color);
}

If extra lines appear, compare the result with a similar built-in theme. Use developer tools to identify the element and variable drawing each line, then correct that variable. Do not apply blanket border: none or border-color: transparent overrides to regions such as main-page-frame, frame-body-left, frame-body-main, frame-body-right, editor-base, or navigation bars. These overrides replace component border rules and may also remove necessary boundaries in Composition Mode, Minimal Mode, or panels that slide into view.

The app's layout manages spacing, rounded corners, and border visibility in different modes. Unless a layout change is explicitly needed, preserve these rules instead of recreating the island layout in theme CSS.

Bottom Status Bar Backgrounds ​

In the normal island layout, the status bars at the bottom of the left, center, and right columns should blend into the window background rather than form separate color blocks matching the panels or navigation bars above them. To preserve the built-in Light theme's appearance, check all three of the following:

  • Status bar variable: The bottom toolbars of the side panels and the editor status bar use --wp-status-bar-bg. Set it to transparent.
  • Direct style overrides: Do not group [data-role="editor-status-bar"] with navigation or tab bars when applying a solid background. A direct background declaration bypasses the status bar variable; remove such overrides so the component continues to use its built-in rules. Check the side-panel regions, [data-role="left-panel-bottom-bar"] and [data-role="right-panel-bottom-bar"], for similar overrides.
  • Parent container background: The central container includes both the editor area and its bottom status bar, and its background is controlled by --wp-main-panel-bg. An opaque parent background still shows through a transparent status bar. Set this variable to transparent as well when the status bar should blend into the window background. Use --wp-paper-bg for the text editor's paper color instead of coloring the entire central container.

Use the following variable settings together with removing direct background overrides on status bars:

css
.theme-custom {
  --wp-status-bar-bg: transparent;
  --wp-main-panel-bg: transparent;
}

Transparency exposes the background underneath; it is not a fixed color. If a color block remains, inspect the computed backgrounds of the status bar and its ancestors. Do not fade the entire element with opacity or remove island borders to address a background issue. Unless a specific status bar design is needed, preserve the app's status bar rules for Composition Mode, Minimal Mode, and floating windows.

Common Interface Selectors ​

SelectorRegion
[data-role="page-wrapper"]Page wrapper
[data-role="main-page-frame"]Main window frame
[data-role="frame-body-left"]Left panel region
[data-role="frame-body-main"]Central working region
[data-role="frame-body-right"]Right panel region
[data-role="left-panel-sidebar"]Left vertical toolbar
[data-role="right-panel-sidebar"]Right vertical toolbar
[data-role="editor-base"]Editor pane container
[data-role="editor-prosemirror"]Main text editor region; use it to scope shared-editor rules
[data-role="editor-nav-bar"]Editor navigation bar
[data-role="editor-status-bar"]Editor status bar
[data-role="editor"]Outer container of the shared text editor
[data-role="editor-paper"]Text editor paper
[data-role="editor-paper-content"]Mounting container for editable content
[data-role="editor-tabs"]Editor tabs region
[data-role="editor-tab-item"]Individual editor tab
[data-role="tree-panel"]Document tree panel
[data-role="memo-editor"]Memo editor

The shared editor can appear in multiple contexts. To target only the main text editor paper, use .theme-custom [data-role="editor-prosemirror"] [data-role="editor-paper"]. editor-paper-content is a mounting container, not the outer editor. Prefer configuration fields and theme variables for paper backgrounds, width, and text layout.

These attributes are not present in every window or view. For example, the main-window frame selector does not match floating windows, and vertical toolbars are absent in a horizontal toolbar layout. Status bars can also be rendered outside the editor region through a portal, so do not assume they are always descendants of editor-base.

Combine state attributes with region selectors:

css
/* Active tab */
.theme-custom [data-role='editor-tab-item'][data-active='1'] {
  color: var(--wp-primary-color);
}

/* Navigation bar of the active pane in split view */
.theme-custom [data-role='editor-base'][data-active-status='1'] [data-role='editor-nav-bar'] {
  background: rgba(210, 230, 219, 0.85);
}

/* Main window with an image background */
.theme-custom [data-role='main-page-frame'][data-background-type='image'] {
  --wp-memo-bg: transparent;
}

data-active-status="1" means the pane is active in split view; "0" means it is inactive in split view. The attribute may be absent when the editor is not split.

A matching selector does not guarantee that its rule wins. The app has dedicated styles for active panes, Continuous View, and other states. If a rule does not produce the expected result, inspect computed styles and selector specificity, then add the necessary region or state qualifiers.

The main window frame also provides data-composition="1" and data-minimal-mode="1" for Composition Mode and Minimal Mode. When a state attribute and data-role belong to the same element, place the selectors directly next to each other without a space.

Distinguish the two background state attributes: main-page-frame in the main window uses data-background-type; page-wrapper in both main and floating windows uses data-editor-background-type. To match an image background in both window types, use [data-role="page-wrapper"][data-editor-background-type="image"]. Do not interchange the attribute names.

To limit a rule to a window type, use:

css
body.theme-custom[data-win-name='main'] [data-role='page-wrapper'] {
  /* Main window */
}

body.theme-custom[data-win-name='float'] [data-role='page-wrapper'] {
  /* Floating window */
}

Basic CSS Example ​

The following style.css works with the earlier JSON configuration. It inherits the Light theme and changes it to a soft green palette:

css
.theme-custom {
  --wp-dark: light;

  --wp-primary-color: #397d75;
  --wp-on-primary-color: #ffffff;

  --wp-text-color: #263b35;
  --wp-text-color-2: #687d75;

  --wp-base-bg: #eef4f1;
  --wp-on-base-bg: #263b35;
  --wp-on-base-bg2: #687d75;
  --wp-paper-bg: #fbfdfb;

  --wp-selected-bg: #397d75;
  --wp-on-selected-bg: #ffffff;
  --wp-hover-bg: rgba(57, 125, 117, 0.12);

  --wp-frame-border-color: 1px solid transparent;
  --wp-border-color: rgba(38, 59, 53, 0.12);

  --wp-left-panel-bg: #dcebe3;
  --wp-main-panel-bg: transparent;
  --wp-right-panel-bg: #e6f0e9;
  --wp-status-bar-bg: transparent;

  --wp-left-panel-border: 1px solid var(--wp-border-color);
  --wp-main-panel-border: 1px solid var(--wp-border-color);
  --wp-right-panel-border: 1px solid var(--wp-border-color);

  --wp-memo-bg: #f3f7ee;
  --wp-caret-color: #397d75;
}

.theme-custom [data-role='editor-nav-bar'] {
  background: rgba(230, 240, 233, 0.8);
}

Background Images, Blur, and Transparency ​

To use a background image, place it at the root of the ZIP archive and merge these fields into the top level of the configuration. Prefer a simple filename such as background.png or background.jpg, matching the configuration exactly, including case. Avoid characters with URL meanings such as # and ?. The app's background-image save logic handles PNG, JPG/JPEG, GIF, BMP, and WebP.

json
{
  "background_image": "background.jpg",
  "background_image_blur": 8,
  "background_overlay_bg": "rgba(255, 255, 255, 0.35)"
}

Also adjust settings.editor_background_opacity as needed, for example to 0.2. The snippet above contains only the fields to add, not a complete config.json.

These settings control different layers:

  • Background image: supplies the underlying image.
  • Blur: softens image details.
  • Overlay: reduces background contrast or makes the image lighter or darker.
  • Paper opacity: controls how much the paper behind the text obscures the background.
  • Panel backgrounds: controlled by CSS variables and can use translucent colors.

Images are centered and fill the window using cover by default, so some edges are cropped when aspect ratios differ. Lowering paper opacity does not make the side panels transparent. If you reuse the earlier CSS example, change the panel backgrounds to translucent colors separately to reveal the image beneath them.

Do not reference a bundled background image directly with url("./background.jpg"). Theme CSS is injected into a page <style> element, so relative URLs are not automatically resolved against the theme directory. Do not use absolute paths from the author's computer either.

Theme styles are assembled in this order: base theme styles → style.css → rules generated from background settings. A positive blur radius generates --wp-page-wrapper-backdrop-filter, and a nonempty overlay generates --wp-page-wrapper-bg. At equal specificity, these rules override the corresponding values in style.css.

Package, Import, and Check ​

Compress config.json, style.css, and any images in use into a ZIP archive, then change its extension to .wptheme. A ZIP tool can also write directly to a file with that extension.

For example, place the configuration and CSS in a my-theme/ directory and run this Python code from its parent directory:

python
import json
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED

source = Path("my-theme")
config = json.loads((source / "config.json").read_text(encoding="utf-8"))
files = ["config.json"]
if (source / "style.css").is_file():
    files.append("style.css")
background = config.get("background_image")
if background:
    # The image must be at the package root, not a path or URL.
    assert isinstance(background, str)
    assert "/" not in background and "\\" not in background
    assert background not in (".", "..")
    files.append(background)

for name in files:
    assert (source / name).is_file(), f"Missing file: {name}"

with ZipFile("my-theme.wptheme", "w", ZIP_DEFLATED) as archive:
    for name in files:
        archive.write(source / name, arcname=name)

In WonderPen, click Import under Settings → Appearance → Custom Themes, then click the imported theme to apply it. Feature access is indicated in the app and on the plan comparison page.

Check at least the following:

  • Text in the editor, memos, document tree, inputs, and menus is readable.
  • Selected, hovered, unfocused, and disabled states are distinguishable.
  • Single-editor, split-view, tabbed, and floating-window layouts display correctly.
  • Island outlines remain visible, gaps between panels have no extra frame separators, and necessary component boundaries such as those in navigation bars remain intact.
  • The bottom status bars of the left, center, and right columns blend into the window background, without unexpected color blocks from direct background overrides or parent containers.
  • Resizing the window does not cause backgrounds or panels to obscure content unexpectedly.
  • Composition Mode and Minimal Mode remain usable.
  • Switching to another theme removes the custom theme's effects.

If the result differs from expectations, also check:

  • Whether other Custom CSS schemes are enabled under Advanced. They load after theme CSS and can override it at equal specificity.
  • Whether local adjustments have been saved for this theme. If needed, clear them with Reset to Default in the theme's context menu.
  • Whether Keep Consistent is enabled under Apply to Other Themes. Stop keeping settings consistent before checking all of the theme's defaults.

The theme editor saves the distributable design. Additional adjustments made in the style panel while using a theme are not automatically included in an exported theme. Save any settings you want to distribute in the theme design itself.

Delivery Checklist for AI Assistants ​

  • The ZIP root contains valid config.json with a nonempty theme name.
  • JSON and CSS use UTF-8, and fields and value types follow this guide. A successful import is not a complete configuration check.
  • A new theme uses a new ID; an update keeps the existing ID.
  • base_style is a valid built-in theme identifier or is omitted.
  • theme_mode, --wp-dark, and the actual palette agree.
  • CSS uses the .theme-custom scope and prefers confirmed data-* selectors for specific elements.
  • Distinguish frame separators from island outlines and follow the border guidance, avoiding blanket overrides that hide panel or component borders.
  • Follow the status bar background guidance to check the status bar variable, direct background overrides, and parent backgrounds together. Setting the status bar variable to transparent alone does not complete the check.
  • Image references do not depend on absolute paths on the author's computer, and the package contains the referenced image.
  • The package excludes local_settings.json, other local* files, and unrelated resources.
  • Deliver the .wptheme file with a short description of its appearance, fonts, and import instructions.
  • If the theme has not been checked in WonderPen, explicitly state that in-app validation has not been completed.