Kzeroko KTM2

Developer Editor Preferences

Shared editor themes, the client preference file and integration rules for the dense authoring controls.

Updated Sep 19, 2026 5 min read

The in-game developer editors share a client-local theme selection with 3 palettes: Blender, Blockbench and Graphite. The implementation lives under client.screen.editor; it is an internal UI framework, not a public API or a server configuration system.

What it does

EditorThemePreferences stores the shared selection. The scene recorder, scene trigger and DungeonEditorFragment read it when their fragment is created; the dungeon base serves the script, gateway, unlock-controller and loot-chest editors.

Choosing the next theme updates the shared preference immediately and rebuilds that editor’s controls. Other existing fragments keep their own theme field; there is no broadcast that repaints every screen. Newly created fragments read the current shared selection.

Runtime model

The singleton loads on first class use. Its file is isekaiexpansion-deveditors.txt in Fabric’s game directory, not the world save or the configuration directory. Reading and writing use UTF-8.

# IsekaiExpansion developer editor preferences
format 1
theme blender
EntryTypeDefaultContract
formatExact text versionRequired in an existing fileMust be 1; other text, including inline comments, is invalid.
themeTheme nameblender in memory when no regular file existsExisting files require blender, blockbench or graphite. Input is trimmed and case-insensitive; output is lowercase.
Lines starting with #CommentOptionalIgnored after surrounding whitespace is stripped.
Blank linesWhitespaceOptionalIgnored.

Each non-comment line splits once on whitespace. Unknown keys and lines without a value are ignored. Later valid duplicate keys replace earlier values, but an unknown theme throws immediately rather than waiting for a later correction. A later invalid format leaves the final format invalid.

File conditionResult
Missing path or non-regular fileKeep Blender without attempting an initial write
Missing required format/theme, invalid format or invalid themeReset to Blender and write the current format
Read failureLog a warning, reset to Blender and attempt the same rewrite
Successful readKeep the parsed theme in memory
External edit after loadingNo watcher or reload method; the current process keeps its in-memory selection

Writing emits only the header, format and theme lines, so custom comments and unknown fields do not survive a save. It writes a sibling isekaiexpansion-deveditors.txt.tmp, then moves it over the destination with atomic replacement. If atomic move is unsupported, it retries with ordinary replacement. Other I/O failures are logged; the in-memory selection is not rolled back and a temporary file may remain.

Contracts

Internal methodBehaviour
EditorThemePreferences.current()Returns the singleton’s current selection
EditorThemePreferences.select(EditorTheme)Null or the same selection returns the current theme without writing; another value updates memory, writes synchronously and returns that selection
EditorTheme.next()Cycles Blender → Blockbench → Graphite → Blender
EditorTheme.serializedName()Uses lowercase with Locale.ROOT
EditorTheme.fromSerializedName(String)Rejects null/blank; trims and parses case-insensitively

Use these methods on the client through the editor UI path. They do not marshal threads, synchronise concurrent access or queue disk writes. Do not load the preference class on a dedicated server or treat its file as synchronised player state.

The palette provides colours for toolbars, normal/raised panels, borders, fields, normal/hover/active buttons, accents, primary/secondary/muted text and danger buttons. SquareButton prioritises danger fill, then active fill, then hover/press fill; an active button still uses the accent border.

Extending it

A new editor should initialise its theme from EditorThemePreferences.current(). Its theme-button callback can follow the existing fragments:

theme = EditorThemePreferences.select(theme.next());
statusColor = theme.textMuted();
rebuild();

Here theme and statusColor are the fragment’s existing fields, and rebuild() recreates controls from that state. Keep editing data in the fragment’s model so rebuilding its widgets does not become an implicit save or reset of authored content.

Shared helperBehaviour to preserve
EditorWidgets.squareRectangular background, corner radius 0 and 1 dp border
EditorWidgets.editTextSingle-line input; initial value is set before the text watcher is attached
EditorWidgets.fieldChanges call the supplied consumer; an optional commit callback is posted when focus is lost
EditorWidgets.choiceCycles the supplied options then rebuilds; provide a non-empty list
EditorWidgets.toggleInverts the value then rebuilds
EditorWidgets.actionRowEqual-width controls separated by the common gap

The common toolbar height is 25 dp, control height 21 dp and gap 3 dp. These are layout constants, not restrictions on values edited by the widgets.

EditorI18n.option lowercases an option, then checks translation prefixes in order: screen.isekaiexpansion.developer_editor.option., screen.isekaiexpansion.cinematic_scene.editor.option., screen.isekaiexpansion.dungeon.editor.option.. Null becomes none. If no translation exists, EditorWidgets.humanize replaces colons/underscores with spaces and capitalises words. Use the translation keys for display text while keeping the underlying serialized value unchanged.

Verifying

  • With the client closed, remove only a test copy of the preference file. Open an editor and confirm Blender is selected without creating the file merely by reading.
  • Cycle all themes, reopen a different editor and restart the client. Check the saved lowercase selection is reused.
  • Test a wrong format, missing theme, uppercase valid theme and invalid theme followed by a valid one. Check which inputs are accepted and which reset the file.
  • Make a test destination unwritable and select another theme. Confirm the warning and in-memory change; a returned selection does not prove the disk write succeeded.
  • Edit a field, lose focus and change theme. Confirm the model retains the edit and that rebuilding does not spuriously fire the initial text-change callback.

Tutorial runtime covers the separate tutorial UI and persistence. Blockbench plugin covers the external asset tool; the editor’s Blockbench palette is only a theme name, not a dependency on that plugin.