logo
Hello World!

PatchKit Editor

May 29, 2025 (Updated: July 5, 2025)
typescriptreactpatchkit

Advanced WYSIWYG editor for designing launcher interfaces with custom state management, CSS variants system, and intuitive UI components.

Previously, creating custom launchers on the PatchKit platform was only possible through Unity or the SDK in Electron, or possibly on demand, by PatchKit developers. The idea emerged for a web-based WYSIWYG editor that could make theme creation easier for users without requiring programming knowledge.

PatchKit Editor is a comprehensive tool for designing application launcher interfaces. The project went through three main development stages: a prototype in jQuery, the first implementation in React, and a completely rewritten second version with advanced architecture and state management system.

React 18, TypeScript, Styled Components, custom state management system

The editor was built in React and TypeScript, which provides better type control and more predictable application behavior. The choice of React was driven by the need to create an interactive interface with many components that must react to state changes in real-time.

The application uses a modular architecture consisting of the following layers:

Custom, high-performance state management system based on useSyncExternalStore from React 18. The system allows for:

  • Observing selectors with precise subscription
  • Re-rendering only components subscribing to specific values
  • Support for complex selectors and functional updates
  • Performance optimization for mouse position-related operations

Component structure divided into categories:

  • Layout: Main application containers (Sidebar, MainContent, Scene)
  • Views: User interface components (Properties, TopbarMenu, ContextMenu)
  • Common: Reusable components (DropdownMenu, KeyboardKey)
  • Launcher: Components rendering launcher preview

Helper functions divided thematically:

  • LauncherElement: Element manipulation (adding, removing, CSS conversion)
  • LauncherConfig: Theme configuration management
  • Utils: Helper functions (name conversion, validation)

The application uses seven specialized stores:

  • uiStore: User interface state (selected elements, modes)
  • sessionStore: User session data and authorization
  • mouseStore: Mouse position and state for scene interactions
  • keyboardStore: Keyboard state for keyboard shortcuts
  • launcherElementsStore: Structure and properties of launcher elements
  • launcherStatesStore: 25+ launcher state flags reduced to simpler states
  • launcherWindowStore: Launcher window properties (size, position)

I created the first prototype in JavaScript and jQuery to handle scene interactions. It was meant to present the concept and allow for making a decision about further project development.

PatchKit Editor Prototype

The actual implementation was created in React and TypeScript. It was released in 2023 and was developed over the following year. This version offered great capabilities but didn't handle all launcher states, didn't allow scene manipulation, editing multiple elements at once, and wasn't very intuitive.

First version of PatchKit Editor

You can see how this version looked here: PatchKit Editor v1

The editor was rewritten from scratch and released at the end of 2024. I designed its new appearance, state management approach, and element styling. The current version introduces significant improvements in performance and functionality.

Current version of PatchKit Editor

You can see how this version looks here: PatchKit Editor v2

  • Navigation: Zoom, pan
  • Positioning tools:
    • Grid with configurable spacing
    • Snapping to element edges and centers
    • Snapping to application window edges
    • Indicators for element margin and padding

  • Interface: Manipulation on scene, in element tree, and with keyboard shortcuts
  • Multiple selection: Simultaneous editing of multiple elements
  • Operations: Copying, pasting, grouping, reordering

State variants: Each element can have different styles for different launcher states - basic states (not installed, installed, update available), task states (installation, update, repair in progress), error states (installation error, no disk space, no permissions), and application states (running, stopped, needs repair).

CSS pseudo-classes: Support for interactive states - :hover (mouse hover), :focus (keyboard focus), :active (active press).

Color Picker with gradients:

  • Support for HSLA, RGBA, hex
  • Recently used colors palette
  • Linear and radial gradients with multiple color points
  • Parsing and generating complex CSS strings

Numeric inputs:

  • Unit support (px, %)
  • Mathematical operations in fields
  • Value changes by mouse dragging
  • Value range validation

Searchable dropdowns:

  • Real-time option filtering
  • Support for option groups
  • Keyboard navigation

  • Window size
  • Container styling

  • Launcher preview in different states
  • User interaction simulation
  • Animation and transition testing

  • Images and icons: File upload, thumbnail preview, format management
  • Fonts: Browsing and adding fonts from Google Fonts library
  • Organization: Folder sorting, name search, permission management

  • Undo/Redo: Complete operation history with undo capability
  • Theme versions: Automatic version saving with restore capability
  • Migration: Automatic conversion of older formats during import

  • Protection against unauthorized access
  • Integration with PatchKit account system
  • API communication encryption

With such a large application, state management is crucial. During scene operations related to mouse position, you can quickly encounter too many rerenders, which, when triggered cascadingly, can slow down or freeze the application.

I created my own state management solution using useSyncExternalStore from React 18. The system allows for:

  • Selective subscription: Components subscribe only to specific parts of state
  • Render optimization: Only components using changed data are re-rendered
  • Support for complex selectors: Ability to observe multiple properties simultaneously
  • Functional updates: Safe state updates using previous value

If I were to write it again, I would probably use the Zustand library, which implements similar patterns.

Themes created in the editor are used in the launcher. This required creating a shared data structure for both applications. It's a JSON based on variants that are applied depending on state flags set by the launcher.

The structure allows defining different styles for different states:

State variants: Each element can have different styles for different combinations of state flags

  • State composition: Multiple variants can be active simultaneously
  • CSS generation: CSS classes and React components are generated based on the structure
  • Nesting: Elements can be arbitrarily nested through the children property

PatchKit launcher uses 25+ state flags describing various aspects of applications and tasks. To simplify the editor interface, these flags are reduced to 18 simpler states.

  • State mapping: Each editor state corresponds to a specific combination of launcher flags
  • Reduction examples:
    • Installation state: isAnyTaskInProgress: true, isInstallTaskInProgress: true
    • Updating state: isAppInstalled: true, isAppUpdateAvailable: true, isAnyTaskInProgress: true, isUpdateTaskInProgress: true

This reduction allows users to design intuitively without needing to understand the complex logic of launcher states.

The CSS conversion system automatically generates appropriate selectors and rules based on element structure:

  • Unit normalization: Automatic addition of px to numeric values
  • Selector generation: Creating CSS selectors for different state combinations
  • Optimization: Minimizing generated CSS size
  • Pseudo-class support: Automatic mapping of interactive states

Many CSS styles require complicated values, but in the editor they are represented by simple controls.

An example is buttons for positioning element content. They allow setting direction (column/row) and content position without needing to understand flexbox.

Element content positioning

The system automatically maps intuitive controls to appropriate CSS properties:

  • Direction: flex-direction: row/column
  • Positioning: justify-content, align-items with automatic adaptation to direction
  • Smart mapping: CSS properties change meaning depending on flexbox direction

Advanced color picker supports creating gradients with any number of color points. The component automatically generates complex CSS strings and parses existing gradients.

Features:

  • Linear and radial gradients

  • Any number of color points

  • Interactive point positioning

  • Real-time preview

  • Existing gradient parsing

    • Generated style examples:
    css
    background: linear-gradient(90deg, #008cff 0%, #ff0000 38%, #00ff47 62%, #00000000 100%);
    
    background: linear-gradient(90deg, #008cff 0%, #ff0000 38%, #00ff47 62%, #00000000 100%);
    
    css
    background: radial-gradient(circle, #008cff 0%, #ff0000 31%, #00ff47 83%, #00000000 100%);
    
    background: radial-gradient(circle, #008cff 0%, #ff0000 31%, #00ff47 83%, #00000000 100%);
    
Color Picker for gradients

PatchKit Editor is an advanced tool that transformed the launcher creation process from a programming task into an intuitive design process. The project serves as an example of how to build a complex web application with a custom state management system while maintaining high performance and usability.

  • Custom state management system: Creating a high-performance solution using the latest React 18 APIs.

  • Advanced CSS architecture: Implementation of a variant system allowing style definition for complex application state combinations, with automatic conversion to optimized CSS.

  • Intuitive interface for complex operations: Transforming complicated CSS properties (flexbox, gradients, positioning) into simple, visual controls accessible to users without technical knowledge.

  • Scalable modular architecture: Dividing the application into specialized modules (stores, components, functions) allowing for easy testing, extension, and code maintenance.

This project was a significant step in my development. Creating such a complex application required developing a systematic approach to software architecture and continuous learning of new technologies.

The greatest satisfaction came from solving the performance problem through a custom state management system. Understanding how React 18 handles concurrent rendering (the ability to interrupt and resume rendering) and using useSyncExternalStore to create a system that ensures data consistency during asynchronous rendering operations was a fascinating challenge. This hook guarantees that all components see the same state even when React interrupts rendering for more urgent tasks.

The project also taught me how important it is to design with the end user in mind. Transforming complex programming concepts into intuitive visual tools required a deep understanding of both technology and user needs.

I consider this project a milestone in my career - the first time I created an application of such scale and complexity that is actively used by hundreds of users to create professional interfaces.

©2025 BatStack